From aad55d1579ddde4ee2f3bb3c0cc742ca7d0e217b Mon Sep 17 00:00:00 2001 From: Ahmed Darrazi Date: Tue, 27 Jan 2026 23:28:27 +0100 Subject: [PATCH] feat(plan): create implementation plan for 065-tenant-rbac-v1 --- .../contracts/capabilities.md | 44 ++++++++ specs/065-tenant-rbac-v1/data-model.md | 32 ++++++ specs/065-tenant-rbac-v1/plan.md | 104 ++++++++++++++++++ specs/065-tenant-rbac-v1/quickstart.md | 74 +++++++++++++ specs/065-tenant-rbac-v1/research.md | 7 ++ 5 files changed, 261 insertions(+) create mode 100644 specs/065-tenant-rbac-v1/contracts/capabilities.md create mode 100644 specs/065-tenant-rbac-v1/data-model.md create mode 100644 specs/065-tenant-rbac-v1/plan.md create mode 100644 specs/065-tenant-rbac-v1/quickstart.md create mode 100644 specs/065-tenant-rbac-v1/research.md diff --git a/specs/065-tenant-rbac-v1/contracts/capabilities.md b/specs/065-tenant-rbac-v1/contracts/capabilities.md new file mode 100644 index 0000000..ceff228 --- /dev/null +++ b/specs/065-tenant-rbac-v1/contracts/capabilities.md @@ -0,0 +1,44 @@ +# Capability Contracts: Tenant RBAC v1 + +This document defines the canonical set of capabilities for the Tenant RBAC system. Feature code MUST use these capability strings when checking permissions with Laravel Gates (e.g., `Gate::allows('tenant.members.manage')`). + +## Naming Convention + +Capabilities follow the format: `tenant..` + +## Capability List (v1) + +### Core +- `tenant.core.view`: View the tenant dashboard and basic information. + +### Membership +- `tenant.members.view`: View the list of members in a tenant. +- `tenant.members.manage`: Add, remove, or change the roles of members in a tenant. (Owner-only) + +### Settings +- `tenant.settings.view`: View tenant settings. +- `tenant.settings.manage`: Modify tenant settings. + +### Providers +- `tenant.providers.view`: View provider connections. +- `tenant.providers.manage`: Add, edit, or remove provider connections. +- `tenant.providers.credentials.rotate`: Rotate credentials for a provider connection. +- `tenant.providers.run_ops`: Execute operations using a provider. + +### Operations & Monitoring +- `tenant.operations.view`: View tenant operations and monitoring data. +- `tenant.operations.start`: Start new tenant operations. + +### Inventory & Drift +- `tenant.inventory.view`: View tenant inventory. +- `tenant.inventory.sync`: Trigger a synchronization of the tenant inventory. +- `tenant.drift.view`: View drift detection reports. +- `tenant.drift.ack`: Acknowledge drift alerts. + +### Policies, Backups, & Restore +- `tenant.policies.view`: View policies. +- `tenant.policies.sync`: Synchronize policies. +- `tenant.policies.delete`: Delete policies. +- `tenant.backups.manage`: Manage backups. +- `tenant.restore.execute`: Execute a restore from a backup. +- `tenant.danger_zone`: Access to destructive "danger zone" actions. (Owner-only) diff --git a/specs/065-tenant-rbac-v1/data-model.md b/specs/065-tenant-rbac-v1/data-model.md new file mode 100644 index 0000000..f5e5b18 --- /dev/null +++ b/specs/065-tenant-rbac-v1/data-model.md @@ -0,0 +1,32 @@ +# Data Model: Tenant RBAC v1 + +This document outlines the data model for the Tenant RBAC feature, as defined in the feature specification. + +## Tables + +### `tenant_memberships` (New Table) + +This table is the source of truth for user membership and roles within a tenant. + +**Columns**: + +| Name | Type | Description | Constraints | +|---|---|---|---| +| `id` | `bigint` or `uuid` | Primary key. Follows repository convention. | Primary Key | +| `tenant_id` | `bigint` | Foreign key to the `tenants` table. | Not Null, FK to `tenants.id` | +| `user_id` | `bigint` | Foreign key to the `users` table. | Not Null, FK to `users.id` | +| `role` | `string` | The user's role within the tenant. | Not Null, Enum: `owner`, `manager`, `operator`, `readonly` | +| `created_at` | `timestamp` | Timestamp of creation. | Not Null | +| `updated_at` | `timestamp` | Timestamp of last update. | Not Null | + +**Indexes**: + +- `tenant_memberships_tenant_id_user_id_unique`: Unique constraint on `(tenant_id, user_id)` to ensure a user has only one role per tenant. +- `tenant_memberships_tenant_id_role_index`: Index on `(tenant_id, role)` for efficient role-based queries within a tenant. +- `tenant_memberships_user_id_index`: Index on `(user_id)` for efficiently finding all tenant memberships for a user. + +## Relationships + +- A `Tenant` has many `TenantMembership` records. +- A `User` has many `TenantMembership` records. +- A `TenantMembership` belongs to one `Tenant` and one `User`. diff --git a/specs/065-tenant-rbac-v1/plan.md b/specs/065-tenant-rbac-v1/plan.md new file mode 100644 index 0000000..d591a22 --- /dev/null +++ b/specs/065-tenant-rbac-v1/plan.md @@ -0,0 +1,104 @@ +# 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. Creating a `tenant_memberships` table to store user roles within each tenant. +2. Defining a central capability registry and mapping roles (`Owner`, `Manager`, `Operator`, `Readonly`) to specific capabilities. +3. Using Laravel Gates and Policies to enforce these capabilities throughout the application. +4. Building a Filament Relation Manager (`MembersRelationManager`) to provide a UI for Owners to manage tenant memberships. +5. Adding comprehensive feature and unit tests with Pest to ensure the RBAC system is secure and correct. + +## 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 and role). +- [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 # New Eloquent model +│ └── User.php # Add relationship to TenantMembership +│ └── Tenant.php # Add relationship to TenantMembership +├── Policies/ +│ └── TenantMembershipPolicy.php # New policy for managing memberships +├── Providers/ +│ └── AuthServiceProvider.php # Register gates and policies +└── Filament/ + └── Resources/ + └── TenantResource/ + └── RelationManagers/ + └── MembersRelationManager.php # New Filament relation manager + +database/ +├── factories/ +│ └── TenantMembershipFactory.php # New model factory +└── migrations/ + └── [timestamp]_create_tenant_memberships_table.php # New migration + +tests/ +├── Feature/ +│ └── Filament/ +│ └── TenantMembersTest.php # New feature test for RBAC UI +└── Unit/ + └── TenantRBACTest.php # New unit test for role-capability mapping +``` + +**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] | diff --git a/specs/065-tenant-rbac-v1/quickstart.md b/specs/065-tenant-rbac-v1/quickstart.md new file mode 100644 index 0000000..bdd3226 --- /dev/null +++ b/specs/065-tenant-rbac-v1/quickstart.md @@ -0,0 +1,74 @@ +# Quickstart: Tenant RBAC v1 + +This guide provides a quick overview for developers on how to use the Tenant RBAC v1 system. + +## Checking Permissions + +The core of the RBAC system is a set of defined capabilities. To check if the currently authenticated user has a specific capability, use Laravel's `Gate` facade. + +**NEVER check for roles directly.** Always check for capabilities. + +### In PHP (Controllers, Policies, Livewire Components) + +```php +use Illuminate\Support\Facades\Gate; + +// Check for a specific capability +if (Gate::allows('tenant.members.manage')) { + // User can manage members +} + +// You can also deny access +if (Gate::denies('tenant.settings.manage')) { + abort(403); +} +``` + +### In Blade Views + +You can use the `@can` and `@cannot` directives in your Blade templates to conditionally show UI elements. + +```blade +@can('tenant.members.manage') + +@endcan + +@cannot('tenant.danger_zone') +

