TenantAtlas/specs/129-workspace-admin-home/data-model.md
ahmido 0c709df54e Spec 129: add workspace admin home overview (#157)
## Summary
- make `/admin` the canonical workspace-level home instead of implicitly forcing tenant context
- add a new Filament workspace overview page with bounded workspace-safe widgets, quick actions, and empty states
- align panel routing, middleware, redirect helpers, and tests with the new workspace-home semantics
- add Spec 129 design artifacts, contracts, and focused Pest coverage for landing, navigation, content, operations, and authorization

## Validation
- `vendor/bin/sail artisan test --compact tests/Feature/Filament/AdminHomeRedirectsToChooseTenantWhenWorkspaceSelectedTest.php tests/Feature/Filament/LoginRedirectsToChooseWorkspaceWhenMultipleWorkspacesTest.php tests/Feature/Filament/WorkspaceOverviewLandingTest.php tests/Feature/Filament/WorkspaceOverviewNavigationTest.php tests/Feature/Filament/WorkspaceOverviewContentTest.php tests/Feature/Filament/WorkspaceOverviewEmptyStatesTest.php tests/Feature/Filament/WorkspaceOverviewOperationsTest.php tests/Feature/Filament/WorkspaceOverviewAuthorizationTest.php tests/Feature/Filament/WorkspaceOverviewPermissionVisibilityTest.php tests/Feature/Filament/ChooseTenantRequiresWorkspaceTest.php tests/Feature/Guards/AdminWorkspaceRoutesGuardTest.php`
- `vendor/bin/sail bin pint --dirty --format agent`

## Notes
- Livewire v4.0+ compliance is preserved through Filament v5 usage.
- Panel provider registration remains in `bootstrap/providers.php` for Laravel 12.
- This feature adds a workspace overview page for the admin panel home; it does not introduce destructive actions.
- No new Filament assets were added, so there is no additional `filament:assets` deployment requirement for this branch.
- Manual browser QA for the quickstart scenarios was not completed in this session because the local browser opened at the Microsoft login flow without an authenticated test session.

Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #157
2026-03-09 21:53:25 +00:00

203 lines
7.7 KiB
Markdown

# Data Model: Workspace Home & Admin Landing
**Feature**: 129-workspace-admin-home | **Date**: 2026-03-09
## Overview
This feature introduces no new database tables. It adds a new workspace-level read model and UI composition layer over existing workspace-owned and tenant-owned records.
The design relies on existing persisted entities plus a few computed overview concepts:
1. a canonical workspace overview page,
2. capability-safe summary metrics,
3. bounded recent and needs-attention entries,
4. quick actions to existing canonical destinations.
## Existing Persistent Entities
### Workspace
| Attribute | Type | Notes |
|-----------|------|-------|
| `id` | int | Primary workspace identity |
| `name` | string | Primary visible workspace label on the overview |
| `slug` | string nullable | Used in some workspace routes |
| `archived_at` | timestamp nullable | Archived workspaces must not be selectable |
**Relationships**:
- has many `WorkspaceMembership`
- has many `Tenant`
**Validation / usage rules**:
- A workspace overview may render only when the workspace is currently selected and the actor remains a valid member.
- Archived or stale workspace context must resolve back through the chooser flow.
### WorkspaceMembership
| Attribute | Type | Notes |
|-----------|------|-------|
| `workspace_id` | int | Workspace isolation boundary |
| `user_id` | int | Actor membership |
| `role` | string | Drives capability resolution |
**Usage rules**:
- Non-members must receive 404 deny-as-not-found for workspace home access.
- Role and capability checks determine which overview surfaces and quick actions may appear.
### Tenant
| Attribute | Type | Notes |
|-----------|------|-------|
| `id` | int | Internal identity |
| `external_id` | string | Route key for tenant destinations |
| `workspace_id` | int | Tenant belongs to exactly one workspace |
| `name` | string | Used on chooser and downstream destinations |
| `status` | string | Only active, accessible tenants count toward overview metrics |
**Usage rules**:
- The workspace overview never requires a selected tenant.
- Tenant counts and tenant-linked actions must reflect only the current user's accessible tenant subset within the active workspace.
### OperationRun
| Attribute | Type | Notes |
|-----------|------|-------|
| `workspace_id` | int | Workspace-bound operational scope |
| `tenant_id` | int nullable | Nullable for some workspace-context monitoring cases |
| `status` | string | Used for active/recent operations summaries |
| `outcome` | string nullable | Used for needs-attention or recent-failure signals |
| `created_at` / `updated_at` | timestamps | Used for recency ordering |
**Usage rules**:
- The overview may show only a bounded, capability-safe subset of operation runs.
- The workspace home must not create, mutate, or transition `OperationRun` records.
### Alert / Finding Surfaces
| Concept | Notes |
|--------|-------|
| Alerts | May contribute an alert summary count or urgent list items if a safe workspace-scoped aggregate exists |
| Findings | May contribute one needs-attention metric or list entries if already available safely and cheaply |
**Usage rules**:
- The overview must not leak existence of unauthorized alerts or findings through counts or list rows.
- These surfaces are optional at render time: if safe aggregation is unavailable, they should be hidden or degrade to empty state.
## New Computed Read Models
### WorkspaceOverviewSurface
| Field | Type | Description |
|------|------|-------------|
| `workspace` | Workspace | Active workspace context shown on the page |
| `tenant_context_active` | bool | Informational only; must not change page scope |
| `summary_metrics` | list<WorkspaceSummaryMetric> | Small KPI set shown at top of page |
| `attention_items` | list<WorkspaceAttentionItem> | Bounded urgent items |
| `recent_operations` | list<WorkspaceRecentOperationItem> | Bounded latest relevant operations |
| `quick_actions` | list<WorkspaceQuickAction> | Existing canonical destinations permitted for the actor |
**Rules**:
- Must render without a selected tenant.
- Must not imply tenant context when `tenant_context_active` is false.
- Must remain complete even when most sub-surfaces are empty.
### WorkspaceSummaryMetric
| Field | Type | Description |
|------|------|-------------|
| `key` | string enum | `accessible_tenants`, `active_operations`, `alerts`, `needs_attention` |
| `label` | string | UI label |
| `value` | int | Capability-safe aggregate value |
| `destination_url` | string nullable | Canonical existing route when drill-down is allowed |
| `visible` | bool | Hidden when aggregate is not safe or not authorized |
**Rules**:
- Value must be cheap to compute and workspace-bounded.
- No metric may reveal unauthorized tenant-owned data.
### WorkspaceAttentionItem
| Field | Type | Description |
|------|------|-------------|
| `kind` | string enum | `failed_operation`, `high_alert`, `high_finding`, or equivalent supported type |
| `title` | string | Human-readable urgent label |
| `subtitle` | string nullable | Cheap contextual metadata |
| `severity` | string nullable | Rendered through existing badge semantics where applicable |
| `destination_url` | string | Canonical route |
| `occurred_at` | datetime | Ordering field |
**Rules**:
- Results must be bounded and ordered by recency or severity.
- Empty state is valid and must render intentionally.
### WorkspaceRecentOperationItem
| Field | Type | Description |
|------|------|-------------|
| `operation_run_id` | int | Canonical run identity |
| `title` | string | Operation label |
| `status` | string | Existing operation status |
| `outcome` | string nullable | Existing outcome label |
| `tenant_label` | string nullable | Optional, only when safe to show |
| `destination_url` | string | Canonical run detail or operations destination |
| `created_at` | datetime | Recency ordering |
**Rules**:
- Must not spoof tenant context if no tenant is selected.
- Result set must be capped.
### WorkspaceQuickAction
| Field | Type | Description |
|------|------|-------------|
| `key` | string enum | `choose_tenant`, `operations`, `alerts`, `switch_workspace`, `manage_workspaces` |
| `label` | string | Visible CTA text |
| `url` | string | Canonical existing destination |
| `visible` | bool | Capability-aware rendering flag |
| `kind` | string enum | `context`, `navigation`, `administration` |
**Rules**:
- `switch_workspace` and `manage_workspaces` must remain separate entries.
- No quick action may introduce a new workflow in this feature.
## State and Transition Notes
### Workspace access state
```text
No selected workspace
-> redirect to choose-workspace
Selected workspace + valid membership
-> render workspace overview at /admin
Selected workspace + stale membership
-> if the actor still has at least one valid workspace membership, clear stale session and redirect to choose-workspace
-> if the actor is no longer entitled to the active workspace scope, return 404 deny-as-not-found
```
### Tenant context behavior
```text
Selected workspace + no selected tenant
-> render workspace overview normally
Selected workspace + selected tenant
-> still render workspace overview at /admin
-> tenant-specific work remains explicit through choose-tenant or /admin/t/{tenant}
```
## Validation Rules
| Rule | Result |
|------|--------|
| `/admin` means workspace home, not tenant branching | Required |
| Workspace home must render without tenant context | Required |
| Non-members receive 404 semantics | Required |
| In-scope unauthorized actions or destinations remain hidden or 403 at target | Required |
| Overview metrics and lists are capability-safe and bounded | Required |
| Empty states remain intentional and complete | Required |
## Schema Impact
No schema migration is expected for this feature.