chitfund/backend/migrations/20260402_payments_audit_and...

53 lines
1.7 KiB
SQL

-- Payments invariants + audit log
-- Adds:
-- - payments.source / payments.entered_by / payments.idempotency_key
-- - payment_audit_events table
ALTER TABLE payments
ADD COLUMN IF NOT EXISTS source VARCHAR(32) NOT NULL DEFAULT 'manual_manager_entry',
ADD COLUMN IF NOT EXISTS entered_by UUID NULL,
ADD COLUMN IF NOT EXISTS idempotency_key VARCHAR(128) NULL;
-- Foreign key for entered_by
DO $$
BEGIN
IF NOT EXISTS (
SELECT 1 FROM pg_constraint WHERE conname = 'payments_entered_by_fkey'
) THEN
ALTER TABLE payments
ADD CONSTRAINT payments_entered_by_fkey
FOREIGN KEY (entered_by) REFERENCES users(id)
ON DELETE SET NULL;
END IF;
END $$;
-- Idempotency key uniqueness (global). If you prefer per-manager scoping,
-- change this to a composite unique index.
DO $$
BEGIN
IF NOT EXISTS (
SELECT 1 FROM pg_indexes WHERE indexname = 'payments_idempotency_key_unique'
) THEN
CREATE UNIQUE INDEX payments_idempotency_key_unique ON payments(idempotency_key) WHERE idempotency_key IS NOT NULL;
END IF;
END $$;
CREATE TABLE IF NOT EXISTS payment_audit_events (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
payment_id UUID NOT NULL REFERENCES payments(id) ON DELETE CASCADE,
actor_user_id UUID NULL REFERENCES users(id) ON DELETE SET NULL,
action VARCHAR(32) NOT NULL,
reason TEXT NULL,
"before" JSONB NULL,
"after" JSONB NULL,
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW()
);
CREATE INDEX IF NOT EXISTS payment_audit_events_payment_id_created_at_idx
ON payment_audit_events(payment_id, created_at DESC);
CREATE INDEX IF NOT EXISTS payment_audit_events_actor_user_id_created_at_idx
ON payment_audit_events(actor_user_id, created_at DESC);