Implements specs 070–072 (workspace foundation, workspace-scoped tenant selection, managed-tenants workspace enforcement).
Highlights
- Adds Workspace + WorkspaceMembership models/migrations + middleware to persist/enforce current workspace context.
- Scopes tenant selection to the current workspace.
- Makes legacy `/admin/managed-tenants*` routes redirect into workspace-scoped URLs.
- Enforces tenant routes under `/admin/t/{tenant}` to 404 when workspace context is missing or mismatched.
- Fixes Filament page Blade wrappers so header actions render on choose-workspace / choose-tenant / no-access pages.
Verification
- Pint: `vendor/bin/sail bin pint --dirty`
- Tests: `vendor/bin/sail artisan test --compact tests/Feature/Guards/NoAdHocFilamentAuthPatternsTest.php tests/Feature/Workspaces tests/Feature/Filament/ChooseTenantIsWorkspaceScopedTest.php tests/Feature/Filament/ChooseTenantRequiresWorkspaceTest.php tests/Feature/Filament/TenantSwitcherUrlResolvesTenantTest.php tests/Feature/ManagedTenants tests/Feature/AdminNewRedirectTest.php`
Notes
- Filament v5 / Livewire v4 compatible.
- Panel provider registration stays in `bootstrap/providers.php` (Laravel 11+ rule).
- No new heavy frontend assets added.
Co-authored-by: Ahmed Darrazi <ahmeddarrazi@MacBookPro.fritz.box>
Reviewed-on: #85
35 lines
2.0 KiB
Markdown
35 lines
2.0 KiB
Markdown
# Spec — 072 Managed Tenants workspace context enforcement
|
|
|
|
## Problem
|
|
Managed Tenant pages exist in an unscoped URL space (`/admin/managed-tenants/*`) while Managed Tenants are product-scoped to a Workspace (MSP portfolio). This makes workspace context feel optional and allows confusing / insecure navigation patterns where tenant context and workspace context can drift.
|
|
|
|
## Mental model (source of truth)
|
|
- **Managed Tenant** = the Entra/Intune tenant. All policy/backup/drift/inventory features are always scoped to a Managed Tenant.
|
|
- In code: Filament tenancy (`/admin/t/{tenant_external_id}/...`).
|
|
- **Workspace** = portfolio container. Controls which Managed Tenants a user can see + portfolio-level settings.
|
|
- In code: session + `last_workspace_id` + middleware (not Filament tenancy).
|
|
|
|
## Goals
|
|
- Workspace becomes a real, enforced context for all tenant-scoped pages.
|
|
- Keep Filament tenancy URL space unchanged: `/admin/t/{tenant_external_id}/...`.
|
|
- Introduce / use a workspace-scoped landing space for portfolio UX: `/admin/w/{workspace}/...`.
|
|
- Eliminate or redirect legacy unscoped Managed Tenants routes under `/admin/managed-tenants/*`.
|
|
|
|
## Non-goals
|
|
- Redesigning all navigation IA or introducing a second Filament panel.
|
|
- Migrating existing tenant data beyond enforcing `tenants.workspace_id` consistency.
|
|
|
|
## Hard rule (security / enterprise)
|
|
When accessing `/admin/t/{tenant}` routes:
|
|
- `current_workspace_id` must be set, and
|
|
- `tenant.workspace_id == current_workspace_id`, and
|
|
- user must be a member of the workspace (and/or tenant, per current auth model).
|
|
Otherwise: **deny as not found** (404).
|
|
|
|
## Acceptance criteria
|
|
- `/admin/managed-tenants/*` does not act as a primary UX entry point anymore (redirects to workspace-scoped UX).
|
|
- `/admin/w/{workspace}/managed-tenants` exists as the primary portfolio landing for Managed Tenants.
|
|
- Tenant switcher only shows tenants from the current workspace.
|
|
- Visiting `/admin/t/{tenant}` with missing or mismatched workspace context results in 404.
|
|
- Pest tests cover redirects + workspace/tenant mismatch denial.
|