PR Body Implements Spec 065 “Tenant RBAC v1” with capabilities-first RBAC, tenant membership scoping (Option 3), and consistent Filament action semantics. Key decisions / rules Tenancy Option 3: tenant switching is tenantless (ChooseTenant), tenant-scoped routes stay scoped, non-members get 404 (not 403). RBAC model: canonical capability registry + role→capability map + Gates for each capability (no role-string checks in UI logic). UX policy: for tenant members lacking permission → actions are visible but disabled + tooltip (avoid click→403). Security still enforced server-side. What’s included Capabilities foundation: Central capability registry (Capabilities::*) Role→capability mapping (RoleCapabilityMap) Gate registration + resolver/manager updates to support tenant-scoped authorization Filament enforcement hardening across the app: Tenant registration & tenant CRUD properly gated Backup/restore/policy flows aligned to “visible-but-disabled” where applicable Provider operations (health check / inventory sync / compliance snapshot) guarded and normalized Directory groups + inventory sync start surfaces normalized Policy version maintenance actions (archive/restore/prune/force delete) gated SpecKit artifacts for 065: spec.md, plan/tasks updates, checklists, enforcement hitlist Security guarantees Non-member → 404 via tenant scoping/membership guards. Member without capability → 403 on execution, even if UI is disabled. No destructive actions execute without proper authorization checks. Tests Adds/updates Pest coverage for: Tenant scoping & membership denial behavior Role matrix expectations (owner/manager/operator/readonly) Filament surface checks (visible/disabled actions, no side effects) Provider/Inventory/Groups run-start authorization Verified locally with targeted vendor/bin/sail artisan test --compact … Deployment / ops notes No new services required. Safe change: behavior is authorization + UI semantics; no breaking route changes intended. Co-authored-by: Ahmed Darrazi <ahmeddarrazi@MacBookPro.fritz.box> Reviewed-on: #79
123 lines
6.4 KiB
Markdown
123 lines
6.4 KiB
Markdown
# Implementation Plan: Tenant RBAC v1
|
|
|
|
**Branch**: `065-tenant-rbac-v1` | **Date**: 2026-01-27 | **Spec**: [spec.md](spec.md)
|
|
**Input**: Feature specification from `/specs/[###-feature-name]/spec.md`
|
|
|
|
**Note**: This template is filled in by the `/speckit.plan` command. See `.specify/scripts/` for helper scripts.
|
|
|
|
## Summary
|
|
|
|
This plan outlines the implementation of a capabilities-first Tenant RBAC system within the existing Laravel and Filament application. The primary requirement is to introduce granular, server-side enforced permissions for tenant users, managed through a new "Members" UI.
|
|
|
|
The technical approach involves:
|
|
1. Verifying the existing `tenant_memberships` table matches the spec (role + minimal provenance fields).
|
|
2. Using the existing central capability registry (`App\Support\Auth\Capabilities`) and role → capability mapping to enforce least privilege.
|
|
3. Ensuring Laravel Gates are defined per capability for all registry entries (no hand-maintained capability lists).
|
|
4. Auditing / completing the Filament Relation Manager (`TenantMembershipsRelationManager`) so only Owners can manage memberships.
|
|
5. Adding/expanding unit + feature tests with Pest to ensure the RBAC system is secure and correct.
|
|
|
|
## Phases & Checkpoints
|
|
|
|
Phase 1 — Setup & Database
|
|
- Done when: `tenant_memberships` schema + relationships are verified and documented, and all related tests pass.
|
|
|
|
Phase 2 — Foundational RBAC Core
|
|
- Done when: capability registry + role mapping are aligned with least-privilege semantics and Gates are registered from `Capabilities::all()`.
|
|
- Done when: request-scope caching prevents repeated membership queries (query-count test).
|
|
|
|
Phase 3 — Membership Management UI
|
|
- Done when: Owners can add/change/remove members via Filament, last-owner rules are enforced, and all membership mutations require confirmation.
|
|
- Done when: members UI render/hydration is DB-only (no outbound HTTP and no jobs dispatched).
|
|
|
|
Phase 4 — Authorization Enforcement
|
|
- Done when: tenant route scoping is deny-as-not-found for non-members and global search is tenant-scoped.
|
|
- Done when: enforcement sweep removes role-ish authorization checks from tenant-plane feature code and replaces them with capability Gates/Policies.
|
|
|
|
Phase 5 — Polish & Finalization
|
|
- Done when: Pint passes for all changed files and the full test suite passes.
|
|
|
|
## Technical Context
|
|
|
|
**Language/Version**: PHP 8.4+
|
|
**Primary Dependencies**: Laravel 12, Filament 5, Livewire 4, Pest 4
|
|
**Storage**: PostgreSQL
|
|
**Testing**: Pest
|
|
**Target Platform**: Web (Laravel application)
|
|
**Project Type**: Web application
|
|
**Performance Goals**: Membership/capability evaluation MUST be O(1) per request after initial load (NFR-001).
|
|
**Constraints**: RBAC UI surfaces MUST be DB-only at render time (NFR-003).
|
|
**Scale/Scope**: The system should be designed to handle a moderate number of tenants and users, with the potential to scale. Initial design should not be a bottleneck for future growth.
|
|
|
|
## Constitution Check
|
|
|
|
*GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.*
|
|
|
|
- [X] **Inventory-first**: N/A for this feature.
|
|
- [X] **Read/write separation**: All membership changes (write operations) are specified to require Owner-level privileges and will be implemented with confirmations and audit logs.
|
|
- [X] **Graph contract path**: N/A. The spec explicitly states no Graph calls for RBAC UI.
|
|
- [X] **Deterministic capabilities**: The role-to-capability mapping is deterministic and defined in a central place.
|
|
- [X] **RBAC Standard**: This feature implements the RBAC standard. It establishes the two-plane separation, capabilities-first authorization, and least-privilege roles.
|
|
- [X] **Tenant isolation**: All queries and actions are tenant-scoped through the `tenant_memberships` table.
|
|
- [X] **Run observability**: N/A for the core RBAC logic, as it's synchronous. Any long-running operations triggered by authorized users will follow this principle.
|
|
- [X] **Automation**: N/A for this feature.
|
|
- [X] **Data minimization**: The `tenant_memberships` table stores only essential information (IDs, role, and minimal provenance fields like `source` and `created_by_user_id`).
|
|
- [X] **Badge semantics (BADGE-001)**: The role badge in the members list will use the `BadgeCatalog`.
|
|
|
|
## Project Structure
|
|
|
|
### Documentation (this feature)
|
|
|
|
```text
|
|
specs/065-tenant-rbac-v1/
|
|
├── plan.md # This file
|
|
├── research.md # Phase 0 output
|
|
├── data-model.md # Phase 1 output
|
|
├── quickstart.md # Phase 1 output
|
|
├── contracts/
|
|
│ └── capabilities.md # Phase 1 output
|
|
└── tasks.md # Phase 2 output (/speckit.tasks command)
|
|
```
|
|
|
|
### Source Code (repository root)
|
|
|
|
The project follows a standard Laravel structure. Key files for this feature will be located in:
|
|
|
|
```text
|
|
app/
|
|
├── Models/
|
|
│ ├── TenantMembership.php # Existing pivot model
|
|
│ └── User.php # Existing relationship to tenants/memberships
|
|
│ └── Tenant.php # Existing relationship to users/memberships
|
|
├── Policies/
|
|
│ └── (optional) TenantMembershipPolicy.php # Optional policy for membership mutations (currently Gate-driven)
|
|
├── Providers/
|
|
│ └── AuthServiceProvider.php # Register per-capability Gates
|
|
└── Filament/
|
|
└── Resources/
|
|
└── TenantResource/
|
|
└── RelationManagers/
|
|
└── TenantMembershipsRelationManager.php # New Filament relation manager
|
|
|
|
database/
|
|
└── migrations/
|
|
└── 2026_01_25_022729_create_tenant_memberships_table.php # Existing migration
|
|
|
|
tests/
|
|
├── Feature/
|
|
│ └── Filament/
|
|
│ └── TenantMembersTest.php # New feature test for RBAC UI
|
|
└── Unit/
|
|
└── Auth/ # Existing unit tests for capability registry + resolver
|
|
```
|
|
|
|
**Structure Decision**: The implementation will use the existing Laravel project structure. New classes and files will be created in their conventional locations. The primary UI for membership management will be a Filament Relation Manager on the `TenantResource`.
|
|
|
|
## Complexity Tracking
|
|
|
|
> **Fill ONLY if Constitution Check has violations that must be justified**
|
|
|
|
| Violation | Why Needed | Simpler Alternative Rejected Because |
|
|
|-----------|------------|-------------------------------------|
|
|
| [e.g., 4th project] | [current need] | [why 3 projects insufficient] |
|
|
| [e.g., Repository pattern] | [specific problem] | [why direct DB access insufficient] |
|