065-tenant-rbac-v1 #79
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