Skip to the content.

← Back to Plugin Architecture

5.6 Activities Plugin Workflows

Last Updated: July 17, 2025
Status: Complete
Plugin: Activities

The Activities plugin implements a comprehensive authorization management system that enables members to request, maintain, and renew activity-based authorizations. This documentation provides factual workflow information based on the actual source code implementation.

Table of Contents

Authorization Lifecycle Workflow

Authorization Status Constants and Flow

Based on the Authorization entity implementation, authorizations follow a five-status lifecycle:

// From Authorization entity - actual status constants
const APPROVED_STATUS = "Approved";
const PENDING_STATUS = "Pending";
const DENIED_STATUS = "Denied";
const REVOKED_STATUS = "Revoked";
const EXPIRED_STATUS = "Expired";

Authorization State Machine

The authorization lifecycle follows this state machine based on the DefaultAuthorizationManager implementation:

stateDiagram-v2
    [*] --> PENDING : Authorization Request Created
    PENDING --> APPROVED : All Required Approvals Received
    PENDING --> DENIED : Approval Denied
    PENDING --> EXPIRED : Expires Before Approval
    APPROVED --> EXPIRED : Authorization Period Ends
    APPROVED --> REVOKED : Administrative Revocation
    DENIED --> [*]
    EXPIRED --> [*] 
    REVOKED --> [*]
    
    note right of APPROVED
        Active authorization
        with start_on and expires_on dates
        Role assignment occurs here
    end note
    
    note right of PENDING
        Awaiting approval
        or in approval process
        Multiple approvers possible
    end note

Temporal Management with ActiveWindow

Authorizations extend ActiveWindowBaseEntity providing automatic temporal lifecycle management:

Activity Participation and Approval Processes

Activity Definition and Configuration

Activities represent authorization types that members can request (e.g., “Marshal”, “Water Bearer”, “Herald”). Based on the Activity entity implementation:

Core Configuration Fields:

Approver Discovery Algorithm:

// From Activity entity's getApproversQuery() method
public function getApproversQuery($branchId = null): SelectQuery
{
    return $this->permissionsLoader->getMembersWithPermissionsQuery(
        $this->permission_id,
        $branchId
    );
}

Activity Group Management

Activity Groups provide categorical organization implemented through the ActivityGroup entity:

Member Eligibility Validation

Based on the authorization request workflow in DefaultAuthorizationManager:

Age Eligibility Check:

Duplicate Request Prevention:

// From DefaultAuthorizationManager.request() method
$existingRequests = $table
    ->find()
    ->where([
        "member_id" => $requesterId,
        "activity_id" => $activityId,
        "status" => Authorization::PENDING_STATUS
    ])
    ->count();
if ($existingRequests > 0) {
    return new ServiceResult(false, "There is already a pending request for this activity");
}

Authorization Request, Approval, Renewal, and Revocation Workflows

Authorization Request Workflow

Based on the DefaultAuthorizationManager.request() implementation:

Request Process Flow:

flowchart TD
    A[Member Initiates Request] --> B{Is Renewal?}
    B -->|Yes| C[Check Existing Authorization]
    B -->|No| D[Skip Renewal Check]
    C --> E{Valid Auth Exists?}
    E -->|No| F[Return Error: No Auth to Renew]
    E -->|Yes| G[Check for Pending Requests]
    D --> G
    G --> H{Pending Request Exists?}
    H -->|Yes| I[Return Error: Duplicate Request]
    H -->|No| J[Create Authorization Entity]
    J --> K[Set Status to PENDING]
    K --> L[Create AuthorizationApproval Entity]
    L --> M[Generate Secure Token]
    M --> N[Send Approval Notification]
    N --> O[Commit Transaction]
    F --> P[End: Failure]
    I --> P
    O --> Q[End: Success]

Renewal vs New Request Logic:

// From DefaultAuthorizationManager - renewal validation
if ($isRenewal) {
    $existingAuths = $table
        ->find()
        ->where([
            "member_id" => $requesterId,
            "activity_id" => $activityId,
            "status" => Authorization::APPROVED_STATUS,
            "expires_on >" => DateTime::now(),
        ])
        ->count();
    if ($existingAuths == 0) {
        return new ServiceResult(false, "There is no existing authorization to renew");
    }
}

Multi-Level Approval Workflow

Based on the DefaultAuthorizationManager.approve() implementation:

Approval Decision Process:

flowchart TD
    A[Approver Makes Decision] --> B[Record Approval Response]
    B --> C[Check Required Approval Count]
    C --> D{More Approvals Needed?}
    D -->|Yes| E[Forward to Next Approver]
    E --> F[Create Next Approval Entity]
    F --> G[Send Notification to Next Approver]
    G --> H[End: Awaiting Next Approval]
    D -->|No| I[Process Final Approval]
    I --> J[Update Authorization Status]
    J --> K[Start ActiveWindow]
    K --> L[Assign Member Role]
    L --> M[Send Success Notification]
    M --> N[End: Authorization Active]

