feat(plan): create implementation plan for 065-tenant-rbac-v1
This commit is contained in:
parent
3a3de045ba
commit
aad55d1579
44
specs/065-tenant-rbac-v1/contracts/capabilities.md
Normal file
44
specs/065-tenant-rbac-v1/contracts/capabilities.md
Normal file
@ -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.<domain>.<verb>`
|
||||||
|
|
||||||
|
## 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)
|
||||||
32
specs/065-tenant-rbac-v1/data-model.md
Normal file
32
specs/065-tenant-rbac-v1/data-model.md
Normal file
@ -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`.
|
||||||
104
specs/065-tenant-rbac-v1/plan.md
Normal file
104
specs/065-tenant-rbac-v1/plan.md
Normal file
@ -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] |
|
||||||
74
specs/065-tenant-rbac-v1/quickstart.md
Normal file
74
specs/065-tenant-rbac-v1/quickstart.md
Normal file
@ -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')
|
||||||
|
<button>Add Member</button>
|
||||||
|
@endcan
|
||||||
|
|
||||||
|
@cannot('tenant.danger_zone')
|
||||||
|
<p>You are not authorized to access the danger zone.</p>
|
||||||
|
@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.
|
||||||
7
specs/065-tenant-rbac-v1/research.md
Normal file
7
specs/065-tenant-rbac-v1/research.md
Normal file
@ -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.
|
||||||
Loading…
Reference in New Issue
Block a user