# Feature Specification: Workspace-first Navigation & Monitoring Hub

**Feature Branch**: `077-workspace-nav-monitoring-hub`  
**Created**: 2026-02-06  
**Status**: Implemented  
**Input**: User description: "Workspace-first navigation and monitoring hub for an enterprise admin suite: remove workspace navigation ambiguity, lock canonical operations deep links, apply tenant context only as default filters, and enforce strict 404/403 access semantics without information leakage."

## Clarifications

### Session 2026-02-06

- Q: What is the authorization plane + status-code rule for `/admin/workspaces` ("Manage workspaces")? → A: Tenant plane (`/admin`, Entra users). `/admin/workspaces` is **Global Mode** (workspace-optional). Index lists only the user’s workspaces; per-record access for non-members is 404 (deny-as-not-found); protected actions/screens return 403 when unauthorized.
- Q: Should `/admin/workspaces` require an active `current_workspace_id`? → A: No. `/admin/workspaces` is **Global Mode** (workspace-optional). The index lists only workspaces the user is a member of; per-record access for non-members remains 404.
- Q: How should the tenant-context default filter on `/admin/operations` be implemented? → A: Server-side default state with a removable filter chip; URL remains `/admin/operations`.
- Q: What happens when a user visits a workspace-scoped page (e.g. `/admin/operations`) with no `current_workspace_id` selected? → A: Redirect to `/admin/choose-workspace` and return to the originally requested URL after selection.
- Q: If tenant context is active but the tenant is not in the current workspace (e.g., user switches workspaces), what should happen? → A: Auto-clear tenant context and continue on tenantless workspace pages.

## User Scenarios & Testing *(mandatory)*

### User Story 1 - Switch workspace without ambiguity (Priority: P1)

As an operator/admin, I need to switch my active workspace (portfolio) using a clear, single-purpose entry point, so that I never confuse "switch workspace" with "manage workspaces".

**Why this priority**: Workspace context is foundational. If it’s confusing, every other module becomes harder to use and support.

**Independent Test**: A user can find "Switch workspace", select a workspace they are a member of, and the application context updates while workspace management remains separate.

**Acceptance Scenarios**:

1. **Given** I am signed in and belong to multiple workspaces, **When** I choose "Switch workspace", **Then** I see only workspaces I am a member of and can select one.
2. **Given** I can manage workspaces, **When** I open "Manage workspaces", **Then** I can access workspace CRUD screens and breadcrumbs stay within the management area.
3. **Given** I cannot manage workspaces, **When** I look at navigation, **Then** I do not see "Manage workspaces".

---

### User Story 2 - Use Monitoring hub from canonical links (Priority: P2)

As an operator, I need monitoring pages (starting with Operations) to be reachable via stable, shareable links that never depend on tenant context, so that support, alerts, and notifications can deep-link reliably.

**Why this priority**: Monitoring must be dependable across contexts; deep links are critical for incident response and support.

**Independent Test**: Visiting the canonical operations URLs works with and without tenant context, and the system enforces membership checks.

**Acceptance Scenarios**:

1. **Given** I am a member of a workspace, **When** I visit `/admin/operations`, **Then** I can view a workspace-wide list of operations.
2. **Given** I have an active tenant context, **When** I visit `/admin/operations`, **Then** operations are pre-filtered to that tenant but the URL remains `/admin/operations`.
3. **Given** I have a run link `/admin/operations/{run}`, **When** I open it, **Then** I see the run detail regardless of tenant context.

---

### User Story 3 - Navigate and search without leaking inaccessible data (Priority: P3)

As a user, I should never learn about workspaces/tenants/runs I cannot access through navigation labels, breadcrumbs, counts, or global search results.

**Why this priority**: Preventing information leakage is a core enterprise requirement and reduces risk in multi-tenant MSP environments.

**Independent Test**: An unauthorized user receives not-found responses for out-of-scope resources and does not see them in search.

**Acceptance Scenarios**:

1. **Given** I am not a member of a workspace, **When** I attempt to access that workspace’s monitoring data or runs, **Then** I receive a not-found response.
2. **Given** I am a workspace member but lack a capability for a protected workspace-scoped screen or action, **When** I attempt to access it directly, **Then** I receive a forbidden response.
3. **Given** I use global search, **When** I search for entities outside my scope, **Then** they do not appear in results (no partial hints).

