# Phase 0 Authorization Inventory and Freeze

This document records the baseline implementation for Phase 0 of the system-wide RBAC migration. Phase 0 intentionally changes **no runtime authorization decisions**.

## Current authorization layers

The application currently has four distinct access layers that must remain independent during the migration:

1. authentication identifies the user;
2. module middleware decides whether an optional feature is enabled;
3. role/permission checks decide which functional action the user may perform;
4. branch isolation decides which branch-owned records the user may access.

The Spatie migration must not merge functional permissions with branch data scope.

## Current system roles

The seeded system-role baseline is:

- `super-administrator`;
- `branch-administrator`;
- `branch-manager`;
- `loan-officer`;
- `loan-inspector`;
- `cashier`;
- `accountant`;
- `debt-collector`;
- `hr-payroll-officer`;
- `auditor`.

The exact role-to-permission matrix is exported from the seeded database instead of duplicated manually in this document.

## Machine-readable inventory

Run:

```bash
php artisan authorization:inventory --json --strict \
  --output=storage/app/authorization/phase-0-inventory.json
```

The export contains:

- every application route, HTTP method, URI, action and middleware stack;
- route permission and module middleware;
- route authorization classification;
- every seeded permission and its assigned roles;
- every seeded role and its permission set;
- the complete role-permission matrix;
- user counts per role without exporting personal user data;
- permission-related source call sites;
- direct role-name source call sites;
- public/self-service/authenticated-exemption allowlists;
- legacy/broad permissions;
- strict classification findings.

The inventory intentionally does **not** export user names, emails, NINs, phone numbers or other customer/staff personal data.

## Route freeze rule

After this phase, every named application route must be one of:

- permission-protected;
- authenticated self-service;
- an explicitly documented authenticated transitional/support exemption;
- explicitly public/authentication-flow.

A new authenticated application route may not rely only on `auth` unless it is deliberately added to the allowlist with a reason. A new public application route must also be explicitly classified.

The current allowlists live in `config/authorization_inventory.php`.

## Current authenticated self-service routes

The following operations intentionally remain available to every authenticated user:

- logout;
- view own security settings;
- enable/confirm/disable own two-factor authentication;
- regenerate own two-factor recovery codes.

## Current authenticated transitional/support exemptions

These are frozen as explicit exceptions rather than being silently treated as authorized:

- `dashboard` — capability filtering is scheduled for RBAC Phase 8;
- `global-search.index` — cross-module search filtering is scheduled for RBAC Phase 8;
- `document-branding.asset` — document/export authorization is reviewed in RBAC Phase 8.

No additional implicit authenticated exemptions may be introduced without changing the registry and passing review.

## Public/authentication-flow routes

The explicit public list includes:

- root redirect;
- login form/submission;
- password-reset request/reset routes;
- two-factor challenge routes;
- module-gated public remote-payment evidence submission.

Framework-owned unnamed routes such as the Laravel health endpoint are outside this application-route classification.

## Legacy/broad permissions frozen for migration

The following are preserved in Phase 0 so the migration cannot silently remove current access:

- `customers.manage`;
- `expenses.manage`;
- `payroll.manage`;
- `collections.manage`.

Their replacement/granular permissions and migration notes are defined in `config/authorization_inventory.php`.

Phase 2 will establish the canonical permission catalog and make retirement of legacy permissions deliberate and testable.

## Source call-site inventory

`authorization:inventory` scans:

- `app/`;
- `routes/`;
- `resources/views/`;
- `database/seeders/`.

It records permission middleware, custom `hasPermission()` calls, Laravel `can()`/Blade `@can`, Gate calls, authorization calls, `hasRole()` usage, and direct role-name queries that match the Phase 0 patterns.

This inventory is observational in Phase 0. Later static-audit phases will begin rejecting legacy helper and hard-coded role-check patterns after their migration cutoff.

## CI gate

Foundation CI runs the strict inventory after fresh migrations and seeders. The gate fails when:

- an application route is not classified;
- a route references a permission that does not exist after seeding;
- a route allowlist entry becomes stale;
- a frozen legacy permission unexpectedly disappears before its migration phase.

The SQLite test job also preserves the JSON inventory as a CI artifact so reviewers can inspect the exact role-permission matrix for the release commit.

## Phase 0 completion criteria

Phase 0 is complete when:

- the strict inventory passes on SQLite and MySQL;
- the role/permission matrix is exportable from seeded data;
- route classifications are complete;
- current authorization and role-name call sites are discoverable;
- no runtime authorization behavior has changed;
- the full application test suite remains green.
