Files
git.stella-ops.org/docs/technical/architecture/multi-tenant-flow-sequences.md

107 lines
4.2 KiB
Markdown

# Multi-Tenant Same-Key End-to-End Flow Sequences
Date: 2026-02-22
Source sprint: `SPRINT_20260222_053_DOCS_multi_tenant_same_api_key_contract_baseline.md`
Related ADR: `docs/architecture/decisions/ADR-002-multi-tenant-same-api-key-selection.md`
## 1) Sign-in to Tenant Mapping
```mermaid
sequenceDiagram
autonumber
participant User
participant Web as Web Console
participant Auth as Authority
participant Gw as Router/Gateway
participant Svc as Tenant-scoped API
User->>Web: Sign in
Web->>Auth: /connect/authorize + PKCE
Auth-->>Web: auth code
Web->>Auth: /connect/token (client credentials or password grant, tenant=<optional>)
Auth->>Auth: Resolve selected tenant from tenant + tenants metadata
Auth-->>Web: Access token (stellaops:tenant + optional stellaops:allowed_tenants)
Web->>Auth: /console/tenants
Auth-->>Web: { tenants[], selectedTenant }
Web->>Web: Hydrate ConsoleSessionStore + AuthSessionStore + PlatformContext
Web->>Gw: API request + canonical tenant header
Gw->>Svc: Forward resolved tenant context
Svc-->>Web: Tenant-scoped response
```
Deterministic selection rule:
- If `tenant` parameter is present at token request time, it must be in assigned tenant set.
- If no parameter and only one assignment/default exists, use that selected tenant.
- If ambiguous (multi-assigned and no default/request), reject.
## 2) Header Selector Tenant Switch
```mermaid
sequenceDiagram
autonumber
participant User
participant Topbar as Header Tenant Selector
participant Session as ConsoleSessionService
participant Auth as Authority
participant Stores as Session/Context Stores
participant APIs as Platform/Scanner/Graph APIs
User->>Topbar: Select tenant "tenant-bravo"
Topbar->>Session: switchTenant("tenant-bravo")
Session->>Stores: Optimistic selectedTenant update
Session->>Auth: /console/tenants (tenant header=tenant-bravo)
Auth-->>Session: allowed tenants + selectedTenant
Session->>Auth: /console/profile + /console/token/introspect
Auth-->>Session: profile/token introspection for selected tenant
Session->>Stores: Commit tenant to Console/Auth/Platform/TenantActivation stores
Session->>APIs: Trigger context reload for tenant-scoped data
APIs-->>Topbar: Refreshed tenant-scoped responses
```
Error recovery path:
- On switch failure (`403`, `tenant_conflict`, session expiry), restore previous tenant in all stores.
- Attempt context reload for previous tenant.
- Surface deterministic error in tenant panel with retry action.
## 3) API Request Propagation Through Gateway
```mermaid
sequenceDiagram
autonumber
participant UI as Web API Client
participant I as Tenant/Context Interceptors
participant Gw as Router/Gateway
participant Backend as Platform/Scanner/Graph
UI->>I: Outgoing request
I->>I: Resolve active tenant from canonical runtime state
I-->>UI: Add canonical header X-StellaOps-Tenant (+ compat aliases)
UI->>Gw: Request with tenant headers + token
Gw->>Gw: Strip caller-supplied identity headers, derive tenant from validated claims, rewrite canonical headers
Gw->>Backend: Forward tenant-scoped request
Backend->>Backend: Resolve tenant context + enforce tenant ownership
Backend-->>UI: Deterministic success/failure payload
```
Cache/store invalidation points after tenant switch:
- Console session context cache.
- Tenant-scoped page stores (Platform/Scanner/Graph read models).
- URL context synchronization where tenant is persisted as global context.
## 4) Failure Sequences
### Missing tenant context
- Expected result: deterministic `400`/`401`/`403` based on service policy and auth stage.
- UI behavior: keep prior selection if available; show recoverable error panel.
### Tenant mismatch
- Trigger: claim tenant != header/request tenant.
- Expected result: reject with deterministic conflict error (for example `tenant_conflict` or `tenant_forbidden`).
- Audit/telemetry: record attempted tenant override + resolved tenant.
### Insufficient scope
- Trigger: token lacks required policy scope for requested endpoint.
- Expected result: deterministic `403` with scope policy failure context.
- UI behavior: no tenant mutation; show access-denied state.