""" Migration: add `removed_at` + `removal_reason` columns to `monitoring_locations`. Lets operators mark a location as no longer actively monitored without deleting it (so historical events stay attributed correctly). Mirrors the timestamp-based "closed state" pattern already used by `unit_assignments.assigned_until`. Behavior: - `removed_at IS NULL` → location is active (default for all existing rows after this migration) - `removed_at` set → location is removed; historical events still attribute to it but it's hidden from active surfaces (assign dropdowns, calendar, etc.) - `removal_reason` → optional operator note (e.g. "client dropped from scope") Idempotent — safe to re-run. Non-destructive — adds only. Run with: docker exec terra-view-terra-view-1 python3 /app/backend/migrate_add_location_removed.py """ import os import sqlite3 DB_PATH = "./data/seismo_fleet.db" def _has_column(cur: sqlite3.Cursor, table: str, column: str) -> bool: cur.execute(f"PRAGMA table_info({table})") return any(row[1] == column for row in cur.fetchall()) def migrate_database() -> None: if not os.path.exists(DB_PATH): print(f"Database not found at {DB_PATH}") return conn = sqlite3.connect(DB_PATH) cur = conn.cursor() added = [] if not _has_column(cur, "monitoring_locations", "removed_at"): cur.execute("ALTER TABLE monitoring_locations ADD COLUMN removed_at DATETIME") added.append("removed_at") if not _has_column(cur, "monitoring_locations", "removal_reason"): cur.execute("ALTER TABLE monitoring_locations ADD COLUMN removal_reason TEXT") added.append("removal_reason") conn.commit() conn.close() if added: print(f" Added columns to monitoring_locations: {', '.join(added)}") else: print(" monitoring_locations already has removed_at + removal_reason — nothing to do.") if __name__ == "__main__": print("Running migration: add removed_at + removal_reason to monitoring_locations") migrate_database() print("Done.")