### Edge Cases

- User is a member of zero workspaces.
- User loses workspace membership while having an active session.
- Tenant context is active but the tenant does not belong to the current workspace.
- A run is referenced by an external deep link after it was deleted or moved.
- User can view monitoring but cannot perform mutations (e.g., cancel/retry) if those actions exist.

## Requirements *(mandatory)*

**Constitution alignment (required):** This feature changes navigation and authorization behavior but does not introduce new external API calls or background jobs. Any mutation actions added later (e.g., cancel/retry) must follow the platform’s safety gates (confirmation/audit) and be covered by authorization tests.

**Constitution alignment (RBAC-UX):**

- **Authorization plane(s) involved**:
  - **Tenant plane (Entra users)** only.
  - **Platform plane (`/system`) is out of scope** for this feature.
- **Authorization planes**:
  - Workspace-level pages (e.g., monitoring hub, workspace management) are governed by workspace membership and workspace capabilities.
  - Tenant context is secondary and must not change canonical routing for monitoring pages.
- **Isolation model note (workspace scope)**:
  - “Workspace-scoped” monitoring is an explicit, access-checked aggregation scope over the managed tenants that belong to the selected workspace.
  - All reads remain bounded to the current workspace; there is no cross-workspace monitoring view in this feature.
- **404 vs 403 semantics (strict)**:
  - Non-member / not entitled to the workspace scope → **404** (deny-as-not-found)
  - Workspace member but missing the required capability for a protected screen/action → **403**
- **Server-side enforcement**: Navigation visibility must not be treated as authorization; all access control is enforced on the server for every protected page and every mutation.
- **Global search non-leakage**: Global search must not show titles, counts, or partial matches for inaccessible workspaces/tenants/runs. Inaccessible entities behave as not-found.

### Functional Requirements

- **FR-001 (One label, one meaning)**: The application MUST provide two distinct, clearly-labeled entry points:
  - "Switch workspace" for selecting the active workspace context.
  - "Manage workspaces" for workspace CRUD/administration.
- **FR-002 (Canonical workspace switch route)**: "Switch workspace" MUST navigate to `/admin/choose-workspace`.
  - **UX note**: "Switch workspace" is a global context control and MUST NOT be registered as a sidebar navigation item.
- **FR-003 (Canonical workspace management route)**: "Manage workspaces" MUST navigate to `/admin/workspaces` and MUST NOT be labeled simply "Workspaces".
- **FR-004 (Breadcrumb correctness)**: Breadcrumbs in workspace management MUST point back to `/admin/workspaces` and must not send users to the workspace switcher.
- **FR-005 (Monitoring is workspace-level)**: Monitoring pages MUST be workspace-scoped and reachable without tenant context.
- **FR-006 (Canonical Operations URLs)**: Operations MUST remain canonical and tenantless:
  - index: `/admin/operations`
  - detail: `/admin/operations/{run}`
- **FR-007 (Tenant context affects defaults, not routing)**: If tenant context is active, the operations index MUST default to showing runs for that tenant using **server-side default filter state**, and users MUST be able to clear that default to view workspace-wide operations. The canonical URL MUST remain `/admin/operations` and the default MUST present a visible, removable filter chip (no required querystring parameters).
- **FR-008 (Tenant shortcut to operations)**: Tenant detail screens MUST offer a "Recent operations" summary and a "View all operations" call-to-action that leads to the canonical operations index.
- **FR-009 (Membership gating)**: Users MUST be a member of a workspace to access workspace-scoped pages. Non-members MUST receive a not-found response.
- **FR-010 (Capability gating for management)**: Workspace-scoped management/mutations MUST be restricted to users with the appropriate capability/capabilities (from the canonical registry). Unauthorized workspace members MUST receive a forbidden response.
  - Canonical capabilities used by this feature:
    - `workspace.manage` (Capabilities::WORKSPACE_MANAGE): create/edit workspace fields.
    - `workspace_membership.manage` (Capabilities::WORKSPACE_MEMBERSHIP_MANAGE): add/remove members and change roles.
