TenantAtlas/specs/085-tenant-operate-hub/spec.md
2026-02-11 01:02:42 +01:00

195 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Feature Specification: Tenant Operate Hub / Tenant Overview IA
**Feature Branch**: `085-tenant-operate-hub`
**Created**: 2026-02-09
**Status**: Draft
**Input**: User description: "Make central Monitoring surfaces feel context-aware when entered from a tenant, without changing canonical URLs, and without weakening deny-as-not-found security boundaries."
## Clarifications
### Session 2026-02-09 (work order alignment)
- Q: What is the source of truth for “Back to tenant”? → A: The active entitled tenant context (Filament tenant if present, otherwise the remembered last-tenant id for the current workspace).
- Q: Should “Back to last tenant” be implemented as a separate feature? → A: No; remembered tenant context is used only to preserve context when navigating from a tenant into central Monitoring.
- Q: What does “Show all tenants” do? → A: It explicitly exits tenant context to return to workspace-wide monitoring (no mixed behavior with filter resets).
- Q: How is Monitoring reached from tenant context? → A: Tenant navigation offers a “Monitoring” group with shortcuts that open central Monitoring surfaces.
- Q: How should stale tenant context (tenant context active but user no longer entitled) behave on Monitoring pages? → A: Monitoring renders workspace-wide (no tenant name, no “Back to tenant”), preserving deny-as-not-found for tenant pages.
- Q: Should run detail offer a secondary escape hatch when tenant context is active? → A: Yes — show a secondary “Show all operations” link to `/admin/operations`.
- Q: How should tenant Monitoring shortcuts indicate “opens central monitoring”? → A: Keep labels minimal (no “↗ Central” suffix).
## User Scenarios & Testing *(mandatory)*
### User Story 1 - Monitoring feels context-aware (Priority: P1)
As an operator, when I open central Monitoring from within a tenant, I immediately understand:
1) whether the Monitoring view is scoped to the current tenant or to all tenants, and
2) how to get back to the tenant I came from.
**Why this priority**: This is the core usability and safety problem: monitoring and tenant work should not feel like different apps, but they must not blur security boundaries.
**Independent Test**: With a tenant context active, a test user can open the Operations index and a run detail, see an explicit scope indicator and a deterministic “Back to tenant”, and exit to workspace-wide monitoring intentionally.
**Acceptance Scenarios**:
1. **Given** a user is a member of a workspace and has access to at least one tenant, **When** they open central Monitoring (Operations), **Then** the page clearly shows whether tenant context is active.
2. **Given** a tenant context is active, **When** the user navigates to a canonical monitoring detail page, **Then** the UI provides a single, clear “Back to tenant” affordance that returns to that tenant dashboard.
3. **Given** a user is not entitled to the current tenant, **When** they try to access tenant-scoped pages via a direct link, **Then** they receive a not-found experience (deny-as-not-found), without any tenant existence hints.
---
### User Story 2 - Canonical URLs with explicit scope (Priority: P2)
As an operator, I can use canonical Monitoring URLs at all times. When tenant context is active, Monitoring views can be tenant-filtered by default, but they must not implicitly change tenant selection.
**Why this priority**: Avoids mistakes and misinterpretation of data by preventing silent scoping changes.
**Independent Test**: With a tenant selected, open monitoring index and detail views and verify the scope is consistent and clearly communicated.
**Acceptance Scenarios**:
1. **Given** a tenant context is active, **When** the user opens the monitoring index, **Then** the default view is tenant-scoped (or clearly offers a one-click tenant scope), and the UI visibly indicates the scope.
2. **Given** no tenant context is active, **When** the user opens monitoring, **Then** the view is workspace-wide and does not imply a tenant is selected.
---
### User Story 3 - Deep links are safe and recoverable (Priority: P3)
As an operator working inside a tenant, when I land on a canonical run detail via a deep link, I can safely return to the tenant if tenant context is still active and I am still entitled.
**Why this priority**: These workflows are frequent. Deep links are where users most often “lose” tenant context.
**Independent Test**: With a tenant context active, open a canonical run detail and verify the “Back to tenant” affordance is present and correct.
**Acceptance Scenarios**:
1. **Given** a tenant context is active and the user is still entitled, **When** they open a canonical run detail, **Then** they see a “Back to tenant” affordance.
2. **Given** tenant context is not active, **When** the user opens a canonical run detail, **Then** they see only a “Back to Operations” affordance.
### Edge Cases
- User has no workspace selected: Monitoring must not show cross-workspace data; user must select a workspace first.
- User has workspace access but zero tenant access: Monitoring must still work in workspace-wide mode, without tenant selection.
- Users tenant access is revoked while they have a deep link open: subsequent tenant-scoped navigation must be deny-as-not-found.
- User opens a bookmarked canonical run detail directly: the UI must provide a deterministic “Back” behavior without inventing tenant context.
- Tenant context is active, but entitlement was revoked: Monitoring must not leak tenant identity; tenant return affordance must not appear (or must be safe).
- Monitoring views must remain view-only render surfaces: rendering must not trigger outbound calls.
## Requirements *(mandatory)*
### Target State (hard decision)
This spec adopts a single, deterministic interpretation:
- Monitoring URLs are canonical and do not change with tenant context.
- Tenant context makes Monitoring *feel* scoped (scope indicators, default filters, and deterministic exits) without implicit tenant switching.
- Operations index: `/admin/operations`
- Operations run detail: `/admin/operations/{run}`
- Alerts: `/admin/alerts`
- Audit log: `/admin/audit-log`
Tenant plane remains under `/admin/t/{tenant}` for tenant dashboards and workflows. Monitoring views are central, but when tenant context is active they become tenant-filtered by default and provide a deterministic “Back to tenant” affordance.
**Constitution alignment (required):** This feature is information architecture + navigation behavior. It MUST NOT introduce new outbound calls for monitoring pages. If it introduces or changes any write/change behavior (e.g., starting workflows), it MUST maintain existing safety gates (preview/confirmation/audit), tenant isolation, run observability, and tests.
**Constitution alignment (RBAC-UX):** This feature changes how users reach surfaces; it MUST preserve and test authorization semantics:
- Non-member / not entitled to workspace scope OR tenant scope → deny-as-not-found (404 semantics)
- Member but missing capability → forbidden (403 semantics)
**Constitution alignment (OPS-EX-AUTH-001):** Authentication handshakes may perform synchronous outbound communication on auth endpoints. This MUST NOT be used for Monitoring pages.
**Constitution alignment (BADGE-001):** If any status/severity/outcome badges are added or changed on hub pages, their meaning MUST be centralized and covered by tests.
**Constitution alignment (UI Action Surfaces):** If this feature adds/modifies any admin or tenant UI surfaces, the “UI Action Matrix” MUST be updated and action gating MUST remain consistent (confirmation for destructive-like actions; server-side authorization for mutations).
### Functional Requirements
- **FR-085-001**: Tenant navigation MUST offer a “Monitoring” group with shortcuts to central Monitoring surfaces:
- Runs (Operations) → `/admin/operations`
- Alerts → `/admin/alerts`
- Audit Log → `/admin/audit-log`
These shortcuts MUST NOT introduce new tenant-scoped monitoring URLs.
- **FR-085-002**: The Operations index (`/admin/operations`) MUST show a clear scope indicator in the page header:
- `Scope: Workspace — all tenants` when no tenant context is active
- `Scope: Tenant — <tenant name>` when tenant context is active
- **FR-085-003**: Canonical Monitoring URLs MUST NOT implicitly change tenant context. Tenant context MAY influence default filters on Monitoring views.
- **FR-085-004**: When tenant context is active on the Operations index, the default tenant filter MUST be set to the current tenant, and the UI MUST make this tenant scoping obvious.
- **FR-085-005**: The Operations index MUST provide two explicit CTAs when tenant context is active:
- `Show all tenants` (explicitly exits tenant context and returns to workspace-wide monitoring)
- `Back to <tenant name>` (navigates to tenant dashboard)
- **FR-085-006**: The run detail (`/admin/operations/{run}`) MUST provide a deterministic “Back” affordance:
- If tenant context is active AND the user is still entitled: `← Back to <tenant name>` (tenant dashboard) AND a secondary `Show all operations` (to `/admin/operations`)
- Else: `Back to Operations` (Operations index)
- **FR-085-007**: “Back to tenant” MUST be based only on active entitled tenant context (Filament tenant, or remembered tenant for the current workspace). It MUST NOT be inferred from arbitrary deep-link parameters.
- **FR-085-008**: Deny-as-not-found MUST remain: users not entitled to workspace or tenant scope MUST receive a not-found experience (404 semantics), with no tenant existence hints.
- **FR-085-009**: Monitoring views (`/admin/operations` and `/admin/operations/{run}`) MUST remain view-only render surfaces and MUST NOT trigger outbound calls during render.
- **FR-085-010**: If tenant context is active but the user is not entitled to that tenant, Monitoring pages MUST behave as workspace-wide views:
- Scope indicator MUST show `Scope: Workspace — all tenants`
- No tenant name MUST be displayed
- No “Back to <tenant>” affordance MUST be rendered
- Direct access to tenant pages MUST continue to be deny-as-not-found
## UI Action Matrix *(mandatory when UI surfaces are changed)*
| Surface | Location | Header Actions | Inspect Affordance (List/Table) | Row Actions (max 2 visible) | Bulk Actions (grouped) | Empty-State CTA(s) | View Header Actions | Create/Edit Save+Cancel | Audit log? | Notes / Exemptions |
|---|---|---|---|---|---|---|---|---|---|---|
| Central Operations (index) | `/admin/operations` | Scope indicator; `Show all tenants` (when tenant context active); deterministic back affordance | Linked run rows to open run detail | N/A | N/A | N/A | N/A | N/A | No | Must not implicitly change tenant context; default tenant filter when tenant context active |
| Central Operations (run detail) | `/admin/operations/{run}` | `← Back to <tenant>` (when tenant context active + entitled) OR `Back to Operations`; secondary `Show all operations` allowed when tenant context active + entitled | N/A | N/A | N/A | N/A | N/A | N/A | No | Must not reveal tenant identity when user is not entitled |
| Tenant navigation shortcuts | Tenant sidebar | N/A | N/A | N/A | N/A | N/A | N/A | N/A | No | “Monitoring” group with central shortcuts |
### Key Entities *(include if feature involves data)*
- **Workspace**: A security and organizational boundary for operations and monitoring.
- **Tenant**: A managed environment within a workspace; access is entitlement-based.
- **Monitoring (Operations)**: Central monitoring views that can be workspace-wide or tenant-scoped when tenant context is active.
- **Operation Run**: A tracked execution of an operational workflow; viewable via canonical run detail.
- **Alert**: An operator-facing signal about an issue or state requiring attention.
- **Audit Event**: An immutable record of important user-triggered actions and sensitive operations.
## Success Criteria *(mandatory)*
### Measurable Outcomes
- **SC-085-001**: In a usability walkthrough, 90% of operators can correctly identify whether Operations is scoped to a tenant or to all tenants within 10 seconds of opening `/admin/operations`.
- **SC-085-002**: With tenant context active, operators can return to the tenant dashboard from `/admin/operations` and `/admin/operations/{run}` in ≤ 1 click.
- **SC-085-003**: Support tickets tagged “lost tenant context / where am I?” decrease by 30% within 30 days after rollout.
- **SC-085-004**: Authorization regression checks show zero cases where a non-entitled user can infer existence of a tenant or view tenant-scoped monitoring data.
### Engineering Acceptance Outcomes
- **SC-085-005**: When tenant context is active, `/admin/operations` and `/admin/operations/{run}` clearly show tenant scope and a “Back to <tenant>” affordance.
- **SC-085-006**: When tenant context is not active, `/admin/operations/{run}` shows “Back to Operations” and no “Back to tenant”.
- **SC-085-007**: Viewing Monitoring pages does not initiate outbound network requests or start background work as a side effect of rendering.
## Test Plan *(mandatory)*
1. **Operations index scope label + CTAs (tenant context)**
- With tenant context active and user entitled, request `/admin/operations`.
- Assert the page indicates `Scope: Tenant — <tenant name>`.
- Assert `Show all tenants` and `Back to <tenant name>` are available.
2. **Operations index scope label (no tenant context)**
- With no tenant context active, request `/admin/operations`.
- Assert the page indicates `Scope: Workspace — all tenants`.
3. **Run detail back affordance (tenant context)**
- With tenant context active and user entitled, request `/admin/operations/{run}`.
- Assert `← Back to <tenant name>` is available.
- Assert secondary `Show all operations` is available and links to `/admin/operations`.
4. **Run detail back affordance (no tenant context)**
- With no tenant context active, request `/admin/operations/{run}`.
- Assert only `Back to Operations` is available.
5. **Deny-as-not-found regression**
- As a user without tenant entitlement, request `/admin/t/{tenant}`.
- Assert deny-as-not-found behavior (404 semantics) and that no tenant identity hints are revealed via Monitoring CTAs.
6. **Stale tenant context behaves workspace-wide**
- With tenant context active but user not entitled, request `/admin/operations`.
- Assert scope indicates workspace-wide and no tenant name or “Back to tenant” is present.
7. **No outbound calls on render**
- Assert rendering `/admin/operations` and `/admin/operations/{run}` does not initiate outbound network calls and does not start background work from a view-only GET.