TenantAtlas/specs/144-canonical-operation-viewer-context-decoupling/data-model.md

99 lines
4.2 KiB
Markdown

# Data Model: Canonical Operation Viewer Context Decoupling
## Overview
This feature introduces no database schema changes. The design work is centered on clarifying how existing records and session state combine to produce canonical run-view behavior.
## Core Entities
### OperationRun
- **Ownership**: Workspace-owned canonical monitoring record
- **Existing fields used by this feature**:
- `id`
- `workspace_id`
- `tenant_id` nullable
- `type`
- `status`
- `outcome`
- `context`
- `summary_counts`
- `initiator_name`
- **Relationships**:
- Belongs to `workspace`
- Optionally belongs to `tenant`
- Optionally belongs to `user`
- **Feature rule**: Route legitimacy is derived from the run itself plus direct entitlement checks, not from remembered tenant context.
### Tenant
- **Ownership**: Workspace-owned durable record
- **Existing fields used by this feature**:
- `id`
- `workspace_id`
- `name`
- `external_id`
- lifecycle state as derived by the tenant operability and lifecycle presentation layer
- **Feature rule**: A tenant linked to a run may be active, onboarding, archived, or otherwise non-selectable as current context and still remain a valid tenant reference for the canonical run viewer.
### RememberedTenantContext
- **Ownership**: Session-backed operator preference state
- **Existing sources used by this feature**:
- Current Filament tenant when present and entitled
- Workspace remembered tenant when no entitled Filament tenant is present
- **Feature rule**: This state may influence labels, back links, and optional information banners, but it never decides whether the canonical run exists or is viewable.
## Derived Viewer State
The implementation should model a lightweight derived view state rather than adding persistence.
### CanonicalRunViewerState
- **Inputs**:
- `OperationRun $run`
- current workspace membership
- direct tenant entitlement for `$run->tenant_id` when present
- current remembered or selected header tenant context
- **Derived outputs**:
- `authorization_outcome`: allowed, deny-as-not-found, forbidden
- `run_tenant_state`: tenantless, active, onboarding, archived, other non-selectable
- `header_context_state`: no selected tenant, selected tenant matches run tenant, selected tenant differs from run tenant
- `banner_message`: null or an informational message explaining mismatch or lifecycle framing
- `follow_up_affordance_state`: available, partially available, unavailable because of lifecycle or entitlement
## Authorization State Matrix
| Run Exists | Workspace Member | Tenant Entitled | Capability Granted | Result |
|------------|------------------|-----------------|--------------------|--------|
| No | N/A | N/A | N/A | 404 not found |
| Yes | No | N/A | N/A | 404 deny-as-not-found |
| Yes | Yes | No for linked tenant | N/A | 404 deny-as-not-found |
| Yes | Yes | Yes or tenantless | No when capability is required | 403 forbidden |
| Yes | Yes | Yes or tenantless | Yes or no capability required | Render viewer |
## Presentation State Matrix
| Run Tenant | Header Tenant Context | Viewer Valid | Expected Messaging |
|------------|-----------------------|--------------|--------------------|
| Tenantless | None | Yes | Workspace-level framing only |
| Tenantless | Selected tenant present | Yes | Optional note that run is workspace-level and not tied to the selected tenant |
| Active tenant | Matching selected tenant | Yes | No mismatch banner required |
| Active tenant | Different selected tenant | Yes | Non-blocking mismatch message |
| Onboarding or archived tenant | None | Yes | Lifecycle-aware canonical workspace framing |
| Onboarding or archived tenant | Different selected tenant | Yes | Lifecycle-aware mismatch message |
## Validation Rules
- A run with `workspace_id <= 0` remains invalid and is denied as not found.
- A tenant-linked run must never reveal tenant-linked details to an actor who lacks entitlement to that tenant.
- A tenantless run must remain viewable based on workspace access and any resolved capability requirement for the run type.
- Remembered tenant context must never be mutated as a side effect of viewing a canonical run.
## No Schema Change Confirmation
- No new tables
- No new columns
- No new indexes
- No data backfill
- No migration work required