TenantAtlas/specs/087-legacy-runs-removal/data-model.md
ahmido d6e7de597a feat(spec-087): remove legacy runs (#106)
Implements Spec 087: Legacy Runs Removal (rigorous).

### What changed
- Canonicalized run history: **`operation_runs` is the only run system** for inventory sync, Entra group sync, backup schedule execution/retention/purge.
- Removed legacy UI surfaces (Filament Resources / relation managers) for legacy run models.
- Legacy run URLs now return **404** (no redirects), with RBAC semantics preserved (404 vs 403 as specified).
- Canonicalized affected `operation_runs.type` values (dotted → underscore) via migration.
- Drift + inventory references now point to canonical operation runs; includes backfills and then drops legacy FK columns.
- Drops legacy run tables after cutover.
- Added regression guards to prevent reintroducing legacy run tokens or “backfilling” canonical runs from legacy tables.

### Migrations
- `2026_02_12_000001..000006_*` canonicalize types, add/backfill operation_run_id references, drop legacy columns, and drop legacy run tables.

### Tests
Focused pack for this spec passed:
- `tests/Feature/Guards/NoLegacyRunsTest.php`
- `tests/Feature/Guards/NoLegacyRunBackfillTest.php`
- `tests/Feature/Operations/LegacyRunRoutesNotFoundTest.php`
- `tests/Feature/Monitoring/MonitoringOperationsTest.php`
- `tests/Feature/Jobs/RunInventorySyncJobTest.php`

### Notes / impact
- Destructive cleanup is handled via migrations (drops legacy tables) after code cutover; deploy should run migrations in the same release.

Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #106
2026-02-12 12:40:51 +00:00

110 lines
3.3 KiB
Markdown

# Phase 1 — Data Model: Legacy Runs Removal (Spec 087)
**Branch**: `087-legacy-runs-removal`
**Date**: 2026-02-12
## Canonical Entity: OperationRun
**Table**: `operation_runs`
**Model**: `App\\Models\\OperationRun`
Key fields (existing):
- `id`
- `workspace_id` (required)
- `tenant_id` (nullable; tenant-scoped runs use this)
- `user_id` (nullable)
- `initiator_name`
- `type` (canonical run_type)
- `status` / `outcome`
- `run_identity_hash` (idempotency)
- `summary_counts` (JSON)
- `failure_summary` (JSON)
- `context` (JSON)
- `started_at` / `completed_at`
- `created_at` / `updated_at`
Spec impact:
- `type` must be standardized to the underscore identifiers listed in FR-012.
## Legacy Entities (To Remove)
### InventorySyncRun
**Table**: `inventory_sync_runs`
**Model**: `App\\Models\\InventorySyncRun`
Notes:
- Acts as a legacy duplicate run store.
- Has `operation_run_id` bridge column (added later).
**Plan**: remove model + table, and rely on `operation_runs`.
### EntraGroupSyncRun
**Table**: `entra_group_sync_runs`
**Model**: `App\\Models\\EntraGroupSyncRun`
Notes:
- Legacy duplicate run store.
- Has `operation_run_id` bridge column.
**Plan**: remove model + table, and rely on `operation_runs`.
### BackupScheduleRun
**Table**: `backup_schedule_runs`
**Model**: `App\\Models\\BackupScheduleRun`
Notes:
- Currently used for schedule run history + retention/purge selection.
- Has `operation_run_id` bridge column.
**Plan**: remove model + table and replace schedule “run history” with querying `operation_runs` by type + context.
## Drift Findings: References Must Become Canonical
**Table**: `findings`
**Model**: `App\\Models\\Finding`
Current fields (relevant):
- `baseline_run_id` → FK to `inventory_sync_runs` (nullable)
- `current_run_id` → FK to `inventory_sync_runs` (nullable)
**Planned fields**:
- `baseline_operation_run_id` → FK to `operation_runs` (nullable)
- `current_operation_run_id` → FK to `operation_runs` (nullable)
**Backfill rule**:
- If `baseline_run_id` points to an `inventory_sync_runs` row with a non-null `operation_run_id`, and that `operation_runs` row exists, copy it.
- Same for `current_run_id`.
- Otherwise leave null (matches spec edge-case expectations).
## Inventory Items: Last Seen Run Reference Must Become Canonical
**Table**: `inventory_items`
**Model**: `App\\Models\\InventoryItem`
Current fields (relevant):
- `last_seen_run_id` → FK to `inventory_sync_runs` (nullable)
- `last_seen_operation_run_id` → FK to `operation_runs` (nullable; already exists)
**Plan**:
- Backfill `last_seen_operation_run_id` via `inventory_sync_runs.operation_run_id` where possible.
- Drop `last_seen_run_id` after code is migrated.
## Backup Schedules: Run History
**Table**: `backup_schedules`
**Model**: `App\\Models\\BackupSchedule`
Planned behavior:
- Remove `runs()` relationship that points to `backup_schedule_runs`.
- For UI/history, query `operation_runs` using:
- `type = backup_schedule_run|backup_schedule_retention|backup_schedule_purge`
- `context->backup_schedule_id = {id}` (and optionally scheduled time metadata)
## Validation Rules (from spec)
- All new run records created by this feature must have `type` in the FR-012 allow-list.
- Run visibility is workspace-scoped; non-members must be deny-as-not-found (404).