--- description: "Task list for Spec 085 — Tenant Operate Hub / Tenant Overview IA" --- # Tasks: Spec 085 — Tenant Operate Hub / Tenant Overview IA **Input**: Design documents from `/specs/085-tenant-operate-hub/` **Required**: - `specs/085-tenant-operate-hub/plan.md` - `specs/085-tenant-operate-hub/spec.md` **Additional docs present**: - `specs/085-tenant-operate-hub/research.md` - `specs/085-tenant-operate-hub/data-model.md` - `specs/085-tenant-operate-hub/contracts/openapi.yaml` - `specs/085-tenant-operate-hub/quickstart.md` **Tests**: REQUIRED (runtime UX + security semantics; Pest) --- ## Phase 1: Setup (Shared Infrastructure) **Purpose**: Confirm the existing code touchpoints and test harness for Spec 085. - [X] T001 Confirm canonical Monitoring routes + existing clear-context endpoint in routes/web.php and app/Http/Controllers/ClearTenantContextController.php - [X] T002 Confirm the Monitoring pages exist and are canonical: app/Filament/Pages/Monitoring/Operations.php, app/Filament/Pages/Operations/TenantlessOperationRunViewer.php, app/Filament/Pages/Monitoring/Alerts.php, app/Filament/Pages/Monitoring/AuditLog.php - [X] T003 Confirm Tenant panel provider is the entry point for tenant sidebar Monitoring shortcuts in app/Providers/Filament/TenantPanelProvider.php - [X] T004 Confirm Laravel 11+/12 panel provider registration is in bootstrap/providers.php (not bootstrap/app.php) - [X] T005 [P] Identify existing monitoring/tenant scoping tests to extend (tests/Feature/Monitoring/OperationsTenantScopeTest.php, tests/Feature/Operations/TenantlessOperationRunViewerTest.php) --- ## Phase 2: Foundational (Blocking Prerequisites) **Purpose**: Shared helper behavior must match Spec 085 semantics before story work. - [X] T006 Update scope-label copy and semantics in app/Support/OperateHub/OperateHubShell.php (MUST match FR-085-002 exactly: "Scope: Workspace — all tenants" / "Scope: Tenant — ") - [X] T007 Ensure OperateHubShell resolves active entitled tenant context safely (Filament tenant when present, otherwise remembered last-tenant id for the current workspace) - [X] T008 Update OperateHubShell return affordance label to include tenant name ("Back to ") in app/Support/OperateHub/OperateHubShell.php - [X] T009 Add a helper method to resolve “active tenant AND still entitled” in app/Support/OperateHub/OperateHubShell.php (used by Operations index + run detail to implement stale-tenant-context behavior) - [X] T010 Ensure Monitoring renders remain DB-only (no outbound calls / no side effects) by standardizing test guards with Http::preventStrayRequests() in tests/Feature/Spec085/*.php and existing coverage tests/Feature/Monitoring/OperationsTenantScopeTest.php and tests/Feature/Operations/TenantlessOperationRunViewerTest.php **Checkpoint**: Shared semantics locked; user story work can begin. --- ## Phase 3: User Story 1 — Monitoring feels context-aware (Priority: P1) 🎯 MVP **Goal**: When tenant context is active, Monitoring clearly shows tenant scope + deterministic “Back to tenant” and offers explicit “Show all tenants” to exit. **Independent Test**: With tenant context active + entitled, GET `/admin/operations` shows `Scope: Tenant — ` and buttons `Back to ` and `Show all tenants`; clicking “Show all tenants” clears tenant context and returns to workspace-wide operations. ### Tests for User Story 1 (write first) - [X] T011 [P] [US1] Add Spec 085 operations header tests in tests/Feature/Spec085/OperationsIndexHeaderTest.php (tenant scope label + both CTAs) - [X] T012 [P] [US1] Add stale-tenant-context test in tests/Feature/Spec085/OperationsIndexHeaderTest.php (tenant context set but user not entitled → workspace scope + no tenant name + no back-to-tenant) - [X] T013 [P] [US1] Add explicit-exit behavior test in tests/Feature/Spec085/OperationsIndexHeaderTest.php (POST /admin/clear-tenant-context clears Filament tenant + last tenant id) - [X] T014 [P] [US1] Add tenant navigation shortcuts test in tests/Feature/Spec085/TenantNavigationMonitoringShortcutsTest.php (tenant sidebar shows “Monitoring” group with Runs/Alerts/Audit Log) - [X] T015 [P] [US1] Add “deny-as-not-found” regression tests for canonical Monitoring access in tests/Feature/Spec085/DenyAsNotFoundSemanticsTest.php (non-workspace-member → 404 for /admin/operations and /admin/operations/{run}) - [X] T016 [P] [US1] Add “deny-as-not-found” regression test for tenant dashboard direct access in tests/Feature/Spec085/DenyAsNotFoundSemanticsTest.php (non-entitled to tenant → 404 for /admin/t/{tenant}) ### Implementation for User Story 1 - [X] T017 [US1] Replace Tenant sidebar "Operations" item with "Monitoring" group shortcuts in app/Providers/Filament/TenantPanelProvider.php (Runs→/admin/operations, Alerts→/admin/alerts, Audit Log→/admin/audit-log) - [X] T018 [US1] Implement Operations index scope indicator per Spec 085 in app/Filament/Pages/Monitoring/Operations.php (workspace vs tenant; stale context treated as workspace) - [X] T019 [US1] Implement Operations index CTAs per Spec 085 in app/Filament/Pages/Monitoring/Operations.php (Back to using App\Filament\Pages\TenantDashboard::getUrl(panel: 'tenant', tenant: $tenant); Show all tenants exits tenant context) - [X] T020 [US1] Ensure “Show all tenants” uses an explicit server-side action (no implicit GET mutation) in app/Filament/Pages/Monitoring/Operations.php (perform the same mutations as app/Http/Controllers/ClearTenantContextController.php: Filament::setTenant(null, true) + WorkspaceContext::clearLastTenantId(); then redirect to /admin/operations) **Checkpoint**: US1 fully testable and meets FR-085-001/002/005/007/010. --- ## Phase 4: User Story 2 — Canonical URLs with explicit scope (Priority: P2) **Goal**: Canonical Monitoring URLs never implicitly change tenant context; tenant context may only affect default filtering and must be obvious. **Independent Test**: With tenant context active, GET `/admin/operations` does not change tenant context and defaults the list to the active tenant (or otherwise clearly shows it’s tenant-scoped by default). ### Tests for User Story 2 - [X] T021 [P] [US2] Add non-mutation test in tests/Feature/Spec085/CanonicalMonitoringDoesNotMutateTenantContextTest.php (GET /admin/operations does not set/clear tenant context) - [X] T022 [P] [US2] Add scope label test in tests/Feature/Spec085/CanonicalMonitoringDoesNotMutateTenantContextTest.php (no tenant context → "Scope: Workspace — all tenants") - [X] T023 [P] [US2] Add default-tenant-filter test in tests/Feature/Monitoring/OperationsTenantScopeTest.php (tenant context active → list defaults to active tenant) ### Implementation for User Story 2 - [X] T024 [US2] Ensure Operations index query applies workspace scoping and (when tenant context is active + entitled) tenant scoping without mutating tenant context in app/Filament/Pages/Monitoring/Operations.php - [X] T025 [US2] Ensure any default tenant filter is applied as a query/filter default only (no calls to Filament::setTenant() during GET) in app/Filament/Pages/Monitoring/Operations.php **Checkpoint**: US2 meets FR-085-003/004/009. --- ## Phase 5: User Story 3 — Deep links are safe and recoverable (Priority: P3) **Goal**: On `/admin/operations/{run}`, tenant-context users get a deterministic “Back to ” plus a secondary “Show all operations”; otherwise only “Back to Operations”. **Independent Test**: With tenant context active + entitled, GET `/admin/operations/{run}` shows `← Back to ` and `Show all operations`; without tenant context it shows `Back to Operations` only. ### Tests for User Story 3 - [X] T026 [P] [US3] Add run detail header-action tests in tests/Feature/Spec085/RunDetailBackAffordanceTest.php (tenant context vs no context) - [X] T027 [P] [US3] Add stale-tenant-context run detail test in tests/Feature/Spec085/RunDetailBackAffordanceTest.php (tenant context set but not entitled → no tenant name, no back-to-tenant) ### Implementation for User Story 3 - [X] T028 [US3] Implement deterministic back affordances for run detail in app/Filament/Pages/Operations/TenantlessOperationRunViewer.php (tenant-context+entitled → “← Back to ” + “Show all operations”; else “Back to Operations”) - [X] T029 [US3] Ensure run detail never reveals tenant identity when the viewer is not entitled (stale tenant context treated as workspace-wide) in app/Filament/Pages/Operations/TenantlessOperationRunViewer.php **Checkpoint**: US3 meets FR-085-006/008/010. --- ## Phase 6: Polish & Cross-Cutting Concerns - [X] T030 [P] Confirm Spec 085 UI Action Matrix matches implemented header actions in specs/085-tenant-operate-hub/spec.md - [X] T031 [P] Validate manual verification steps in specs/085-tenant-operate-hub/quickstart.md against actual behavior (update doc only if it drifted) - [X] T037 Ensure “Show all tenants” clears Operations table tenant filter state (prevents stale Livewire table filter state from keeping the list scoped) - [X] T032 Run formatting on changed files under app/ and tests/ using vendor/bin/sail bin pint --dirty - [X] T033 Run focused test suite: vendor/bin/sail artisan test --compact tests/Feature/Spec085 tests/Feature/Monitoring/OperationsTenantScopeTest.php tests/Feature/Operations/TenantlessOperationRunViewerTest.php - [X] T034 Fix Filament auth-pattern guard compliance by removing Gate:: usage in app/Filament/Pages/Operations/TenantlessOperationRunViewer.php (use $this->authorize(...)) - [X] T035 Ensure canonical Operate Hub routes sanitize stale/non-entitled tenant context by applying ensure-filament-tenant-selected middleware to /admin/operations, /admin/alerts, /admin/audit-log, and /admin/operations/{run} - [X] T036 Harden Spec 085-related tests to match final copy/semantics and avoid brittle Livewire DOM assertions (tests/Feature/OpsUx/OperateHubShellTest.php, tests/Feature/Monitoring/OperationsCanonicalUrlsTest.php) --- ## Dependencies & Execution Order ### Dependency Graph ```mermaid graph TD P1[Phase 1: Setup] --> P2[Phase 2: Foundational] P2 --> US1[US1 (P1): Context-aware Monitoring entry] US1 --> US2[US2 (P2): Canonical URLs + explicit scope] US1 --> US3[US3 (P3): Deep-link back affordances] US2 --> P6[Phase 6: Polish] US3 --> P6 ``` ### User Story Dependencies - US1 is the MVP. - US2 and US3 depend on the shared foundational semantics (scope labels + entitled active tenant resolution). --- ## Parallel Execution Examples ### US1 ```text In parallel: - T011 (tests) in tests/Feature/Spec085/OperationsIndexHeaderTest.php - T017 (tenant nav shortcuts) in app/Providers/Filament/TenantPanelProvider.php Then: - T018–T020 in app/Filament/Pages/Monitoring/Operations.php ``` ### US2 ```text In parallel: - T021–T022 (non-mutation + scope label tests) - T023 (default tenant filter test) in tests/Feature/Monitoring/OperationsTenantScopeTest.php Then: - T024–T025 in app/Filament/Pages/Monitoring/Operations.php ``` ### US3 ```text In parallel: - T026–T027 (run detail tests) in tests/Feature/Spec085/RunDetailBackAffordanceTest.php Then: - T028–T029 in app/Filament/Pages/Operations/TenantlessOperationRunViewer.php ``` --- ## Implementation Strategy ### MVP Scope - Implement US1 only (T011–T020), run T033, then manually validate via specs/085-tenant-operate-hub/quickstart.md. ### Incremental Delivery - US1 → US2 → US3, keeping each story independently testable.