163 lines
13 KiB
Markdown
163 lines
13 KiB
Markdown
# Feature Specification: Workspace-first Navigation & Monitoring Hub
|
||
|
||
**Feature Branch**: `077-workspace-nav-monitoring-hub`
|
||
**Created**: 2026-02-06
|
||
**Status**: Draft
|
||
**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). Workspace management is workspace-scoped: non-members receive 404 (deny-as-not-found); members missing required capabilities receive 403.
|
||
- 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`.
|
||
- **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.
|