-- Create order_reviews table CREATE TABLE IF NOT EXISTS order_reviews ( id SERIAL PRIMARY KEY, transaction_id INTEGER NOT NULL UNIQUE REFERENCES transactions(id) ON DELETE CASCADE, rating TEXT, order_again BOOLEAN, note TEXT, item_verdicts JSONB NOT NULL DEFAULT '[]', created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); -- Add source_message_id to expense_metadata ALTER TABLE expense_metadata ADD COLUMN IF NOT EXISTS source_message_id TEXT; -- 1. Admit 'credits' as a payment method. ALTER TABLE transactions DROP CONSTRAINT IF EXISTS transactions_payment_method_check; ALTER TABLE transactions ADD CONSTRAINT transactions_payment_method_check CHECK (payment_method IS NULL OR payment_method IN ('card','cash','bank_transfer','credits','other')); -- 2. Idempotency key (I7). Partial: rows without an order_reference -- (manual entries) are unaffected. CREATE UNIQUE INDEX IF NOT EXISTS uq_expense_source_order ON expense_metadata (source, order_reference) WHERE order_reference IS NOT NULL; -- 3. I1 as a database-level guard, not just workflow logic. -- Scoped to pipeline-created rows so manual/statement rows are untouched. ALTER TABLE transactions DROP CONSTRAINT IF EXISTS chk_ingested_orders_after_cutover; ALTER TABLE transactions ADD CONSTRAINT chk_ingested_orders_after_cutover CHECK ( payment_method IS DISTINCT FROM 'credits' OR transaction_date >= DATE '2026-01-09' ); -- 4. Constrain the review verdict (ยง6.1). ALTER TABLE order_reviews DROP CONSTRAINT IF EXISTS chk_order_review_rating; ALTER TABLE order_reviews ADD CONSTRAINT chk_order_review_rating CHECK (rating IS NULL OR rating IN ('again','fine','never'));