TenantAtlas/specs/191-baseline-compare-operator-mode/data-model.md
ahmido f7bbea2623 191-baseline-compare-operator-mode (#223)
## Summary
<!-- Kurz: Was ändert sich und warum? -->

## Spec-Driven Development (SDD)
- [ ] Es gibt eine Spec unter `specs/<NNN>-<feature>/`
- [ ] Enthaltene Dateien: `plan.md`, `tasks.md`, `spec.md`
- [ ] Spec beschreibt Verhalten/Acceptance Criteria (nicht nur Implementation)
- [ ] Wenn sich Anforderungen während der Umsetzung geändert haben: Spec/Plan/Tasks wurden aktualisiert

## Implementation
- [ ] Implementierung entspricht der Spec
- [ ] Edge cases / Fehlerfälle berücksichtigt
- [ ] Keine unbeabsichtigten Änderungen außerhalb des Scopes

## Tests
- [ ] Tests ergänzt/aktualisiert (Pest/PHPUnit)
- [ ] Relevante Tests lokal ausgeführt (`./vendor/bin/sail artisan test` oder `php artisan test`)

## Migration / Config / Ops (falls relevant)
- [ ] Migration(en) enthalten und getestet
- [ ] Rollback bedacht (rückwärts kompatibel, sichere Migration)
- [ ] Neue Env Vars dokumentiert (`.env.example` / Doku)
- [ ] Queue/cron/storage Auswirkungen geprüft

## UI (Filament/Livewire) (falls relevant)
- [ ] UI-Flows geprüft
- [ ] Screenshots/Notizen hinzugefügt

## Notes
<!-- Links, Screenshots, Follow-ups, offene Punkte -->

Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #223
2026-04-11 12:51:46 +00:00

166 lines
7.6 KiB
Markdown

# Data Model: Baseline Compare Matrix: High-Density Operator Mode
## Overview
This follow-up introduces no new persisted entity. It reuses the existing Spec 190 matrix truth and adds derived presentation models for operator density, staged filtering, and non-blocking status cues.
## Existing Source Truths Reused Without Change
### Baseline compare truth from Spec 190
The following derived or canonical inputs remain authoritative and are not redefined by this spec:
- workspace-scoped baseline reference truth
- visible tenant summaries
- subject summaries
- subject-by-tenant matrix cells
- compare-start availability and existing drilldown destinations
This spec changes how those inputs are rendered and interacted with, not how they are computed.
## New Derived Presentation Models
### MatrixPresentationState
**Type**: request-scoped page presentation contract
**Source**: route/query state + visible tenant count + existing run state
| Field | Type | Notes |
|------|------|-------|
| `requestedMode` | string | `auto`, `dense`, or `compact` from route/query state |
| `resolvedMode` | string | Final mode used for rendering: `dense` or `compact` |
| `visibleTenantCount` | integer | Existing visible-set count from the matrix bundle |
| `activeFilterCount` | integer | Count of currently applied filters |
| `hasStagedFilterChanges` | boolean | Whether filter draft state differs from applied state |
| `autoRefreshActive` | boolean | True when background polling is active because compare work is queued or running |
| `lastUpdatedAt` | datetime or null | Timestamp for the currently rendered matrix data |
| `canOverrideMode` | boolean | Whether the operator may locally switch away from `auto` |
### MatrixFilterDraft
**Type**: request-scoped staged filter model
**Source**: page form state only
| Field | Type | Notes |
|------|------|-------|
| `selectedPolicyTypes` | array<string> | Draft policy-type filter selection |
| `selectedStates` | array<string> | Draft state-group selection |
| `selectedSeverities` | array<string> | Draft severity selection |
| `tenantSort` | string | Current tenant sort choice |
| `subjectSort` | string | Current subject sort choice |
| `focusedSubjectKey` | string or null | Optional current subject focus |
### DenseSubjectRowView
**Type**: request-scoped dense-mode row view
**Source**: existing subject summary + existing matrix cells
| Field | Type | Notes |
|------|------|-------|
| `subjectKey` | string | Stable row key |
| `displayName` | string | Primary row label |
| `policyType` | string | Compact secondary label |
| `baselineExternalId` | string or null | Optional secondary context |
| `deviationBreadth` | integer | Existing subject summary metric |
| `missingBreadth` | integer | Existing subject summary metric |
| `ambiguousBreadth` | integer | Existing subject summary metric |
| `maxSeverity` | string or null | Existing subject summary severity |
| `trustLevel` | string | Existing subject summary trust |
| `cells` | array<DenseCellView> | One condensed cell per visible tenant |
### DenseCellView
**Type**: request-scoped dense-mode cell view
**Source**: existing matrix cell + existing tenant summary freshness
| Field | Type | Notes |
|------|------|-------|
| `tenantId` | integer | Visible tenant identifier |
| `subjectKey` | string | Subject row key |
| `state` | string | Existing Spec 190 state |
| `freshnessState` | string | Freshness signal shown in compact form |
| `trustLevel` | string | Trust signal shown in compact form |
| `severity` | string or null | Optional attention signal |
| `attentionLevel` | string | Derived presentation label such as `aligned`, `refresh_recommended`, or `needs_attention` |
| `reasonSummary` | string or null | Short secondary explanation for compact reveal surfaces |
| `primaryDrilldownUrl` | string or null | Preferred next follow-up action |
| `secondaryDrilldownUrls` | array<string, string> | Additional compact follow-up links when available |
### CompactSubjectResultView
**Type**: request-scoped single-tenant row view
**Source**: one visible tenant summary + existing matrix cell + existing subject summary
| Field | Type | Notes |
|------|------|-------|
| `tenantId` | integer | The single visible tenant in compact mode |
| `subjectKey` | string | Stable subject key |
| `displayName` | string | Primary subject label |
| `policyType` | string | Secondary grouping/context |
| `state` | string | Existing Spec 190 state |
| `freshnessState` | string | Compact freshness label |
| `trustLevel` | string | Compact trust label |
| `severity` | string or null | Optional attention indicator |
| `reasonSummary` | string or null | Short explanation line |
| `primaryDrilldownUrl` | string or null | Main follow-up action |
| `runUrl` | string or null | Secondary run-level follow-up |
### MatrixSupportSurfaceState
**Type**: request-scoped supporting-context contract
**Source**: page state + existing legends + refresh metadata
| Field | Type | Notes |
|------|------|-------|
| `legendMode` | string | `grouped`, `collapsed`, or equivalent compact support behavior |
| `showActiveFilterSummary` | boolean | Whether applied filters are summarized inline |
| `showLastUpdated` | boolean | Whether the page displays last-updated metadata |
| `showAutoRefreshHint` | boolean | Whether passive auto-refresh copy is visible |
| `showBlockingRefreshState` | boolean | Reserved for deliberate user-triggered reloads only |
## Rendering and Resolution Rules
### Mode resolution rules
1. If `requestedMode = auto` and `visibleTenantCount > 1`, resolve to `dense`.
2. If `requestedMode = auto` and `visibleTenantCount = 1`, resolve to `compact`.
3. If a manual override is present, use it unless it would produce an invalid empty layout.
4. Manual override remains route-local and must never be persisted as product truth.
### Dense-mode rules
- The subject column remains sticky during horizontal scroll.
- The primary visible content per cell is state, trust, freshness, and attention.
- Long explanatory text and repeated action links do not render as the dominant cell body.
### Compact single-tenant rules
- The tenant header does not repeat as a pseudo-column structure.
- Each subject entry shows one primary status line and a reduced set of secondary metadata.
- Existing subject focus and drilldown continuity remain available.
### Filter workflow rules
- Heavy multi-select filters use staged state first and apply only when the operator confirms.
- Applied filter count and scope summary reflect the applied state, not merely the draft state.
- Reset may clear both draft and applied state in one explicit action.
### Status signal rules
- `blocking refresh` is reserved for deliberate user-triggered reload or recalculation moments.
- `auto-refresh active` indicates passive polling while compare work is still queued or running.
- `lastUpdatedAt` reflects the timestamp of the rendered matrix payload, not merely the latest compare run in the system.
### Safety rules
- No rendering path may widen tenant visibility beyond the existing visible set.
- No presentation-state change may change the underlying compare state, trust, or freshness semantics.
- No grouped legend or compact cell may invent new status vocabulary outside existing centralized badge semantics.
## Relationships
- One `MatrixPresentationState` governs one rendered matrix page.
- One `MatrixFilterDraft` belongs to one `MatrixPresentationState`.
- In dense mode, one `DenseSubjectRowView` maps to many `DenseCellView` entries.
- In compact mode, one visible tenant yields many `CompactSubjectResultView` entries.
- One `MatrixSupportSurfaceState` coordinates legends, refresh hints, and active-filter summaries for the same page render.