# Phase 6 — Loan Decisions and Financial Movement Authorization

## Purpose

Phase 6 applies the system-wide authorization architecture to loan decisions and money-moving loan workflows. It keeps branch isolation independent from functional permissions and leaves workflow/state/accounting invariants in the domain services.

## Scope

This phase covers:

- loan approval decisions and reviewer-requested collateral;
- loan disbursement;
- direct loan payment receipt posting;
- remote payment submission and verification;
- loan top-up creation and execution;
- early settlement;
- restructuring request and decision;
- write-off request, decision and recovery record access;
- arrears follow-up;
- payment-deadline installment excuses.

Accounting administration, expenses, payroll, cash closing and fixed assets remain Phase 7 work.

## Authorization layers

Each protected financial action now has the following boundaries where applicable:

1. existing authenticated/module middleware;
2. existing functional `permission:*` middleware;
3. Laravel `can:*` policy middleware for record-level actions;
4. policy checks combining functional permission and branch accessibility;
5. transactional service-level Gate rechecks for high-risk mutations;
6. workflow, balance, account-branch and maker-checker invariants in domain services.

Super Administrator behavior continues to come only from the global `Gate::before` rule. Spatie Teams remains disabled and branch visibility remains owned by `BranchAccessService` / branch scopes.

## Policies

Phase 6 extends `LoanPolicy` with abilities for:

- `approve`;
- `addCollateral`;
- `disburse`;
- `receivePayment`;
- `submitRemotePayment`;
- `createTopUp`;
- `executeTopUp`;
- `settle`;
- `restructure`;
- `requestWriteOff`;
- `viewArrears`;
- `followUpArrears`;
- `excuseInstallment`.

Record policies were added for:

- `LoanDisbursement`;
- `LoanPayment`;
- `RemotePaymentSubmission`;
- `LoanTopUp`;
- `LoanEarlySettlement`;
- `LoanRestructuring`;
- `LoanWriteOff`.

The HTTP route layer retains the existing functional permission boundary and adds record policy middleware rather than replacing it during this staged cutover.

## Service-level authorization

The following mutation services now re-authorize with Laravel Gate so a direct service call cannot rely only on route middleware:

- `LoanApprovalService`;
- `LoanDisbursementService`;
- `LoanPaymentService`;
- `RemotePaymentService`;
- `LoanTopUpService`;
- `LoanEarlySettlementService`;
- `LoanRestructuringService`.

Write-off request/approval/recovery services already performed explicit functional-permission and branch checks before Phase 6; record policies now protect their HTTP record boundaries as well.

Direct loan-payment posting and remote-payment verification deliberately use separate service entry points. A remote verifier therefore does not acquire general `payments.receive` authority merely because an approved remote submission must be posted to the loan ledger.

## Maker-checker separation

`FinancialMakerCheckerService` centralizes the new high-risk separation rules when the business has maker-checker enabled:

- the employee who approved a loan cannot also disburse it;
- the employee who approved a replacement loan cannot execute that top-up disbursement;
- the employee who requested a restructuring cannot approve or reject that same request;
- a staff member who submitted remote-payment evidence cannot verify that same submission.

Existing rules remain in force:

- a loan creator cannot approve their own loan when maker-checker is enabled;
- a write-off requester cannot approve their own write-off when maker-checker is enabled.

Ordinary loan repayment receipt posting remains a single-step financial operation; Phase 6 does not invent an additional checker where the business workflow did not previously require one.

## Account-branch safeguards

Phase 6 preserves existing same-branch checks for disbursement, repayment and write-off recovery and adds explicit transactional same-branch checks for:

- top-up disbursement accounts;
- early-settlement receiving accounts.

This prevents a financial-account identifier from moving value across branch boundaries even if form/controller validation is bypassed.

## Granular installment-excuse permission

The installment excuse routes no longer reuse the broad `loans.update` permission.

New canonical permission:

- `loans.installments.excuse`

Risk classification: `approve`.

To preserve existing effective access during migration, it is granted only to the default roles that previously had `loans.update` and could therefore reach the action:

- Branch Administrator;
- Branch Manager;
- Loan Officer.

It is not granted to Loan Inspector, Cashier, Accountant, Debt Collector, HR/Payroll Officer or Auditor. The authorization catalog regression test removes this Phase 6 replacement grant before recomputing the frozen Phase 2 access fingerprint, proving no unrelated default-role capability changed.

## Preserved domain behavior

Phase 6 does not weaken or replace existing business rules such as:

- valid loan workflow states;
- manager approval thresholds;
- signed-contract requirements;
- repayment schedule reconciliation;
- top-up eligibility and override authorization;
- settlement adjustment authorization and principal-waiver protection;
- restructuring stale-balance/schedule detection;
- write-off evidence and balance rules;
- write-off recovery limits;
- nested record ownership checks;
- branch isolation/global scopes.

Policy failures are authorization failures; workflow-state or accounting-integrity failures remain domain validation failures.

## Regression coverage

Phase 6 tests verify:

- financial Loan policy abilities require both permission and accessible branch;
- the new installment-excuse permission preserves only prior effective access;
- maker-checker blocks the identified same-employee high-risk combinations;
- maker-checker restrictions are inactive when the business setting is disabled;
- representative financial routes retain functional permissions and add policy middleware;
- high-risk services retain internal Gate/maker-checker checks;
- the canonical permission count and default role matrix are updated deliberately.

The full Foundation CI suite remains the merge gate, including SQLite tests, MySQL migrations/performance checks, production configuration/cache compilation and release/restore verification.
