# Data Model: Backup/Restore Job Orchestration (049) This feature relies on existing “run record” models/tables and (optionally) extends them to meet the orchestration requirements. ## Entities ## 1) RestoreRun (`restore_runs`) **Purpose:** Run record for restore executions and dry-run/preview workflows. **Model:** `App\Models\RestoreRun` **Key fields (existing):** - `id` (PK) - `tenant_id` (FK → tenants) - `backup_set_id` (FK → backup_sets) - `requested_by` (string|null) - `is_dry_run` (bool) - `status` (string) - `requested_items` (json|null) - `preview` (json|null) — persisted preview output - `results` (json|null) — persisted execution output (may include per-item outcomes) - `failure_reason` (text|null) - `started_at` / `completed_at` (timestamp|null) - `metadata` (json|null) **Relationships:** - `RestoreRun belongsTo Tenant` - `RestoreRun belongsTo BackupSet` **State transitions (target):** - `queued → running → succeeded|failed|partial` **Validation constraints (creation/dispatch):** - tenant-scoped access required - `backup_set_id` must belong to tenant - preview/dry-run must not perform writes (constitution Read/Write Separation) --- ## 2) BulkOperationRun (`bulk_operation_runs`) **Purpose:** Run record for background operations that process many internal items, including backup-set capture-like actions. **Model:** `App\Models\BulkOperationRun` **Key fields (existing):** - `id` (PK) - `tenant_id` (FK → tenants) - `user_id` (FK → users) - `resource` (string) — e.g. `policy`, `backup_set` - `action` (string) — e.g. `export`, `add_policies` - `status` (string) — `pending`, `running`, `completed`, `completed_with_errors`, `failed`, `aborted` - `total_items`, `processed_items`, `succeeded`, `failed`, `skipped` - `item_ids` (jsonb) - `failures` (jsonb|null) — safe per-item error summaries - `audit_log_id` (FK → audit_logs|null) **Relationships:** - `BulkOperationRun belongsTo Tenant` - `BulkOperationRun belongsTo User` **Recommended additions (to satisfy FR-002/FR-004 cleanly):** - `idempotency_key` (string, indexed; uniqueness enforced for active statuses via partial index) - `started_at` / `finished_at` (timestampTz) - `error_code` (string|null) - `error_context` (jsonb|null) **State transitions (target):** - `queued → running → succeeded|failed|partial` - `pending` maps to `queued` - `completed_with_errors` maps to `partial` --- ## 3) Notification Event (DB notifications) **Purpose:** Persist state transitions and completion notices for the initiating user. **Storage:** Laravel Notifications (DB channel). **Payload shape (target):** - `tenant_id` - `run_type` (restore_run / bulk_operation_run) - `run_id` - `status` (queued/running/succeeded/failed/partial) - `counts` (optional) - `safe_error_code` + `safe_error_context` (optional) ## Notes on “per-item outcomes” (FR-005) - For restore workflows, per-item outcomes can initially be stored in `restore_runs.results` as a structured JSON array/object keyed by internal item identifiers. - For bulk operations, per-item outcomes are already persisted as `bulk_operation_runs.failures` plus the counter columns. - If Phase 1 needs relational per-item tables for querying/filtering, introduce a dedicated “run item results” table per run type (Phase 2+ preferred).