-- v1.0.9 Item G — subscription pending_payment state machine.
--
-- The user_subscriptions.status column is a free-text VARCHAR(30) with
-- no DB-level enum, so the new 'pending_payment' value introduced by
-- the Go const StatusPendingPayment requires no DDL. This migration is
-- documentation + an index that the future reconciliation worker
-- (Phase 2) needs to find rows stuck in pending_payment past the
-- webhook-arrival window.
--
-- Index strategy : a partial index on (created_at) WHERE status =
-- 'pending_payment' is the smallest possible footprint that still
-- gives the reconciler an O(log N) scan for "rows older than 30m
-- that haven't transitioned yet". A non-partial composite index would
-- pay storage cost for every row in the table; partial keeps it
-- proportional to the in-flight set.
--
-- CONCURRENTLY is intentionally not used: the migration runner wraps
-- each migration in a single transaction (database.go:390) and
-- Postgres forbids CREATE INDEX CONCURRENTLY inside a transaction
-- block. The partial WHERE clause keeps this index tiny (only rows
-- currently in pending_payment), so the brief AccessExclusiveLock
-- taken by the non-concurrent variant resolves in milliseconds —
-- comfortably shorter than any human-noticeable migration window.
-- If pending_payment cardinality grows large enough to matter, switch
-- to a manual two-step deploy (DDL outside the migration runner).

CREATE INDEX IF NOT EXISTS idx_user_subscriptions_pending_payment
    ON user_subscriptions (created_at)
    WHERE status = 'pending_payment';

COMMENT ON INDEX idx_user_subscriptions_pending_payment IS
    'v1.0.9 Item G — feeds the subscription reconciliation sweep that catches rows stuck in pending_payment past the webhook deadline.';
