# Implementation Plan: Tenant RBAC v1 **Branch**: `062-tenant-rbac-v1` | **Date**: 2026-01-25 | **Spec**: [specs/062-tenant-rbac-v1/spec.md](specs/062-tenant-rbac-v1/spec.md) **Input**: Feature specification from `specs/062-tenant-rbac-v1/spec.md` ## Summary This feature introduces a comprehensive Role-Based Access Control (RBAC) system for TenantAtlas. It leverages Microsoft Entra ID for authentication and manages authorization on a per-Suite-Tenant basis. The core of this feature is the `tenant_memberships` table, which will be the source of truth for authorization. The implementation will follow a capabilities-first approach, where permissions are checked using Gates and Policies rather than direct role comparisons. ### Clarifications - No Entra user credentials are stored; only the dedicated break-glass platform superadmin may have local credentials. - All access control decisions must be auditable. - Non-member access to tenant-scoped routes (including direct `/t/{tenant}` URLs) MUST be deny-as-not-found (404). - A canonical capability registry (e.g., `app/Support/Auth/Capabilities.php` or an enum) will be the source of truth. Role → capability mapping MUST reference only registry entries; tests must fail if unknown capabilities are used. - Audit action_ids will be standardized: - `tenant_membership.add` - `tenant_membership.role_change` - `tenant_membership.remove` - `tenant_membership.bootstrap_assign` - `tenant_membership.bootstrap_recover` - `tenant_role_mapping.create` - `tenant_role_mapping.update` - `tenant_role_mapping.delete` - The system MUST prevent removing or demoting the last remaining `owner` membership for a Suite Tenant. ## Technical Context **Language/Version**: PHP 8.4 **Primary Dependencies**: Laravel 12, Filament v5, Livewire v4 **Storage**: PostgreSQL **Testing**: Pest **Target Platform**: Web **Project Type**: Web Application **Performance Goals**: - User login and tenant selection should be completed in under 3 seconds. - Membership changes should be reflected in under 2 seconds. - Audit log entries should be created in under 1 second. **Constraints**: - No Entra user credentials are stored; only the dedicated break-glass platform superadmin may have local credentials. - All access control decisions must be auditable. **Scale/Scope**: - The system should be designed to handle up to 1,000 tenants and 10,000 users. ## Constitution Check *GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.* - **Inventory-first**: Not directly applicable. - **Read/write separation**: **PASS**. - **Graph contract path**: **PASS**. - **Deterministic capabilities**: **PASS**. - **Tenant isolation**: **PASS**. - **Run observability**: **PASS**. - **Automation**: **PASS**. - **Data minimization**: **PASS**. - **Badge semantics (BADGE-001)**: Not applicable. ## Project Structure ### Documentation (this feature) ```text specs/062-tenant-rbac-v1/ ├── plan.md # This file ├── research.md # Phase 0 output ├── data-model.md # Phase 1 output ├── quickstart.md # Phase 1 output ├── contracts/ # Phase 1 output └── tasks.md # Phase 2 output ``` ### Source Code (repository root) ```text app/ ├── Models/ │ ├── User.php │ ├── Tenant.php │ ├── TenantMembership.php │ └── TenantRoleMapping.php ├── Policies/ │ └── TenantMembershipPolicy.php ├── Providers/ │ └── AuthServiceProvider.php └── Support/ └── Auth/ └── Capabilities.php database/ └── migrations/ ├── XXXX_XX_XX_XXXXXX_create_tenant_memberships_table.php └── XXXX_XX_XX_XXXXXX_create_tenant_role_mappings_table.php routes/ └── web.php tests/ └── Feature/ └── TenantRBAC.php ``` **Structure Decision**: The project is a standard Laravel application. New files will be created in the appropriate directories. ## Complexity Tracking No violations to the constitution.