# Phase 5 — Customer, Loan Origination and Collateral Authorization

## Status

Phase 5 converts the customer, loan-product, loan-origination and collateral record boundaries to Laravel policies while preserving the existing Spatie permission catalog and branch-isolation architecture.

This phase intentionally does **not** change default role grants or rename permissions. It adds a record-level authorization contract around the permissions that already exist.

## Security model

Phase 5 uses two complementary boundaries:

1. **Functional permission middleware** — existing `permission:*` middleware continues to answer what operation the user may perform.
2. **Laravel policy middleware / Gate authorization** — policies answer whether that operation may be performed on the specific record, including branch access.

The existing functional middleware is kept during the staged RBAC migration so this phase does not widen access or create a rollback gap. Later cutover/cleanup phases can remove the legacy middleware wrapper after all modules have policy/Gate coverage.

## Policies

### `CustomerPolicy`

Covers:

- `viewAny` / `view`;
- `create`;
- `update`;
- `manageDocuments`;
- `manageGuarantors`;
- `manageWatchlist`.

Record operations require both the matching permission and access to the customer's branch.

### `LoanProductPolicy`

Covers:

- list/view;
- create/update;
- repayment preview.

Loan products are business-level configuration, not branch-owned records, so the policy preserves the existing permission model and does not invent a branch dimension.

### `LoanPolicy`

Covers Phase 5 origination concerns:

- `viewAny` / `view`;
- `create`;
- `update`;
- origination status transitions;
- contract generation;
- loan document upload;
- loan document download.

Record operations require the relevant loan permission and access to the loan branch.

Approval, disbursement, payment, remote-payment, top-up, settlement, restructuring, write-off and recovery authorization remain Phase 6 work.

### `CollateralPolicy`

Covers:

- list/view;
- create/update;
- custody/status movement;
- collateral files;
- collateral category administration.

Branch-owned collateral actions require the matching permission and access to the collateral branch. Category administration remains business-scoped using the businesses reachable through the actor's accessible branches; super-admin remains system-wide through the canonical branch service.

## Route boundary

Phase 5 record routes now include policy middleware in addition to their functional permission middleware. Examples:

```text
permission:customers.view + can:view,customer
permission:customers.update + can:update,customer
permission:customers.documents + can:manageDocuments,customer

permission:loans.view + can:view,loan
permission:loans.update + can:update,loan
permission:loans.contract + can:generateContract,loan
permission:loans.documents + can:manageDocuments,loan

permission:collateral.view + can:view,collateral
permission:collateral.manage + can:update,collateral
permission:collateral.custody + can:move,collateral
permission:collateral.documents + can:manageDocuments,collateral
```

This is deliberate defense in depth during the migration. The policy boundary executes before controller business logic for record routes.

## Branch isolation remains independent

Phase 5 does not use Spatie Teams and does not encode branch IDs into role assignments.

Policies call `BranchAccessService`, which remains the canonical answer to **which branch-owned records** a user may act on. Functional permissions continue to answer **what** the user may do.

Existing query-level isolation remains unchanged:

- `Customer` continues to use its branch-aware builder/global scope;
- `Loan` continues to use `BranchScope`;
- `Collateral` continues to use `BranchScope`;
- route binding still resolves records so the policy can return a deterministic 403 for inaccessible branch-owned records.

## Workflow rules remain domain rules

Policies do not replace workflow-state validation.

Examples intentionally retained in controllers/services include:

- core loan terms editable only in draft/correction states;
- contract generation blocked in locked review/decision states;
- signed/supporting document upload state restrictions;
- collateral movement must contain a real status/location change;
- customer/collateral/guarantor references must belong to the selected branch/customer;
- required collateral/guarantor conditions remain enforced by loan workflow services.

These checks continue to return the existing validation/domain responses (commonly 422) instead of being collapsed into generic authorization failures.

## Super administrator

The existing `Gate::before` super-admin rule remains the single functional/policy bypass. `BranchAccessService::isSystemWide()` remains the data-scope bypass for branch isolation.

No new super-admin checks are scattered through Phase 5 controllers or policies.

## Permission semantics preserved

No permission names or default role grants change in this phase. Existing permissions remain authoritative, including:

- `customers.view`, `customers.create`, `customers.update`, `customers.documents`, `customers.guarantors`, `customers.watchlist`;
- `loan-products.view`, `loan-products.manage`;
- `loans.view`, `loans.create`, `loans.update`, `loans.contract`, `loans.documents`;
- `collateral.view`, `collateral.manage`, `collateral.custody`, `collateral.documents`.

The legacy umbrella `customers.manage` remains catalogued/deprecated exactly as before; Phase 5 does not reintroduce it as an authorization boundary.

## Regression coverage

`Phase5AuthorizationPolicyTest` verifies:

- matching permission + accessible branch succeeds;
- matching permission + inaccessible branch fails;
- permission with no branch assignment fails for branch-owned records;
- customer document/guarantor/watchlist abilities remain independent;
- loan-product read does not imply management;
- super-admin Gate bypass remains intentional;
- representative Phase 5 record routes contain both functional permission and policy middleware;
- cross-branch customer route access is denied at the policy boundary.

The existing full branch-isolation and module workflow suites remain required CI gates.

## Deployment impact

Phase 5 contains no database migration and no role/permission data migration. Deployment therefore requires only the normal application release process and permission cache behavior already covered by the repository's release verification.

## Deferred to Phase 6

The following are deliberately not changed here:

- loan approval decisions and maker-checker rules;
- additional collateral requested by the approval workflow;
- disbursement;
- payments and remote payments;
- top-ups;
- settlements;
- restructurings;
- write-offs and recoveries;
- arrears/collection actions.

Those operations move next because they combine authorization with financial postings and stronger maker-checker requirements.
