Implements Spec 083 (Canonical Required Permissions manage surface hardening + issues-first UX).
Highlights:
- Enforces canonical route: /admin/tenants/{tenant}/required-permissions
- Legacy tenant-plane URL /admin/t/{tenant}/required-permissions stays non-existent (404)
- Deny-as-not-found (404) for non-workspace members and non-tenant-entitled users
- Strict tenant resolution (no cross-plane fallback)
- DB-only render (no external provider calls on page load)
- Issues-first layout + canonical next-step links (re-run verification -> /admin/onboarding)
- Freshness/stale detection (missing or >30 days -> warning)
Tests (Sail):
- vendor/bin/sail artisan test --compact tests/Feature/RequiredPermissions
- vendor/bin/sail artisan test --compact tests/Unit/TenantRequiredPermissionsFreshnessTest.php tests/Unit/TenantRequiredPermissionsOverallStatusTest.php
Notes:
- Filament v5 / Livewire v4 compliant.
- No destructive actions added in this spec; link-only CTAs.
Co-authored-by: Ahmed Darrazi <ahmeddarrazi@MacBookPro.fritz.box>
Reviewed-on: #101
41 lines
1.6 KiB
Markdown
41 lines
1.6 KiB
Markdown
# Data Model — Spec 083
|
|
|
|
This feature is primarily **read-only UX + authorization hardening**. No new tables are required.
|
|
|
|
## Existing entities (relevant)
|
|
|
|
### Workspace
|
|
- **Purpose**: Isolation boundary for tenant management surfaces.
|
|
- **Key fields**: `id`.
|
|
|
|
### WorkspaceMembership
|
|
- **Purpose**: Establishes user membership in a workspace.
|
|
- **Key fields**: `workspace_id`, `user_id`, `role`.
|
|
|
|
### Tenant
|
|
- **Purpose**: Managed Entra tenant (scoped to a workspace).
|
|
- **Key fields**: `id`, `external_id` (Entra tenant GUID), `workspace_id`, `status`, `name`.
|
|
|
|
### TenantMembership
|
|
- **Purpose**: Tenant entitlement (read-only access at minimum).
|
|
- **Key fields**: `tenant_id`, `user_id`, `role`, `source`, `source_ref`.
|
|
|
|
### TenantPermission
|
|
- **Purpose**: Stored permission inventory used by Required Permissions page.
|
|
- **Key fields**: `tenant_id`, `permission_key`, `status` (`granted|missing|error`), `details` (JSON), `last_checked_at`.
|
|
|
|
## Derived / computed values
|
|
|
|
### "Last refreshed"
|
|
- **Definition**: `max(tenant_permissions.last_checked_at)` for the tenant.
|
|
- **Stale rule** (Spec 083): stale if missing OR older than 30 days.
|
|
|
|
### Summary overall status
|
|
Derived from stored permission rows (and freshness):
|
|
- **Blocked**: any missing `application` permission.
|
|
- **Needs attention**: any warning exists (missing delegated OR error rows folded into warning OR stale freshness).
|
|
- **Ready**: no blockers, no warnings.
|
|
|
|
## State transitions
|
|
- None introduced here (page remains read-only). Mutations happen on other surfaces (verification start, provider connection management) and must enforce capability checks there.
|