TenantAtlas/specs/083-required-permissions-hardening/data-model.md
ahmido 55166cf9b8 Spec 083: Required permissions hardening (canonical /admin/tenants, DB-only, 404 semantics) (#101)
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
2026-02-08 23:13:25 +00:00

1.6 KiB

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.