You are not authorized to access the danger zone.

+@endcannot +``` + +### In Filament Resources + +Filament actions and pages can be protected using the `can` method. + +```php +use Filament\Actions\Action; +use Filament\Resources\Pages\ListRecords; + +// Protecting an action +Action::make('delete') + ->requiresConfirmation() + ->action(fn ($record) => $record->delete()) + ->visible(fn ($record) => Gate::allows('tenant.policies.delete', $record)); + +// Protecting a page +class ListMembers extends ListRecords +{ + // ... + public static function canView(): bool + { + return Gate::allows('tenant.members.view'); + } +} +``` + +## Capability Reference + +A full list of available capabilities is defined in `specs/065-tenant-rbac-v1/contracts/capabilities.md`. + +## Key Principles + +1. **Capabilities, Not Roles**: All authorization checks MUST be against capabilities, not roles (`owner`, `manager`, etc.). This decouples the application's logic from the role definitions. +2. **Server-Side Enforcement**: UI hiding is not security. Always enforce permissions on the server-side (in controllers, actions, or policies) in addition to hiding UI elements. +3. **Use Policies for Model-Specific Logic**: For authorization logic that depends on a specific model instance, use a Laravel Policy class. diff --git a/specs/065-tenant-rbac-v1/research.md b/specs/065-tenant-rbac-v1/research.md new file mode 100644 index 0000000..931797b --- /dev/null +++ b/specs/065-tenant-rbac-v1/research.md @@ -0,0 +1,7 @@ +# Research: Tenant RBAC v1 + +**Date**: 2026-01-27 + +No significant research was required for this feature. The specification is comprehensive and relies on established technologies and patterns within the project (Laravel, Filament, Pest). + +The implementation will follow standard Laravel practices for Gates, Policies, and database migrations.