- **FR-011 (Monitoring hub IA)**: The sidebar MUST provide a "Monitoring" area that is the canonical home for Operations now, with reserved surfaces for future Alerts and Audit Log.
- **FR-012 (Deep-link stability)**: Any monitoring entity intended for support workflows MUST have a stable deep link that does not depend on tenant context.
- **FR-013 (No workspace selected)**: If a user visits a workspace-scoped page without a selected workspace context, the system MUST redirect to `/admin/choose-workspace` and then return the user to their originally requested URL after a successful selection.
- **FR-014 (Invalid tenant context)**: If tenant context is active but the tenant does not belong to the current workspace, the system MUST auto-clear tenant context and continue on workspace-level pages without tenant scoping.

- **FR-077-016 (Header context bar)**: The header MUST provide an always-available context bar for Suite navigation:
  - **FR-077-016-A (Workspace visible)**: If a workspace is selected, show `Workspace: <name>` and allow the user to open the existing workspace switcher (`/admin/choose-workspace`).
  - **FR-077-016-B (Tenant accessible on tenantless pages)**: The header MUST surface tenant context even on tenantless pages (e.g., `/admin/operations`). If there is an active tenant context, show `Tenant: <tenant name>` (fallback to a safe identifier). If there is no active tenant but there is a last-selected tenant in the current workspace session, show it.
  - **FR-077-016-C (No implicit switching)**: Canonical pages MUST NOT silently switch tenant or workspace. The context bar is an explicit control only.
  - **FR-077-016-D (No leakage)**: Tenant picker contents MUST include only tenants the user is entitled to view within the current workspace. Unauthorized tenant selection via direct URL MUST remain deny-as-not-found (404).
  - **FR-077-016-E (Filament-native)**: Implementation MUST use Filament v5 mechanisms (topbar/user-menu render hooks + Filament tenancy) and Livewire v4 where needed.

### Key Entities *(include if feature involves data)*

- **Workspace**: Primary context container for a customer/portfolio.
- **Workspace Membership**: The relationship that entitles a user to a workspace.
- **Managed Tenant**: Secondary context within a workspace; used for scoping defaults and tenant workflows.
- **Operation Run**: A record representing an operational execution that belongs to a workspace and may be associated with a tenant.
- **Capability**: A named permission that gates management/mutation behavior.

## Success Criteria *(mandatory)*

### Measurable Outcomes

- **SC-001 (Reduced confusion)**: In a moderated test with new users, at least 90% correctly choose the right destination (switch vs manage) on first attempt.
- **SC-002 (Faster workspace switching)**: Users can switch to a known workspace in under 15 seconds without using search.
- **SC-003 (Reliable deep links)**: Support can open `/admin/operations/{run}` successfully regardless of tenant context in 100% of tested cases.
- **SC-004 (No leakage regressions)**: Security regression tests confirm 0 instances of inaccessible workspaces/tenants/runs appearing in navigation or global search.

## Acceptance details (pinned)

### Recent operations summary (FR-008)

- Show the most recent **5** operation runs for the current tenant, ordered by `created_at` descending (fallback: `id` descending).
- Display, at minimum: `type` (label), `status`, `outcome`, `created_at` (or since), and a link to the run detail.
- Provide a "View all operations" CTA that navigates to canonical `/admin/operations` (no tenant prefix / no required query params).

### Header context bar (FR-077-016)

- The header shows a stable, compact context bar:
  - `Workspace: <name>` (clickable)
  - `Tenant: <name>` (picker)
- Tenant picker is available on tenantless pages.
- No automatic tenant selection occurs when opening canonical URLs.

## Mandatory Tests (pinned)

- **T-077-016-1 (Tenant dropdown on tenantless pages)**: With a selected workspace and an active tenant context, visiting `/admin/operations` shows the tenant picker and selecting a tenant navigates to tenant home.
- **T-077-016-2 (Security filtering)**: Only entitled tenants within the current workspace appear in the picker; posting /navigating to an unauthorized tenant results in 404.
- **T-077-016-3 (No implicit switching)**: Visiting `/admin/operations/{run}` from a deep link MUST NOT auto-switch tenant.
