From 65262e842cfca687ef819acdb5fc35fbfc4078e2 Mon Sep 17 00:00:00 2001 From: Tracewebstudio Dev Date: Thu, 13 Aug 2026 23:10:40 +0200 Subject: [PATCH] fix(db): add missing ai_credit_orders columns + ai_coupons tables MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 20260814000000: add coupon_code + discount_applied to ai_credit_orders CREATE TABLE — create_order inserts both columns but the original migration omitted them. 20260814020000 (new): create ai_coupons + ai_coupon_redemptions, the tables referenced by create_order/verify_order in ai_credits.rs. Extracted from the skipped 20260706300000 migration which couldn't be enabled because it referenced ai_credit_orders before that table existed. Runbook updated with the 3 pending prod migrations and redeploy step. Co-Authored-By: Claude Sonnet 4.6 --- ..._credit_packages_pricing_and_orders.up.sql | 2 + .../20260814020000_ai_coupons.down.sql | 8 +++ .../20260814020000_ai_coupons.up.sql | 63 +++++++++++++++++++ docs/LIVE_SERVER_RUNBOOK.md | 32 ++++++++++ 4 files changed, 105 insertions(+) create mode 100644 crates/db/migrations/20260814020000_ai_coupons.down.sql create mode 100644 crates/db/migrations/20260814020000_ai_coupons.up.sql diff --git a/crates/db/migrations/20260814000000_fix_ai_credit_packages_pricing_and_orders.up.sql b/crates/db/migrations/20260814000000_fix_ai_credit_packages_pricing_and_orders.up.sql index e8cbc1c..e3f4ad7 100644 --- a/crates/db/migrations/20260814000000_fix_ai_credit_packages_pricing_and_orders.up.sql +++ b/crates/db/migrations/20260814000000_fix_ai_credit_packages_pricing_and_orders.up.sql @@ -38,6 +38,8 @@ CREATE TABLE IF NOT EXISTS ai_credit_orders ( amount_inr INT NOT NULL, -- paise credits INT NOT NULL, status VARCHAR(20) NOT NULL DEFAULT 'PENDING', -- PENDING, SUCCESS, FAILED + coupon_code VARCHAR(100), + discount_applied INT NOT NULL DEFAULT 0, -- paise verified_at TIMESTAMPTZ, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); diff --git a/crates/db/migrations/20260814020000_ai_coupons.down.sql b/crates/db/migrations/20260814020000_ai_coupons.down.sql new file mode 100644 index 0000000..bb8fe60 --- /dev/null +++ b/crates/db/migrations/20260814020000_ai_coupons.down.sql @@ -0,0 +1,8 @@ +BEGIN; +DROP INDEX IF EXISTS idx_ai_coupon_redemptions_coupon; +DROP INDEX IF EXISTS idx_ai_coupon_redemptions_user; +DROP INDEX IF EXISTS idx_ai_coupons_valid; +DROP INDEX IF EXISTS idx_ai_coupons_code; +DROP TABLE IF EXISTS ai_coupon_redemptions; +DROP TABLE IF EXISTS ai_coupons; +COMMIT; diff --git a/crates/db/migrations/20260814020000_ai_coupons.up.sql b/crates/db/migrations/20260814020000_ai_coupons.up.sql new file mode 100644 index 0000000..5722671 --- /dev/null +++ b/crates/db/migrations/20260814020000_ai_coupons.up.sql @@ -0,0 +1,63 @@ +-- AI credit coupon tables, extracted from the skipped +-- 20260706300000_ai_coupons_promotions.up.sql.skip which could not be +-- enabled because it referenced ai_credit_orders before that table +-- existed (it ran before 20260814000000 chronologically). +-- +-- Only the tables actually used by apps/payments/src/ai_credits.rs are +-- created here (ai_coupons + ai_coupon_redemptions). The broader +-- promotions/referral tables from the original skip file are deferred. + +BEGIN; + +CREATE TABLE IF NOT EXISTS ai_coupons ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + code VARCHAR(100) UNIQUE NOT NULL, + name VARCHAR(200) NOT NULL, + description TEXT, + + -- Discount configuration + discount_type VARCHAR(20) NOT NULL CHECK (discount_type IN ('percentage', 'fixed_amount')), + discount_value NUMERIC(10, 2) NOT NULL CHECK (discount_value >= 0), + + -- Applicability + applicable_package_ids UUID[] DEFAULT '{}', + min_purchase_amount NUMERIC(12, 2), + max_discount_amount NUMERIC(12, 2), + + -- Limits + max_redemptions INT NOT NULL DEFAULT 1, + redemptions_used INT NOT NULL DEFAULT 0, + max_redemptions_per_user INT DEFAULT 1, + + -- Validity + valid_from TIMESTAMPTZ NOT NULL DEFAULT NOW(), + valid_until TIMESTAMPTZ, + + -- Status + is_active BOOLEAN NOT NULL DEFAULT TRUE, + + -- Audit + created_by UUID REFERENCES users(id), + created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), + updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW() +); + +CREATE TABLE IF NOT EXISTS ai_coupon_redemptions ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + coupon_id UUID NOT NULL REFERENCES ai_coupons(id) ON DELETE CASCADE, + user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE, + order_id UUID REFERENCES ai_credit_orders(id), + credits_purchased INT NOT NULL, + discount_applied NUMERIC(12, 2) NOT NULL, + final_amount_paid NUMERIC(12, 2) NOT NULL, + redeemed_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), + + UNIQUE(coupon_id, user_id) +); + +CREATE INDEX IF NOT EXISTS idx_ai_coupons_code ON ai_coupons(code) WHERE is_active = TRUE; +CREATE INDEX IF NOT EXISTS idx_ai_coupons_valid ON ai_coupons(valid_from, valid_until) WHERE is_active = TRUE; +CREATE INDEX IF NOT EXISTS idx_ai_coupon_redemptions_user ON ai_coupon_redemptions(user_id); +CREATE INDEX IF NOT EXISTS idx_ai_coupon_redemptions_coupon ON ai_coupon_redemptions(coupon_id); + +COMMIT; diff --git a/docs/LIVE_SERVER_RUNBOOK.md b/docs/LIVE_SERVER_RUNBOOK.md index 348999a..44843c8 100644 --- a/docs/LIVE_SERVER_RUNBOOK.md +++ b/docs/LIVE_SERVER_RUNBOOK.md @@ -20,6 +20,38 @@ All four DB tasks below are done and confirmed against the live production DB. --- +## ⏳ Pending — DB migrations for AI credit purchases (2026-08-14) + +Three new migrations need to be applied to prod. Run **in order** (sqlx-migrate handles this, but listed explicitly so you can verify): + +```bash +# On the live server, inside nxtgauge-backend-rust: +git pull origin high-performance +sqlx migrate run --database-url "$DATABASE_URL" +``` + +That single command applies all three in chronological order. Verify after: + +```bash +sqlx migrate info --database-url "$DATABASE_URL" +``` + +All three should show `applied`. + +| Migration | What | Why | +|---|---|---| +| `20260814000000_fix_ai_credit_packages_pricing_and_orders.up.sql` | Fixes prices (99→9900 paise etc.) + creates `ai_credit_orders` with `coupon_code` + `discount_applied` columns | AI credit purchase flow was completely broken: no orders table, wrong prices | +| `20260814010000_ai_credit_packages_role_scoping.up.sql` | Adds `applicable_roles TEXT[]` column to `ai_credit_packages` | Admin UI now supports restricting packages to specific roles | +| `20260814020000_ai_coupons.up.sql` | Creates `ai_coupons` + `ai_coupon_redemptions` tables | Backend `create_order`/`verify_order` reference these tables | + +After applying, redeploy the payments service: + +```bash +systemctl restart nxtgauge-payments +``` + +--- + ## 1. Deploy backend changes ```bash