Required Approval Count Logic:

// From DefaultAuthorizationManager - approval count checking
$requiredApprovalCount = $this->getApprovalsRequiredCount(
    $authorization->is_renewal,
    $activity,
);
if (
    $this->getNeedsMoreRenewals(
        $requiredApprovalCount,
        $authorization->id,
        $approvalTable,
    )
) {
    // Forward to next approver
    if (!$this->processForwardToNextApprover(...)) {
        // Handle forwarding failure
    }
} else {
    // Final approval - activate authorization
    if (!$this->processApprovedAuthorization(...)) {
        // Handle activation failure
    }
}

Authorization Denial Workflow

Based on the DefaultAuthorizationManager.deny() implementation:

Denial Process:

  1. Record Denial Decision: Timestamp and reason recorded in AuthorizationApproval
  2. Update Authorization Status: Status set to DENIED_STATUS
  3. Set Temporal Window: Authorization set to expired (past dates) to prevent conflicts
  4. Audit Trail: Approver ID and denial reason recorded
  5. Notification: Requester notified of denial with reason
// From DefaultAuthorizationManager.deny() method
$approval->responded_on = DateTime::now();
$approval->approved = false;
$approval->approver_id = $approverId;
$approval->approver_notes = $denyReason;
$approval->authorization->revoker_id = $approverId;
$approval->authorization->revoked_reason = $denyReason;
$approval->authorization->status = Authorization::DENIED_STATUS;
$approval->authorization->start_on = DateTime::now()->subSeconds(1);
$approval->authorization->expires_on = DateTime::now()->subSeconds(1);

Authorization Revocation Workflow

Based on the DefaultAuthorizationManager.revoke() implementation:

Revocation Process:

  1. ActiveWindow Integration: Uses activeWindowManager->stop() to immediately end authorization
  2. Role Removal: Automatically removes granted roles through ActiveWindow
  3. Status Update: Authorization status updated to REVOKED_STATUS
  4. Audit Trail: Revoker ID and revocation reason recorded
  5. Notification: Member notified of revocation with details
// From DefaultAuthorizationManager.revoke() method
$awResult = $this->activeWindowManager->stop(
    "Activities.Authorizations",
    $authorizationId,
    $revokerId,
    $revokedReason
);

Authorization Renewal Workflow

Renewals use the same request/approval flow but with special validation:

Renewal Requirements:

Activity Management Documentation

Activity Group Organization

Based on the ActivityGroup entity and ActivityGroupsController implementation:

Group Management Features:

Group Management Workflow:

  1. Creation: Administrative creation of new activity groups
  2. Activity Assignment: Activities assigned to groups during creation/editing
  3. Reporting Integration: Groups used for organizational reporting
  4. Navigation Support: Groups support hierarchical navigation structure

Activity Configuration Management

Based on the Activity entity and ActivitiesController implementation:

Activity Configuration Workflow:

  1. Basic Configuration: Name, description, activity group assignment
  2. Age Restrictions: Minimum and maximum age requirements
  3. Approval Requirements: Number of required approvers for new requests and renewals
  4. Permission Linkage: Association with KMP permission for approver discovery
  5. Administrative Validation: Comprehensive validation of configuration integrity

Administrative Features:

Member Participation Tracking

Based on the Authorization entity relationships and MemberAuthorizationsTrait:

Participation Tracking Features:

Member Integration:

// From MemberAuthorizationsTrait - navigation badge support
public function pendingApprovalCount(): int
{
    if (!$this->_approver_activity_auth_count) {
        $table = TableRegistry::getTableLocator()->get('Activities.AuthorizationApprovals');
        $this->_approver_activity_auth_count = $table->memberAuthQueueCount($this->id);
    }
    return $this->_approver_activity_auth_count;
}

Integration Points and Architecture

RBAC Security Integration

Permission-Based Approval Authority:

Authorization Policy Framework:

ActiveWindow Temporal Management

Lifecycle Integration:

Service Layer Architecture

AuthorizationManagerInterface Implementation:

Navigation and UI Integration:

Email Notification System

Automated Workflow Notifications:

Reporting and Analytics Integration

Authorization Analytics:

Report Generation:


Conclusion

The Activities plugin workflows are implemented through a comprehensive service-oriented architecture that integrates deeply with KMP’s RBAC system, temporal management, and notification systems. The factual implementation provides:

This implementation provides a robust foundation for managing member activity authorizations while maintaining security, auditability, and organizational compliance.

References