TenantAtlas/specs/155-tenant-review-layer/data-model.md
2026-03-21 23:02:02 +01:00

5.2 KiB

Data Model: Tenant Review Layer

Overview

The first slice introduces a new tenant-owned review aggregate that consumes existing evidence-domain and governance outputs without replacing them.

Entities

TenantReview

  • Purpose: The primary recurring governance review record for one tenant, anchored to one chosen evidence basis.
  • Ownership: Tenant-owned (workspace_id, tenant_id required).
  • Core fields:
    • id
    • workspace_id
    • tenant_id
    • evidence_snapshot_id
    • current_export_review_pack_id nullable
    • operation_run_id nullable for async composition/refresh
    • initiated_by_user_id
    • published_by_user_id nullable
    • superseded_by_review_id nullable self-reference
    • fingerprint nullable, deterministic for dedupe of unchanged draft composition
    • status enum: draft, ready, published, archived, superseded, failed
    • completeness_state enum: complete, partial, missing, stale
    • summary JSONB for aggregate executive metadata and publish blockers
    • published_at nullable timestamp
    • archived_at nullable timestamp
    • generated_at nullable timestamp
    • created_at, updated_at
  • Derived presentation states:
    • publication state is derived from status plus published_at; no separate persisted publication enum is introduced in this slice
    • export readiness is derived from current_export_review_pack_id, review completeness/readiness rules, and the latest related review-pack state; no separate persisted export-readiness enum is introduced in this slice
  • Relationships:
    • belongs to Tenant
    • belongs to Workspace
    • belongs to EvidenceSnapshot
    • belongs to User as initiator
    • belongs to User as publisher
    • belongs to OperationRun for async generation/refresh only
    • has many TenantReviewSection
    • has many ReviewPack export artifacts if export history is retained per review
  • Validation rules:
    • workspace_id and tenant_id must match the anchored evidence snapshot
    • exactly one active evidence basis per review
    • published reviews cannot be mutated in place
    • archived reviews cannot return to draft/ready
  • State transitions:
    • draft -> ready
    • draft -> failed
    • ready -> published
    • ready -> failed
    • published -> superseded
    • published -> archived
    • ready -> archived
    • terminal: archived, superseded

TenantReviewSection

  • Purpose: Ordered section-level composition for one tenant review.
  • Ownership: Tenant-owned through tenant_review_id; redundantly stores workspace_id and tenant_id for isolation and query simplicity.
  • Core fields:
    • id
    • tenant_review_id
    • workspace_id
    • tenant_id
    • section_key enum-like string such as executive_summary, open_risks, accepted_risks, permission_posture, baseline_drift_posture, operations_health
    • title
    • sort_order
    • required boolean
    • completeness_state
    • source_snapshot_fingerprint nullable
    • summary_payload JSONB
    • render_payload JSONB
    • measured_at nullable timestamp
    • created_at, updated_at
  • Relationships:
    • belongs to TenantReview
  • Validation rules:
    • unique per tenant_review_id + section_key
    • sort_order must be stable and non-negative
    • summary_payload and render_payload must be sanitized, summary-first, and secret-free

ReviewPack (existing, extended)

  • Purpose: Existing export artifact reused as the stakeholder-facing executive pack output.
  • Change in this feature:
    • add tenant_review_id nullable foreign key
    • treat executive-pack exports as review-derived artifacts when tenant_review_id is present
  • Important existing fields reused:
    • workspace_id, tenant_id
    • operation_run_id
    • evidence_snapshot_id
    • status
    • fingerprint
    • options
    • file_disk, file_path, file_size, sha256
    • generated_at, expires_at
  • State transitions:
    • existing queued -> generating -> ready|failed -> expired
    • derived from review export pipeline, not from review publication state itself

Derived Views

Workspace Review Register Row

  • Purpose: Canonical /admin/reviews row projection for entitled tenants only.
  • Fields:
    • tenant_id
    • tenant_name
    • review_id
    • review_status
    • completeness_state
    • published_at
    • generated_at
    • evidence_snapshot_id
    • has_ready_export
    • publish_blockers_count

Indexing / Constraints

  • tenant_reviews(workspace_id, tenant_id, created_at desc)
  • tenant_reviews(tenant_id, status, published_at desc)
  • partial unique index for one current mutable review per tenant_id if desired: status in ('draft','ready')
  • unique tenant_review_sections(tenant_review_id, section_key)
  • review_packs(tenant_review_id, generated_at desc)

Invariants

  • Tenant-owned review tables always include both workspace_id and tenant_id.
  • A published review is immutable.
  • A review always points to exactly one anchored evidence snapshot.
  • Review completeness is explicit and never inferred from pack readiness alone.
  • Export artifacts never become the source of truth for review content; they remain derived from TenantReview.