-- v1.0.6.2: Void subscription rows that sit in active/trialing state without -- any effective payment linkage. Introduced to compensate for a bypass where -- POST /subscribe could create 'active' rows on paid plans without invoking -- the payment provider (e.g., when HYPERSWITCH_ENABLED=false or provider -- unset). The runtime filter in GetUserSubscription (service.go) closes the -- feature bypass going forward; this migration cleans up the rows already -- written to the database pre-v1.0.6.2. -- -- Fantôme selection criteria: -- 1. status IN ('active', 'trialing') -- 2. plan is paid (subscription_plans.price_monthly_cents > 0) -- 3. no invoice attached carries a hyperswitch_payment_id (= PSP never reached) -- 4. not a currently-valid trial (trial_end > NOW()) -- -- Audit table is dated so a future rerun doesn't collide. Rows here can be -- used to notify affected users (if any were honest-path). CREATE TABLE IF NOT EXISTS voided_subscriptions_20260417 ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), subscription_id UUID NOT NULL, user_id UUID NOT NULL, plan_id UUID NOT NULL, previous_status VARCHAR(30) NOT NULL, voided_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); CREATE INDEX IF NOT EXISTS idx_voided_subscriptions_20260417_user ON voided_subscriptions_20260417(user_id); INSERT INTO voided_subscriptions_20260417 (subscription_id, user_id, plan_id, previous_status) SELECT us.id, us.user_id, us.plan_id, us.status FROM user_subscriptions us JOIN subscription_plans sp ON sp.id = us.plan_id WHERE us.status IN ('active', 'trialing') AND sp.price_monthly_cents > 0 AND NOT EXISTS ( SELECT 1 FROM subscription_invoices si WHERE si.subscription_id = us.id AND si.hyperswitch_payment_id IS NOT NULL AND si.hyperswitch_payment_id <> '' ) AND NOT ( us.status = 'trialing' AND us.trial_end IS NOT NULL AND us.trial_end > NOW() ); UPDATE user_subscriptions SET status = 'expired', canceled_at = COALESCE(canceled_at, NOW()), updated_at = NOW() WHERE id IN (SELECT subscription_id FROM voided_subscriptions_20260417); DO $$ DECLARE v_count INTEGER; BEGIN SELECT COUNT(*) INTO v_count FROM voided_subscriptions_20260417; RAISE NOTICE 'v1.0.6.2: voided % pre-existing unpaid subscription row(s)', v_count; END $$;