# Data Model: SoT Foundations & Assignments (006)

This feature reuses existing snapshot and restore run entities, and introduces a consistent JSON “mapping + decisions” report.

## Existing Entities (today)

### BackupSet

- Purpose: Groups a point-in-time capture for a tenant.
- Relationships: hasMany `BackupItem`.

### BackupItem

- Purpose: Stores an immutable snapshot item.
- Key fields (relevant):
  - `tenant_id`, `backup_set_id`
  - `policy_id` (nullable)
  - `policy_identifier` (Graph id)
  - `policy_type` (logical type)
  - `payload` (raw JSON)
  - `metadata` (normalized JSON)

### RestoreRun

- Purpose: Tracks restore preview/execution lifecycle.
- Key fields (relevant):
  - `is_dry_run`
  - `requested_items` (selection)
  - `preview` (dry-run decision report)
  - `results` (execution report)
  - `metadata` (extra structured info)

## New / Extended Concepts (this feature)

### FoundationSnapshot (logical concept)

Represented as a `backup_items` row.

- `policy_type` (new keys):
  - `assignmentFilter`
  - `roleScopeTag`
  - `notificationMessageTemplate`
- `policy_identifier`: source Graph `id`
- `policy_id`: `null`
- `payload`: raw Graph resource JSON
- `metadata` (proposed, shape):

  ```json
  {
    "displayName": "...",
    "kind": "assignmentFilter|roleScopeTag|notificationMessageTemplate",
    "graph": {
      "resource": "deviceManagement/assignmentFilters",
      "apiVersion": "v1.0"
    }
  }
  ```

### RestoreMappingReport (logical concept)

Stored within `restore_runs.preview`/`restore_runs.results`.

- `mappings.foundations[]` (proposed shape):

  ```json
  {
    "type": "assignmentFilter",
    "sourceId": "<old-guid>",
    "sourceName": "Filter A",
    "decision": "mapped_existing|created|created_copy|failed",
    "targetId": "<new-guid>",
    "targetName": "Filter A (Copy)",
    "reason": "..."
  }
  ```

### AssignmentDecisionReport (logical concept)

Stored within `restore_runs.preview`/`restore_runs.results`.

- `assignments[]` entries (proposed shape):

  ```json
  {
    "policyType": "settingsCatalogPolicy",
    "sourcePolicyId": "...",
    "targetPolicyId": "...",
    "decision": "applied|skipped|failed",
    "reason": "missing_filter_mapping|missing_group_mapping|preview_only|graph_error",
    "details": {
      "sourceAssignmentCount": 3,
      "appliedAssignmentCount": 2
    }
  }
  ```

## Relationships / Flow

- `BackupSet` contains both “policy snapshots” and “foundation snapshots” as `BackupItem` rows.
- `RestoreRun` consumes a `BackupSet` and produces:
  - foundation mapping report
  - policy restore decisions
  - assignment application decisions

## Validation & State Transitions

- Restore execution is single-writer per tenant (existing safety requirement FR-009).
- Restore behavior:
  - Preview (`is_dry_run=true`): builds mapping/decisions, **no Graph writes**.
  - Execute (`is_dry_run=false`): creates missing foundations, restores policies, applies assignments when safe.
  - Conditional Access entries are always recorded as preview-only/skipped in execute.
