# PostFundManagement (PFM) Platform — Operational Processes & Governance (Processes.md) > **Document Context**: Authoritative operational manual and process specification for the PFM Platform. Derived from the PFM SRS v2.0 and governing all lifecycle transitions, workflow gates, RBAC controls, and Maker-Checker segregation of duties. --- ## 1. PFM End-to-End Operational Lifecycle The PFM platform governs the lifecycle of grant, development, innovation, and impact funding portfolios from the moment an award is approved through long-term post-fund monitoring. ``` ┌────────────────────────────────────────────────────────────────────────────────────────┐ │ POST-FUND LIFECYCLE │ │ │ │ [1. Award Intake] ──> [2. Contracting] ──> [3. Onboarding] │ │ External Approval Draft Agreement KYC & Banking Gate │ │ Recorded (BR-001) Auto-created (BR-002) Required for Disb. (BR-003) │ │ │ │ │ ▼ │ │ [4. Project & WBS] ──> [5. Budget & Lines] ──> [6. Disbursement Gate] │ │ Milestones & Tasks Allocations & Caps Requires Verified Evidence │ │ Progress Tracking No Over-commitment & Satisfied Conditions (BR-004) │ │ │ │ │ ▼ │ │ [7. M&E & Evidence] ─> [8. Change & Risk] ──> [9. Close-Out & Impact] │ │ Indicator Actuals Variations & Issues Post-Fund Monitoring │ │ Field Site Visits Audit Trail (BR-007) Portfolio Roll-Up (BR-010) │ └────────────────────────────────────────────────────────────────────────────────────────┘ ``` --- ## 2. Core Operational Processes ### 2.1 Process 1: Award Intake & Funding Registration (Module M01) * **Pre-condition**: Award has been approved by external sanctioning committee (BR-001). * **Actor**: Funding Administrator (`grant_financials: add`). * **Workflow**: 1. Capture external reference number, award amount ($> 0$), funding period, programme, and recipient organisation. 2. System enforces duplicate check against external reference numbers. 3. Upon successful award creation, the system **automatically initializes** the corresponding legal `Contract` in `Draft` status (BR-002). ### 2.2 Process 2: Contracting & Agreement Management (Module M02) * **Pre-condition**: Valid award record exists. * **Actors**: Legal / Programme Manager (`grant_financials: add`), Executive / Authorised Signatory (`grant_financials: update`). * **Workflow**: 1. Author attaches legal terms, clauses, total value, and effective/expiry dates. 2. Upload signed bilateral agreement PDF. 3. Transition contract status to `Active`. 4. **Maker-Checker Rule**: The user who uploaded or created the contract cannot be the signatory who transitions it to `Active`. ### 2.3 Process 3: Project WBS & Milestones Management (Module M04 & M07) * **Pre-condition**: Project is in `Active` status. * **Actors**: Contributor / Project Manager (`projects_milestones: add`), Supervisor / Manager (`projects_milestones: update`). * **Workflow**: 1. Project Manager defines contractual milestones with due dates and priority levels. 2. Contributors log ground activities against milestones. 3. Contributor uploads completion evidence. 4. Status transitions from `Planned` $\to$ `In Progress` $\to$ `Submitted` $\to$ `Under Review` $\to$ `Verified & Approved`. 5. **Verification Gate**: Only users with `projects_milestones: update` who **did not create** the milestone can verify and approve it. ### 2.4 Process 4: Disbursement Control & Payment Release (Module M05 & M06) * **Pre-condition**: Recipient onboarding complete, banking details verified, and linked milestone deliverable verified. * **Actors**: Finance Officer (`grant_financials: add`), Finance Director / Manager (`grant_financials: update`). * **Workflow**: 1. Finance Officer drafts disbursement tranche drawdown against verified milestone. 2. System validates conditions precedent and budget caps (commits + expenditures $\le$ approved budget line). 3. Authoriser verifies evidence and approves tranche release. 4. **Maker-Checker Rule**: The user who captured the payment request cannot approve the disbursement. ### 2.5 Process 5: M&E Indicators, Risks & Evidence Review (Module M08 & M09) * **Pre-condition**: Approved project indicators and risk registers configured. * **Actors**: M&E Officer (`evidence_risks: add`), Programme Supervisor (`evidence_risks: update`). * **Workflow**: 1. Field staff or recipients submit indicator actuals and supporting verification files (`EvidenceType`). 2. Evidence enters the `EvidenceReviewQueue`. 3. Supervisor reviews document authenticity, geotags, and deliverable match. 4. Decision: `Approve & Verify` or `Reject` (with mandatory rework reasoning). 5. **Maker-Checker Rule**: The officer who uploaded the evidence document cannot approve their own submission. ### 2.6 Process 6: Change Management & Variations (Module M15 & M16) * **Pre-condition**: Active project with identified issue or required contractual variance. * **Actors**: Contributor (`change_management: add`), Manager (`change_management: update`). * **Workflow**: 1. Contributor logs project issue or drafts contractual change request (budget reallocation, timeline extension, scope shift). 2. Impact assessment conducted. 3. Governance deliberation. 4. Resolution: `Approved & Enacted` or `Rejected`. 5. **Maker-Checker Rule**: Change request initiator cannot approve or enact the change. ### 2.7 Process 7: Automated Background Workflows & Scheduled Jobs (PostFundManagement.Jobs) * **Pre-condition**: Background jobs host (`PostFundManagement.Jobs`) active and connected to `pfm-scheduler`. * **Actors**: System Engine, `JobsWorker` Daemon, Domain Event Handlers. * **Workflow**: 1. **Event Triggering**: API operations emit strongly typed events (`IEvent`) and enqueue them into `pfm-scheduler` via `IJobOrchestrator`. 2. **Cron Schedule Execution**: `JobsWorker` initializes recurring schedules on daemon startup for periodic monitoring, risk assessments, and communication batches. 3. **Job Execution**: Quartz cluster dispatches acquired triggers to `MediatorJob` within `PostFundManagement.Jobs` (concurrency limit = 5). 4. **Mediated Processing**: Event payload is deserialized and published via `IMediator` to execute domain logic (project monitoring, risk threshold checks, email dispatch). 5. **Cascading One-Time Jobs**: When a recurring job identifies an action item requiring separate asynchronous execution, it triggers a decoupled one-time job (`jobOrchestrator.SendAsync`). --- ## 3. The Maker-Checker Operational Policy ### 3.1 Policy Definition Under PFM enterprise governance standards, **dual authorization (Maker-Checker)** is mandatory for all material lifecycle decisions: $$\text{Approval Granted} \iff (\text{User has 'update' permission}) \land (\text{User ID} \neq \text{Record Creator ID})$$ ### 3.2 Matrix of Segregated Actions | Operational Domain | Maker Action (`add`) | Checker Action (`update`) | Maker-Checker Invariant | | :--- | :--- | :--- | :--- | | **Projects & Governance** | Register project, update scope | Approve project governance status | Creator cannot approve project | | **Contractual Milestones** | Define milestone, submit evidence | Verify deliverable, approve milestone | Milestone author cannot verify | | **Disbursements** | Capture tranche drawdown request | Authorize payment release | Requestor cannot release payment | | **Budgets** | Define budget line, allocate funds | Approve statutory budget line | Allocator cannot approve budget | | **Evidence Queue** | Upload proof, ingest documentation | Approve & verify evidence artifact | Submitter cannot verify evidence | | **Change Requests** | Draft scope / budget variation | Approve & enact variation | Initiator cannot enact change | | **Site Visits** | Log field checklist & observations | Approve site inspection report | Inspector cannot self-sign report | | **Programmes** | Create programme structure | Approve programme governance | Creator cannot approve programme | ### 3.3 System Behavior on Maker-Checker Collisions When an authorised approver navigates to a record they personally created: 1. **Dropdown Controls**: The `Approved` option is disabled with the label: `Approved (Maker-Checker: Cannot approve own record)` 2. **Action Buttons**: Fast-track approve buttons are hidden, and a visual tag `Maker-Checker (Creator)` is displayed. 3. **Audit Trail**: Any attempt to bypass client controls logs a security violation in the immutable audit log (`settings_auditlog`). --- ## 4. RBAC Operational Roles & Boundaries ### 4.1 Role Assignment Rules 1. **`Contributor`**: Operational field execution. Strictly restricted to `view` and `add`. Contributors can create activities, submit evidence, and draft change requests, but **never approve records or export datasets**. 2. **`Supervisor`**: Operational oversight. Possesses `view, add, update, export`. Verifies milestones, inspects evidence, reviews site visits, and exports reports, subject to the Maker-Checker rule. 3. **`Manager`**: Comprehensive operational management. Possesses `all` across operational domains. Manages audit logs, notifications, and tenancy. 4. **`Executive`**: Strategic leadership. Possesses `all` across strategic domains (`dashboard`, `governance`, `grant_financials`, `evidence_risks`). 5. **`Admin`**: System administrator. Possesses `unrestricted: all`. Governs tenant boundaries, partitions, and system security. 6. **`Partner`**: External grantee / recipient. Strictly confined to `PartnerUI`. Any attempt to access `ConsoleUI` triggers an immediate security lockout. --- ## 5. Caching & Mutation Invalidation Workflow To ensure that caching never impedes record lifecycle updates or displays stale data while maximizing UI responsiveness, the following operational flow is enforced across ConsoleUI: ```mermaid sequenceDiagram autonumber actor User as User / Maker participant UI as ConsoleUI React Query participant Client as Axios HttpClient participant OutputCache as Backend OutputCache Redis/Memory participant DB as PostgreSQL Database User->>UI: Submits Record Mutation Create/Update/Approve UI->>Client: Dispatches POST / PUT / PATCH / DELETE Client->>DB: Executes Mutation in Database DB-->>Client: Returns 200 OK / 201 Created Client->>Client: Interceptor detects mutation: bumps activeMutationEpoch UI->>UI: onSuccess triggers invalidateQueries UI->>Client: Refetches active queries with _v = activeMutationEpoch Client->>OutputCache: GET /v1/api/* with new _v epoch Note over OutputCache: Cache Miss: new _v key never seen before OutputCache->>DB: Queries PostgreSQL for fresh data DB-->>OutputCache: Returns updated entities OutputCache-->>UI: Caches fresh data under _v and returns to UI UI-->>User: UI updates immediately with new status / record ``` ### 5.1 Operating Rules for Record Modifications 1. **Zero Manual Cache Eviction Required**: Frontend developers do not need to manually configure cache busters for standard operations. The Axios response interceptor in `httpClient.ts` automatically increments `activeMutationEpoch` on any successful mutating call (`POST`, `PUT`, `PATCH`, `DELETE`). 2. **Deterministic Invalidation**: Calling standard `queryClient.invalidateQueries({ queryKey: [...] })` or `invalidateAndBustCache(queryClient, filters)` guarantees that the subsequent refetch bypasses stale ASP.NET Core OutputCache entries. 3. **Optimized Read Cache**: When users navigate across unchanged views or switch tabs, identical `_v` tokens are reused, allowing backend OutputCache and React Query in-memory caches to fulfill requests in < 5ms without unnecessary database hits. --- ## 6. Background Job Lifecycle & Event Execution Workflows The dedicated worker host (`PostFundManagement.Jobs`) operates as a decoupled daemon executing recurring maintenance routines and asynchronous domain events dispatched from the API or internally from other jobs. ### 6.1 Event Ingestion & Job Persistence Flow ```mermaid flowchart TD subgraph Producer ["PostFundManagement.Api (Event Source)"] A["User Action / Lifecycle Transition"] --> B["Domain Command / Mutation"] B --> C["Instantiate IEvent (e.g. SyncUserEvent, ProjectReminderEvent)"] C --> D["IJobOrchestrator.SendAsync() or ScheduleAsync()"] end subgraph Store ["PostgreSQL Clustered Store (pfm-scheduler)"] D --> E[("QRTZ_JOB_DETAILS and QRTZ_TRIGGERS")] end subgraph Consumer ["PostFundManagement.Jobs (Execution Host)"] E -->|"Acquire Trigger Lock"| F["Quartz Scheduler Engine (MaxConcurrency = 5)"] F --> G["MediatorJob[TNotification]"] G --> H["Deserialize JSON Payload from JobDataMap"] H --> I["IMediator.Publish(notification)"] I --> J["Domain Event Handler: Business Logic in pfm DB"] J -.->|"Cascading Sub-Task Needed"| K["IJobOrchestrator.SendAsync: Dispatch One-Time Job"] K -.-> E end ``` ### 6.2 Standard Background Processes #### 1. Automated Project Monitoring & Reminders Process * **Trigger**: Scheduled cron job registered on `JobsWorker` startup. * **Operational Cycle**: 1. Job queries active projects and non-completed milestones across tenant partitions. 2. Compares milestone contractual due dates against current UTC time: - **T - 14 / T - 7 / T - 1 Days**: Emits reminder notification events to Grantee/Partner project managers. - **T + 0 Days (Overdue)**: Automatically flags the milestone as `Overdue` (`FR-M07-009`) and updates project RAG status to `At Risk` (`FR-M04-017`). 3. Escalates overdue notifications to internal Programme Managers for intervention. #### 2. Risk Monitoring & Automated Escalation Process * **Trigger**: Periodic recurring schedule. * **Operational Cycle**: 1. Queries all active project risk registers and Key Risk Indicators (KRIs) (`FR-M09-001` - `011`). 2. Evaluates current severity score ($\text{Risk Score} = \text{Likelihood} \times \text{Impact}$). 3. If risk score breaches the configured programme tolerance threshold: - Automatically logs a risk escalation event. - Dispatches alerts to Risk Managers and Portfolio Executives. 4. Sweeps assigned risk mitigation actions; identifies overdue mitigation plans and emits reminders to responsible assignees. #### 3. Email Notification Processing Workflow (`Platform.Email`) * **Trigger**: High-frequency recurring polling job or deferred one-time dispatch. * **Operational Cycle**: 1. Queries pending notifications from the transactional database where `Platform == NotificationPlatform.Email` and `Status == NotificationStatus.Pending` or `Queued`. 2. Resolves tenant context using `HeadlessTenantContextService`. 3. Formats email templates with recipient credentials and branding. 4. Transmits messages via MailKit/MimeKit SMTP engine with rate-limiting and connection pooling. 5. On successful delivery: Updates record status to `Sent`, stamps `DeliveredAt` timestamp, and logs dispatch telemetry (`FR-M25-001`). 6. On failure: Increments retry counter; if retry limit exceeded, marks as `Failed` with diagnostic error trace. ### 6.3 Recurring-to-One-Time Job Cascading Pattern When a recurring job evaluates a broad batch of records (e.g., scanning thousands of project indicators or verifying compliance expirations), it must not execute long-running operations synchronously in the recurring job thread: 1. The recurring job identifies items requiring heavy processing (e.g. generating an executive PDF digest or calling external webhooks). 2. For each identified item, it enqueues an isolated one-time job via `IJobOrchestrator.SendAsync(specificEvent)`. 3. This releases the recurring job quickly, distributes execution across the 5 available worker threads in `PostFundManagement.Jobs`, and guarantees that a single failed sub-task can be retried independently without stalling the entire recurring cycle.