
---
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 — <tenant name>")
- [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 <tenant name>") 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 — <tenant>` and buttons `Back to <tenant>` 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 <tenant> 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 <tenant>” 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 <tenant>` 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 <tenant>” + “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.
