Summary Consolidates the “Tenant Operate Hub” work (Spec 085) and the follow-up adjustments from the 086 session merge into a single branch ready to merge into dev. Primary focus: stabilize Ops/Operate Hub UX flows, tighten/align authorization semantics, and make the full Sail test suite green. Key Changes Ops UX / Verification Readonly members can view verification operation runs (reports) while starting verification remains restricted. Normalized failure reason-code handling and aligned UX expectations with the provider reason-code taxonomy. Onboarding wizard UX “Start verification” CTA is hidden while a verification run is active; “Refresh” is shown during in-progress runs. Treats provider_permission_denied as a blocking reason (while keeping legacy compatibility). Test + fixture hardening Standardized use of default provider connection fixtures in tests where sync/restore flows require it. Fixed multiple Filament URL/tenant-context test cases to avoid 404s and reduce tenancy routing brittleness. Policy sync / restore safety Enrollment configuration type collision classification tests now exercise the real sync path (with required provider connection present). Restore edge-case safety tests updated to reflect current provider-connection requirements. Testing vendor/bin/sail artisan test --compact (green) vendor/bin/sail bin pint --dirty (green) Notes Includes merged 086 session work already (no separate PR needed). Co-authored-by: Ahmed Darrazi <ahmeddarrazi@ebc83aaa-d947-4a08-b88e-bd72ac9645f7.fritz.box> Co-authored-by: Ahmed Darrazi <ahmeddarrazi@MacBookPro.fritz.box> Co-authored-by: Ahmed Darrazi <ahmeddarrazi@adsmac.fritz.box> Reviewed-on: #103
14 KiB
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:
- whether the Monitoring view is scoped to the current tenant or to all tenants, and
- 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:
- 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.
- 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.
- 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:
- 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.
- 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:
- 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.
- 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.
- User’s 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-logThese shortcuts MUST NOT introduce new tenant-scoped monitoring URLs.
- Runs (Operations) →
-
FR-085-002: The Operations index (
/admin/operations) MUST show a clear scope indicator in the page header:Scope: Workspace — all tenantswhen no tenant context is activeScope: 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 secondaryShow all operations(to/admin/operations) - Else:
Back to Operations(Operations index)
- If tenant context is active AND the user is still entitled:
-
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/operationsand/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 ” affordance MUST be rendered
- Direct access to tenant pages MUST continue to be deny-as-not-found
- Scope indicator MUST show
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/operationsand/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/operationsand/admin/operations/{run}clearly show tenant scope and a “Back to ” 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)
-
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 tenantsandBack to <tenant name>are available.
- With tenant context active and user entitled, request
-
Operations index scope label (no tenant context)
- With no tenant context active, request
/admin/operations. - Assert the page indicates
Scope: Workspace — all tenants.
- With no tenant context active, request
-
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 operationsis available and links to/admin/operations.
- With tenant context active and user entitled, request
-
Run detail back affordance (no tenant context)
- With no tenant context active, request
/admin/operations/{run}. - Assert only
Back to Operationsis available.
- With no tenant context active, request
-
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.
- As a user without tenant entitlement, request
-
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.
- With tenant context active but user not entitled, request
-
No outbound calls on render
- Assert rendering
/admin/operationsand/admin/operations/{run}does not initiate outbound network calls and does not start background work from a view-only GET.
- Assert rendering