## 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
166 lines
7.6 KiB
Markdown
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. |