-- Migration: 009_session_machine_soft_delete.sql
-- Purpose: Give connect_machines and connect_sessions a soft-delete marker
--          (deleted_at) so an operator can PURGE a stale machine/session —
--          removing it from the live console — without destroying its audit
--          history (SPEC-004 / v2-stable-identity Task 5).
--
--   Task 5 is the operator-removal mechanism that finally purges the ~14 live
--   ghost connect_machines rows left by the duplicate-registration bug. The
--   live-only admin "disconnect" (DELETE /api/sessions/:id) and the legacy hard
--   DELETE /api/machines/:agent_id stay as they were; the NEW purge path
--   (`?purge=true`) sets deleted_at, drops the in-memory session via
--   SessionManager::remove_session, and writes an audit row. A soft delete keeps
--   the row (and its connect_session_events history) for the audit trail per the
--   project convention "prefer deleted_at over hard deletes" (CLAUDE.md), while
--   every list/get query filters `deleted_at IS NULL` so the purged unit
--   disappears from the dashboard and the startup reconcile never restores it.
--
-- Idempotent: ADD COLUMN IF NOT EXISTS. The columns are NULLABLE with no default,
-- so adding them is a metadata-only change on Postgres (no table rewrite, no row
-- locks held for a scan) — safe to apply online. A NULL deleted_at means "live";
-- a non-null timestamp means "removed at that instant". Applied on server startup
-- by sqlx::migrate!(); never pre-applied via psql. Ordered after 008.
-- See .claude/standards/gururmm/sqlx-migrations.md.

-- 1. connect_sessions.deleted_at: when set, the session was operator-purged and is
--    excluded from every list/get query. NULL = live.
ALTER TABLE connect_sessions ADD COLUMN IF NOT EXISTS deleted_at TIMESTAMPTZ;

-- 2. connect_machines.deleted_at: when set, the machine was operator-purged. This
--    is the marker that hides the ghost duplicate rows from /api/machines and the
--    startup reconcile. NULL = live.
ALTER TABLE connect_machines ADD COLUMN IF NOT EXISTS deleted_at TIMESTAMPTZ;

-- 3. Partial indexes so the hot "live rows only" filter (deleted_at IS NULL) used
--    by every list query stays an index scan as the soft-deleted set grows. The
--    predicate matches the WHERE clause the queries use.
CREATE INDEX IF NOT EXISTS idx_connect_machines_live
    ON connect_machines (hostname)
    WHERE deleted_at IS NULL;

CREATE INDEX IF NOT EXISTS idx_connect_sessions_live
    ON connect_sessions (started_at DESC)
    WHERE deleted_at IS NULL;
