Auto-created PR: committing all local changes and pushing branch `277-stored-reports-surface` to remote. Please review and adjust the title/description as needed. Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de> Reviewed-on: #333
7.3 KiB
Data Model: Stored Reports Surface v1
Date: 2026-05-06
Branch: 277-stored-reports-surface
Overview
This slice introduces no new persisted entity. StoredReport remains the only stored-report source of truth. The new surface adds tenant-scoped, read-only view models over that truth and keeps downstream evidence, review, and review-pack consumers separate.
Existing Persisted Truth
1. Stored Report
Persistence: Existing stored_reports table
Ownership: Tenant-owned
Scope: Many retained rows per tenant and report family
| Field | Type | Nullable | Notes |
|---|---|---|---|
id |
bigint | no | Internal stored-report id |
workspace_id |
bigint | no | Required workspace isolation anchor |
tenant_id |
bigint | no | Required tenant isolation anchor |
report_type |
string | no | Current v1 supported values: permission_posture, entra.admin_roles |
payload |
jsonb | no | Family-specific report payload |
fingerprint |
string | yes | Integrity anchor for the current row |
previous_fingerprint |
string | yes | Historical lineage anchor |
created_at |
datetime | yes | Persisted creation time |
updated_at |
datetime | yes | Standard timestamp |
Behavior rules:
- Stored reports are immutable retained artifacts after creation.
currentversushistoricalis derived by comparing the row with the latest row for the sametenant_idandreport_type.retention_statestays derived asretainedin this slice.- No new persisted lifecycle, publication, or browse metadata is introduced.
2. Evidence Snapshot Item Source Reference
Persistence: Existing evidence_snapshot_items.source_record_type and source_record_id fields
Ownership: Existing evidence domain
These fields remain downstream identity anchors when evidence items point to a stored report. They are context only in this slice and do not create an additional v1 launch seam.
3. Review Pack / Tenant Review Consumption
Persistence: Existing review-pack and tenant-review summaries
Ownership: Existing reporting domains
These consumers remain separate business truth. The stored-report surface may describe that stored reports are reused downstream, but it does not converge their operator routes in v1.
Derived Read Models
4. Stored Report Row Summary
Persistence: none, derived at runtime
Owner: stored-report register
| Field | Type | Required | Notes |
|---|---|---|---|
report_id |
int | yes | Backed by stored_reports.id |
display_reference |
string | yes | Stored report #{id} ({family label}) from existing artifact-truth wording |
report_type |
string | yes | Raw family key |
report_family_label |
string | yes | Headline-style label such as Permission posture report |
lifecycle_state |
string | yes | current or historical from artifact truth |
retention_state |
string | yes | retained |
measured_at |
datetime | yes | Derived from payload timestamp when present, otherwise created_at |
summary_highlights |
list | yes | Bounded, family-specific summary facts |
history_visibility |
bool | yes | Whether the row is included only when history is revealed |
5. Stored Report Detail View
Persistence: none, derived at runtime
Owner: stored-report detail page
| Field | Type | Required | Notes |
|---|---|---|---|
artifact_truth |
array | yes | Reused ArtifactTruthPresenter::forStoredReport() envelope |
display_reference |
string | yes | Stable stored-report reference |
report_family_label |
string | yes | Headline family label |
measured_at |
datetime | yes | Payload timestamp or created_at |
integrity_anchor |
string | no | fingerprint, shown when present |
previous_fingerprint |
string | no | Historical lineage anchor |
current_report_id |
int | no | Latest same-family row when viewing a historical record |
current_report_url |
string | no | Canonical detail URL for the current row |
summary_branch |
object | yes | One of the two supported family-specific summary shapes below |
raw_payload |
array | yes | Present but collapsed by default |
6. Permission Posture Summary
Persistence: none, derived from StoredReport.payload
Payload anchors from current repo truth:
posture_scorerequired_countgranted_countchecked_atpermissions[]entries withkey,type,status, andfeatures
Derived summary fields:
| Field | Type | Notes |
|---|---|---|
posture_score |
int or null | Primary posture score |
required_count |
int | Required permissions count |
granted_count |
int | Granted permissions count |
missing_count |
int | Derived as required_count - granted_count, never persisted |
at_risk_permissions |
list | First few non-granted permission entries for operator summary |
checked_at |
datetime or null | Preferred measurement timestamp when present |
7. Entra Admin Roles Summary
Persistence: none, derived from StoredReport.payload
Payload anchors from current repo truth:
measured_attotals.roles_totaltotals.assignments_totaltotals.high_privilege_assignmentshigh_privilege[]entries with role, principal, scope, and severity fields
Derived summary fields:
| Field | Type | Notes |
|---|---|---|
roles_total |
int | Total role definitions captured |
assignments_total |
int | Total assignments captured |
high_privilege_assignments |
int | Count of privileged assignments |
highest_risk_assignment |
array or null | First highest-severity assignment for operator context |
measured_at |
datetime or null | Preferred measurement timestamp |
8. Stored Report Launch Seam
Persistence: none, derived from existing operator routes
| Field | Type | Required | Notes |
|---|---|---|---|
source_surface |
string | yes | Current v1 source surface name |
target_url |
string | yes | Canonical stored-report detail URL |
Current v1 seam:
AdminRolesSummaryWidgetis the only confirmed canonical drilldown source in this slice.
Derived State Rules
| Rule | Derived Behavior |
|---|---|
| Current row selection | Latest row by created_at desc, id desc for the same tenant_id and report_type |
| Lifecycle state | current for the latest row, otherwise historical |
| Retention state | retained for v1 stored-report browsing |
| Measured time | payload.measured_at or payload.checked_at when available, otherwise created_at |
| Register visibility | Only rows with an explicit family-to-capability mapping are listed |
| Detail authorization | Family-aware capability check after workspace and tenant membership is established |
| Unexpected report family | Outside v1 browse and detail scope until a follow-up spec adds support |
Boundaries Explicitly Preserved
- No new report-generation, export, or lifecycle-mutation truth is introduced.
- Evidence snapshots, tenant reviews, review packs, and stored reports remain separate artifacts.
- Current versus historical stays derived and is not persisted as a new domain state.
- No generic report registry, schema catalog, or renderer framework is created.
- Evidence, review, and review-pack routes remain context only and are not v1 convergence targets.