9.3 KiB
Implementation Plan: Spec 080 Workspace-Managed Tenant Administration Migration
Branch: 080-workspace-managed-tenant-admin | Date: 2026-02-07 | Spec: /specs/080-workspace-managed-tenant-admin/spec.md
Input: Feature specification from /Users/ahmeddarrazi/Documents/projects/TenantAtlas/specs/080-workspace-managed-tenant-admin/spec.md
Note: This template is filled in by the /speckit.plan command. See .specify/scripts/ for helper scripts.
Summary
Migrate tenant administration surfaces out of tenant scope (/admin/t/{tenant}/*) into workspace scope (/admin/*) and keep tenant scope strictly for operational modules.
Implementation strategy:
- Introduce a second Filament panel for tenant operations at
/admin/t/{tenant}. - Convert the existing admin panel at
/admininto a tenantless workspace management panel. - Register management resources/pages only in the workspace panel, ensuring tenant-scoped management routes are not registered (404).
- Rewire internal CTAs/links (onboarding, required permissions, provider connection edit) to the new canonical workspace routes.
Technical Context
Language/Version: PHP 8.4.15 (Laravel 12)
Primary Dependencies: Filament v5, Livewire v4, Tailwind v4
Storage: PostgreSQL (via Sail)
Testing: Pest v4 (PHPUnit v12 runner)
Target Platform: Web application (server-rendered Filament/Livewire)
Project Type: Laravel monolith
Performance Goals: No new performance targets; management viewers must remain DB-only at render time
Constraints:
- No external calls during render for management viewers (DB-only).
- Dev-stage removed routes must 404 (no redirects).
- 404 vs 403 semantics must follow RBAC-UX. Scale/Scope: Enterprise SaaS IA separation across admin surfaces (route + navigation correctness)
Constitution Check
GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.
Assessment (pre-Phase 0): PASS
- No new Graph calls are introduced by this migration.
- No new long-running operations are introduced.
- Authorization behavior is being tightened via panel separation and route registration.
- Monitoring/management viewers remain DB-only.
Notes:
-
This feature changes how routes are registered (which affects discovery, global search, and navigation). It must include regression tests ensuring removed tenant-scoped management routes do not exist.
-
Inventory-first: clarify what is “last observed” vs snapshots/backups
-
Read/write separation: any writes require preview + confirmation + audit + tests
-
Graph contract path: Graph calls only via
GraphClientInterface+config/graph_contracts.php -
Deterministic capabilities: capability derivation is testable (snapshot/golden tests)
-
RBAC-UX: two planes (/admin vs /system) remain separated; cross-plane is 404; non-member tenant access is 404; member-but-missing-capability is 403; authorization checks use Gates/Policies + capability registries (no raw strings, no role-string checks)
-
RBAC-UX: destructive-like actions require
->requiresConfirmation()and clear warning text -
RBAC-UX: global search is tenant-scoped; non-members get no hints; inaccessible results are treated as not found (404 semantics)
-
Tenant isolation: all reads/writes tenant-scoped; cross-tenant views are explicit and access-checked
-
Run observability: long-running/remote/queued work creates/reuses
OperationRun; start surfaces enqueue-only; Monitoring is DB-only; DB-only <2s actions may skip runs but security-relevant ones still audit-log; auth handshake exception OPS-EX-AUTH-001 allows synchronous outbound HTTP on/auth/*withoutOperationRun -
Automation: queued/scheduled ops use locks + idempotency; handle 429/503 with backoff+jitter
-
Data minimization: Inventory stores metadata + whitelisted meta; logs contain no secrets/tokens
-
Badge semantics (BADGE-001): status-like badges use
BadgeCatalog/BadgeRenderer; no ad-hoc mappings; new values include tests
Project Structure
Documentation (this feature)
specs/[###-feature]/
├── plan.md # This file (/speckit.plan command output)
├── research.md # Phase 0 output (/speckit.plan command)
├── data-model.md # Phase 1 output (/speckit.plan command)
├── quickstart.md # Phase 1 output (/speckit.plan command)
├── contracts/ # Phase 1 output (/speckit.plan command)
└── tasks.md # Phase 2 output (/speckit.tasks command - NOT created by /speckit.plan)
Source Code (repository root)
app/
├── Filament/
│ ├── Pages/
│ │ ├── Workspaces/
│ │ ├── Monitoring/
│ │ └── …
│ ├── Resources/
│ └── Concerns/
├── Providers/
│ └── Filament/
│ ├── AdminPanelProvider.php
│ ├── TenantPanelProvider.php
│ └── SystemPanelProvider.php
├── Support/
│ └── Middleware/
routes/
└── web.php
tests/
├── Feature/
└── Unit/
bootstrap/
└── providers.php
Structure Decision: Laravel monolith. Panel providers define panel boundaries. Routes outside Filament are defined in routes/web.php.
Complexity Tracking
No constitution violations requiring justification.
Phase 0 — Outline & Research
Outputs (written during /speckit.plan):
/Users/ahmeddarrazi/Documents/projects/TenantAtlas/specs/080-workspace-managed-tenant-admin/research.md
Research questions (all resolved):
- How to configure a tenancy panel whose URLs are
/admin/t/{tenant}without duplicating/t/. - How to enforce route removal: do not register resources/pages in the tenant panel.
- How to keep global search isolated by panel registration.
Phase 1 — Design & Contracts
Outputs:
/Users/ahmeddarrazi/Documents/projects/TenantAtlas/specs/080-workspace-managed-tenant-admin/data-model.md/Users/ahmeddarrazi/Documents/projects/TenantAtlas/specs/080-workspace-managed-tenant-admin/contracts//Users/ahmeddarrazi/Documents/projects/TenantAtlas/specs/080-workspace-managed-tenant-admin/quickstart.md
Panel Design
Workspace panel (Manage)
- ID:
admin(keep existing ID to avoid breakingpanel:adminmiddleware usage) - Path:
/admin - Tenancy: disabled (no
->tenant(...)) - Registered artifacts: tenant management resources/pages, monitoring pages.
Tenant panel (Operate)
- ID:
tenant(new) - Path:
/admin/t - Tenancy: enabled via
Tenant::classwithslugAttribute: 'external_id' - Tenant route prefix: blank/
nullso tenant routes become/admin/t/{tenant}/... - Registered artifacts: operational resources/pages only (inventory, drift, backups, policies, directory, etc.).
- Route-shape verification is mandatory: automated regression checks must assert canonical tenant URLs are
/admin/t/{tenant}and/admin/t/{tenant}/...(never/admin/t/t/{tenant}).
Laravel 11+ provider registration requirement:
- Register the new tenant panel provider in
/Users/ahmeddarrazi/Documents/projects/TenantAtlas/bootstrap/providers.php.
Routing/Removal Mechanism
Tenant-scoped management routes return 404 by construction:
- Management resources/pages are not registered in the tenant panel.
- No redirects (dev-stage).
Authorization Design
- Workspace management pages: require selected workspace + membership; non-member → 404.
- Tenant operational routes: require workspace membership + tenant entitlement; non-entitled → 404.
- Mutations: capability missing → 403 (server-side policy/gate); destructive-like actions require
->requiresConfirmation().
Global Search Design
- Workspace panel: managed tenants are searchable (ensure resource has Edit/View page).
- Tenant panel: tenant-management entities are not registered, so they cannot appear in global search.
Phase 2 — Implementation Plan (Code + Tests)
Stop condition for /speckit.plan: this section outlines implementation, but actual task breakdown happens in /speckit.tasks.
Planned steps:
- Add new panel provider for tenant operations (e.g.,
App\Providers\Filament\TenantPanelProvider). - Register provider in
bootstrap/providers.php(Laravel 11+ pattern). - Refactor
AdminPanelProviderinto a tenantless workspace panel:
- remove tenancy configuration (
->tenant(...), tenant menu, tenant route prefix) - remove tenant-only middleware from the workspace panel pipeline
- Move/register management pages/resources into workspace panel:
TenantResource(managed tenants CRUD / manage view)ProviderConnectionResource(workspace-managed connections by tenant)- required permissions viewer page
- membership management surfaces
- onboarding/activation surfaces
- Move/register operational pages/resources into the tenant panel.
- Rewire internal links/CTAs that currently build tenant-scoped management URLs to the new workspace-managed canonical URLs.
- Add regression tests (Pest) to cover:
- workspace member can access
/admin/tenants* - non-member gets 404
- tenant entitlement required for
/admin/t/{tenant}/... - canonical tenant panel route shape is
/admin/t/{tenant}/...(no duplicated/t) - tenant-scoped management routes are missing (404)
- link rewiring expectations (where feasible)
- Run targeted test pack and Pint:
vendor/bin/sail artisan test --compact tests/Feature/...vendor/bin/sail bin pint --dirty