# Data Model: Cross-Resource Navigation & Drill-Down Cohesion

**Feature**: 131-cross-resource-navigation | **Date**: 2026-03-10

## Overview

This feature introduces no new database tables. It adds a shared navigation read model and relation-mapping layer over existing workspace-owned and tenant-owned records.

The design relies on existing persisted entities plus a small set of computed presentation concepts:

1. a navigation matrix defining allowed operator journeys,
2. related-context sections on key detail pages,
3. list-level drill-down actions,
4. canonical destination context for operations and other authoritative pages,
5. explicit unavailable-state handling for missing or unauthorized relations.

## Existing Persistent Entities

### Policy

| Attribute | Type | Notes |
|-----------|------|-------|
| `id` | int | Primary internal policy identity |
| `tenant_id` | int | Tenant ownership boundary |
| `workspace_id` | int | Workspace ownership boundary |
| `display_name` | string nullable | Primary human-readable label for navigation |
| `policy_type` | string | Policy-type hint used in labels and filtered destinations |

**Relationships**:
- has many `PolicyVersion`
- may be referenced by findings, backup items, and operation runs through context or foreign keys

**Usage rules**:
- Parent policy is the default upstream destination from a policy version.
- Policy links must remain tenant-entitlement checked.

### PolicyVersion

| Attribute | Type | Notes |
|-----------|------|-------|
| `id` | int | Primary version identity |
| `policy_id` | int nullable | Parent policy relationship |
| `tenant_id` | int | Tenant ownership boundary |
| `workspace_id` | int | Workspace ownership boundary |
| `version_number` | int or string | Displayed as user-facing version context |
| `captured_at` | timestamp | Useful for evidence-related context |

**Relationships**:
- belongs to `Policy`
- may be referenced from baseline snapshot items or backup items

**Usage rules**:
- Policy version detail must expose parent policy and related snapshot evidence where resolvable.
- When the parent policy cannot be opened, the page must still preserve readable version context.

### BaselineProfile

| Attribute | Type | Notes |
|-----------|------|-------|
| `id` | int | Primary workspace-owned baseline profile identity |
| `workspace_id` | int | Workspace ownership boundary |
| `name` | string | Primary label |
| `status` | string | Badge-backed profile state |
| `capture_mode` | string | Useful supporting context on related pages |

**Relationships**:
- has many `BaselineSnapshot`
- may be indirectly referenced by findings and operation runs

**Usage rules**:
- Baseline profile is the primary upstream destination from a baseline snapshot.
- Baseline profile links are workspace-authorized, not tenant-authorized.

### BaselineSnapshot

| Attribute | Type | Notes |
|-----------|------|-------|
| `id` | int | Primary snapshot identity |
| `workspace_id` | int | Workspace ownership boundary |
| `baseline_profile_id` | int | Owning baseline profile |
| `captured_at` | timestamp | Primary temporal context |
| `summary_jsonb` | jsonb | Existing summary and fidelity metadata |

**Relationships**:
- belongs to `BaselineProfile`
- may reference policy versions and source operation runs through existing summary or evidence metadata
- may be linked to related findings

**Usage rules**:
- Snapshot detail must expose owning profile, source run, and related findings where meaningful and authorized.
- Snapshot remains workspace-owned even when it refers to tenant evidence.

### Finding

| Attribute | Type | Notes |
|-----------|------|-------|
| `id` | int | Primary finding identity |
| `tenant_id` | int | Tenant ownership boundary |
| `workspace_id` | int | Workspace ownership boundary |
| `finding_type` | string | Used for operator context and prioritization |
| `subject_display_name` | string nullable | Existing human-readable subject label |
| `baseline_operation_run_id` | int nullable | Existing related operations link |
| `current_operation_run_id` | int nullable | Existing related operations link |
| `evidence_jsonb` | jsonb | Existing source-evidence context |

**Relationships**:
- may point to baseline snapshots, policy versions, policies, inventory items, and runs through evidence metadata and explicit IDs

**Usage rules**:
- Findings are high-priority drill-down surfaces and must not degrade into raw IDs when source evidence is resolvable.
- Findings remain tenant-authorized even when they link to workspace-owned baseline records.

### BackupSet

| Attribute | Type | Notes |
|-----------|------|-------|
| `id` | int | Primary backup set identity |
| `tenant_id` | int | Tenant ownership boundary |
| `workspace_id` | int | Workspace ownership boundary |
| `name` | string | Primary operator label |
| `status` | string | Existing badge-backed lifecycle state |
| `item_count` | int | Supporting list context |

**Relationships**:
- has many backup items
- may be referenced by operation-run context and restore flows

**Usage rules**:
- Backup set pages should expose related operation runs or resulting artifacts when available.
- Backup-related navigation must stay consistent with canonical operations routing.

### OperationRun

| Attribute | Type | Notes |
|-----------|------|-------|
| `id` | int | Canonical run identity |
| `workspace_id` | int | Workspace ownership boundary |
| `tenant_id` | int nullable | Nullable for some workspace-level operations |
| `type` | string | Operation type driving related destinations |
| `status` | string | Existing run status badge |
| `outcome` | string nullable | Existing outcome badge |
| `context` | json/jsonb | Existing target-resource and workflow metadata |

