# Phase 9 — Direct Role-Check Audit and Final RBAC Cleanup

## Objective

Phase 9 removes remaining runtime authorization decisions that depend directly on role names and prepares the application for the final removal of deprecated authorization compatibility paths.

The target state is simple:

- permissions and policies decide whether a user may perform an action;
- roles remain permission bundles and administration metadata;
- role names are not used as hidden authorization rules in controllers, routes, services, middleware, or Blade views;
- frontend visibility and backend enforcement use the same canonical permission identifiers;
- deprecated permission aliases are removed only after runtime usage is proven to be zero.

## Safety boundary for this step

This audit-gate step **does not change existing runtime access**, remove roles, or delete compatibility permissions.

Before hard removals, Phase 9 first creates a deterministic inventory of direct role-name coupling. This keeps the migration reversible and prevents a cleanup commit from accidentally denying legitimate users or widening access.

## Audit command

Run the human-readable audit:

```bash
php artisan authorization:audit-role-checks
```

Run the strict audit:

```bash
php artisan authorization:audit-role-checks --strict
```

Emit JSON:

```bash
php artisan authorization:audit-role-checks --json
```

Persist an audit artifact:

```bash
php artisan authorization:audit-role-checks \
    --strict \
    --output=storage/app/authorization/phase-9-role-check-audit.json
```

A custom source path can be supplied with one or more `--path` options when reviewing a focused module.

## What is classified as an authorization role check

The audit treats these patterns as runtime authorization coupling:

- `hasRole(...)`
- `hasAnyRole(...)`
- `hasAllRoles(...)`
- `role:` middleware
- Blade role directives such as `@role`, `@hasrole`, `@hasanyrole`, and `@hasallroles`

Under `--strict`, an unapproved authorization role check returns a failure exit code.

The preferred replacement is a canonical permission check or policy decision, for example `can(...)`, permission middleware, a policy method, or another authorization service backed by the canonical permission catalog.

## Structural role references

Some role-name references are legitimate because the application must still manage roles themselves. Examples include:

- listing roles in the roles administration UI;
- assigning a role to a user;
- resolving default/system role metadata;
- maintaining role-to-permission matrices.

These are reported separately as **structural role references**. They do not fail strict mode, but references outside documented structural paths remain visible for review.

A structural-role exception is not permission to use role names for authorization.

## Exception policy

Temporary exceptions live in:

```text
config/authorization_role_check_audit.php
```

Every approved path must have a written reason. Prefer a narrow exact file path over a directory prefix.

Exceptions are temporary compatibility controls, not permanent architecture. Each exception must be reviewed and removed as its call site is migrated to canonical permissions or policies.

## Phase 9 execution sequence

1. Run the source/runtime role-check audit and record all findings.
2. Classify each finding as authorization coupling or legitimate role administration.
3. Replace authorization role checks with canonical permission/policy checks module by module.
4. Verify frontend navigation/actions and backend routes/controllers use the same permission identifiers.
5. Run the existing authorization inventory/catalog audits to identify deprecated aliases and missing identifiers.
6. Prove deprecated aliases have zero runtime/source usage.
7. Remove stale compatibility aliases and their bridge code only after regression coverage passes.
8. Enable `authorization:audit-role-checks --strict` in CI once the repository baseline contains no unapproved role authorization checks.
9. Run the full authorization regression suite and cross-role access matrix before merging final removals.

## Merge criteria for the audit-gate commit

This initial Phase 9 audit-gate commit is ready when:

- the audit command deterministically classifies direct role checks;
- strict mode fails for an unapproved authorization role check;
- a documented temporary exception remains visible but does not fail strict mode;
- structural role-management queries are classified separately;
- exact and directory-prefix approval paths are supported;
- no runtime roles, permissions, or compatibility aliases are removed in the same commit.

## Next implementation step

After this gate is merged or validated, run it against the full application source and use its findings as the migration queue. Convert those findings to canonical permission/policy checks first. Only then perform compatibility alias removal and enable the strict audit in CI.
