# Research — Workspace-first Navigation & Monitoring Hub (077)

**Date**: 2026-02-06  
**Branch**: 077-workspace-nav-monitoring-hub  
**Spec**: [specs/077-workspace-nav-monitoring-hub/spec.md](spec.md)

## Repo Reality Check (what exists today)

- Admin panel exists at `/admin` via [app/Providers/Filament/AdminPanelProvider.php](../../app/Providers/Filament/AdminPanelProvider.php).
- System panel exists at `/system` with a separate auth guard (`platform`) via [app/Providers/Filament/SystemPanelProvider.php](../../app/Providers/Filament/SystemPanelProvider.php).
- Workspace context selection exists:
  - Page `/admin/choose-workspace` via [app/Filament/Pages/ChooseWorkspace.php](../../app/Filament/Pages/ChooseWorkspace.php)
  - POST switch endpoint `/admin/switch-workspace` via [routes/web.php](../../routes/web.php)
  - Workspace switcher UI in the user menu via [resources/views/filament/partials/workspace-switcher.blade.php](../../resources/views/filament/partials/workspace-switcher.blade.php)
- Navigation ambiguity is currently real:
  - When no tenant is selected, navigation is replaced with a single item labeled **"Workspaces"** linking to the choose-workspace page via [app/Support/Middleware/EnsureFilamentTenantSelected.php](../../app/Support/Middleware/EnsureFilamentTenantSelected.php).
  - Separately, the sidebar includes another **"Workspaces"** item linking to `/admin/workspaces` (workspace CRUD) via [app/Providers/Filament/AdminPanelProvider.php](../../app/Providers/Filament/AdminPanelProvider.php).
- Operations is already canonical and tenantless:
  - Resource slug is `/admin/operations` via [app/Filament/Resources/OperationRunResource.php](../../app/Filament/Resources/OperationRunResource.php).
  - Detail page is `/admin/operations/{record}`.

## Decisions (resolved)

### D1 — Manage workspaces stays on `/admin/workspaces` and follows workspace RBAC semantics (404 for non-members, 403 for missing capability)

- Decision: Treat `/admin/workspaces` as a **workspace-scoped** management surface in the tenant plane (`/admin`, Entra users):
  - Non-members (or out-of-scope workspace records) → **404** (deny-as-not-found)
  - Members missing required capabilities for protected actions/screens → **403**
- Rationale: Aligns with the constitution RBAC-UX model (membership is the isolation boundary; capability denial is 403 after membership is established) while still preventing cross-workspace leakage.
- Alternatives considered:
  - Move management into `/system` panel: rejected because this feature targets the tenant plane IA. (If workspace CRUD becomes platform-admin only later, that should be handled as a separate migration spec.)

### D2 — Tenant context influences Operations via server-side default filter state, not querystring

- Decision: Apply the tenant default filter server-side while keeping the canonical URL `/admin/operations` unchanged.
- Rationale: Matches Spec 077 clarification (Q2=A). Prevents link-sharing surprises and keeps canonical monitoring routes stable.
- Alternatives considered:
  - Querystring-based default filtering (e.g. `?tenant_id=`): rejected as it makes filtered URLs the de-facto navigation target.

### D3 — Missing workspace context redirects to `/admin/choose-workspace` and returns to the requested URL

- Decision: When a workspace-scoped page is visited without an active workspace selection, redirect to `/admin/choose-workspace` and then return.
- Rationale: Matches Spec 077 clarification (Q3=A) and aligns with existing `/admin` root override behavior in [routes/web.php](../../routes/web.php).

### D4 — Invalid tenant context (tenant not in current workspace) is auto-cleared

- Decision: If tenant context is active but does not belong to the current workspace, clear tenant context and continue on workspace-level pages.
- Rationale: Matches Spec 077 clarification (Q4=A). Reduces “ghost tenant” behavior after a workspace switch.
- Alternatives considered:
  - Hard 404: rejected as too confusing during normal context switching.

## Key Implementation Implications (for planning)

- **Rename navigation labels** to satisfy “one label, one meaning”:
  - The “Workspaces” navigation item that points to the choose-workspace page must become **"Switch workspace"**.
  - The “Workspaces” navigation item that points to CRUD must become **"Manage workspaces"** and be capability-gated with workspace RBAC semantics (404 for non-members; 403 for missing capability).
- **Operations filter chip/removal**: current behavior filters by `Tenant::current()` inside `OperationRunResource::getEloquentQuery()`, which is not user-removable. The plan should move this behavior into a table filter with default state.
- **No render-time external calls**: monitoring pages must remain DB-only at render (already consistent with constitution).