**Relationships**:
- may point to policies, backup sets, restore runs, baseline compare destinations, and other domain records via context

**Usage rules**:
- `OperationRun` is the canonical operational drill-down target.
- Related domain links should be generated from run context only when target authorization can be proven.

## New Computed Read Models

### NavigationMatrixRule

| Field | Type | Description |
|------|------|-------------|
| `source_type` | string | Resource or page type that owns the navigation surface |
| `source_surface` | string enum | `detail_section`, `detail_header`, `list_row`, `canonical_list` |
| `relation_key` | string | Stable semantic relation identifier, e.g. `source_run`, `parent_policy` |
| `target_type` | string | Destination resource or page type |
| `target_mode` | string enum | `direct_record`, `filtered_list`, `canonical_page` |
| `label` | string | Shared operator-facing action or entry label |
| `priority` | int | Lower number = higher visibility priority |
| `requires_capability_check` | bool | Whether actionability depends on explicit authorization |
| `missing_state_policy` | string enum | `hide`, `show_unavailable`, `show_reference_only` |

**Rules**:
- Every in-scope relationship in the spec’s navigation matrix maps to one rule.
- Rules choose only one canonical destination for the same operator task.

### RelatedContextSection

| Field | Type | Description |
|------|------|-------------|
| `title` | string | Usually `Related context` or a narrow equivalent |
| `entries` | list<RelatedContextEntry> | Ordered related records for the current page |
| `primary_entry_key` | string nullable | Optional marker for the most likely next step |
| `empty_message` | string nullable | Optional empty-state copy when no related entries are available |

**Rules**:
- Detail pages should render one structured section rather than scattering relation fields.
- Entries are ordered by operator relevance, not by storage order.

### RelatedContextEntry

| Field | Type | Description |
|------|------|-------------|
| `key` | string | Stable identifier such as `source_run` or `baseline_profile` |
| `label` | string | User-facing relation label |
| `value` | string | Human-readable related object label |
| `secondary_value` | string nullable | Optional technical ID or context hint |
| `target_url` | string nullable | Drill-down destination when actionable |
| `target_kind` | string | Resource or canonical page type |
| `availability` | string enum | `available`, `missing`, `unauthorized`, `unresolved` |
| `unavailable_reason` | string nullable | User-safe explanation when not actionable |
| `context_badge` | string nullable | Optional workspace, tenant, or type hint |

**Rules**:
- `value` should favor human-readable labels over raw IDs.
- Technical identifiers may appear only as secondary supporting context.

### DrillDownAction

| Field | Type | Description |
|------|------|-------------|
| `label` | string | Shared operator-facing action label |
| `url` | string | Target destination |
| `placement` | string enum | `row_action`, `header_action`, `inline_entry`, `grouped_action` |
| `priority` | int | Governs whether it appears inline or only in grouped context |
| `target_kind` | string | Destination type |
| `visible` | bool | Whether action should be rendered at all |
| `disabled_reason` | string nullable | Optional tooltip or unavailable-state explanation |

**Rules**:
- No more than the highest-priority actions should remain visibly inline on list rows.
- Actions to canonical operations pages must resolve through the canonical helper layer.

### CanonicalNavigationContext

| Field | Type | Description |
|------|------|-------------|
| `workspace_id` | int | Active workspace scope |
| `tenant_id` | int nullable | Originating tenant context if preserved |
| `source_surface` | string | Resource or page that launched the navigation |
| `canonical_route_name` | string | Authoritative destination route name |
| `filter_payload` | array | Context-preserving query or filter state |
| `back_link_label` | string nullable | Explicit return path label |

**Rules**:
- Canonical route identity must remain stable even when tenant context is preserved.
- This model is especially important for operations and monitoring surfaces.

### UnavailableRelationState

| Field | Type | Description |
|------|------|-------------|
| `relation_key` | string | Relation that could not be resolved |
| `reference_value` | string nullable | Technical identifier or fallback reference |
| `reason` | string enum | `missing`, `deleted`, `unauthorized`, `unresolved` |
| `message` | string | User-facing explanation |
| `show_reference` | bool | Whether the secondary reference is safe to display |

**Rules**:
- Unauthorized states must not disclose more than existing access rules allow.
- Missing and unresolved states must preserve surrounding page usability and layout.

## Validation Rules

| Rule | Result |
|------|--------|
| Every in-scope relationship resolves through one explicit navigation-matrix rule | Required |
| Canonical run destinations always use the tenantless operations route family | Required |
| Non-members receive 404 semantics for target resources | Required |
| In-scope members lacking capability may see disabled or unavailable context, but target execution still fails with 403 | Required |
| Related-context entries show human-readable labels first and technical IDs second | Required |
| List-level drill-down actions remain limited to the highest-priority operator journeys | Required |
| Missing or unresolved relations render clear unavailable states without broken links | Required |

## Schema Impact

No schema migration is expected for this feature.