-- CreateEnum CREATE TYPE "AdminStatus" AS ENUM ('ACTIVE', 'DISABLED'); -- CreateEnum CREATE TYPE "AdminRole" AS ENUM ('SUPER_ADMIN', 'OPERATOR', 'SUPPORT'); -- CreateEnum CREATE TYPE "UserStatus" AS ENUM ('ACTIVE', 'BLOCKED'); -- CreateEnum CREATE TYPE "CampaignStatus" AS ENUM ('DRAFT', 'ACTIVE', 'PAUSED', 'FINISHED'); -- CreateEnum CREATE TYPE "PrizeType" AS ENUM ('PHYSICAL', 'DISCOUNT_CODE', 'CREDIT', 'CASH', 'NO_PRIZE', 'OTHER'); -- CreateEnum CREATE TYPE "StockType" AS ENUM ('LIMITED', 'UNLIMITED'); -- CreateEnum CREATE TYPE "PrizeStatus" AS ENUM ('ACTIVE', 'INACTIVE'); -- CreateEnum CREATE TYPE "SpinStatus" AS ENUM ('SUCCESS', 'FAILED', 'DUPLICATE'); -- CreateEnum CREATE TYPE "ChanceTxnType" AS ENUM ('SIGNUP_BONUS', 'ADMIN_ADJUSTMENT', 'SPIN_CONSUME', 'CAMPAIGN_BONUS', 'REFUND'); -- CreateEnum CREATE TYPE "UserPrizeStatus" AS ENUM ('NEW', 'CONTACTED', 'DELIVERED', 'ACTIVE_CODE', 'USED', 'EXPIRED'); -- CreateEnum CREATE TYPE "SmsType" AS ENUM ('OTP', 'WINNING', 'NO_PRIZE', 'PRIZE_REMINDER'); -- CreateEnum CREATE TYPE "SmsStatus" AS ENUM ('PENDING', 'SENT', 'FAILED'); -- CreateEnum CREATE TYPE "WheelDesign" AS ENUM ('CLASSIC_CASINO', 'NEON_CYBER', 'MINIMAL_FLAT', 'LUXURY_GOLD', 'PLAYFUL_CARTOON'); -- CreateTable CREATE TABLE "admins" ( "id" TEXT NOT NULL, "name" TEXT NOT NULL, "mobile" TEXT NOT NULL, "email" TEXT NOT NULL, "password_hash" TEXT NOT NULL, "role" "AdminRole" NOT NULL DEFAULT 'OPERATOR', "status" "AdminStatus" NOT NULL DEFAULT 'ACTIVE', "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, "updated_at" TIMESTAMP(3) NOT NULL, CONSTRAINT "admins_pkey" PRIMARY KEY ("id") ); -- CreateTable CREATE TABLE "users" ( "id" TEXT NOT NULL, "mobile" TEXT NOT NULL, "name" TEXT, "status" "UserStatus" NOT NULL DEFAULT 'ACTIVE', "last_login_at" TIMESTAMP(3), "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, "updated_at" TIMESTAMP(3) NOT NULL, CONSTRAINT "users_pkey" PRIMARY KEY ("id") ); -- CreateTable CREATE TABLE "otp_codes" ( "id" TEXT NOT NULL, "mobile" TEXT NOT NULL, "code" TEXT NOT NULL, "user_id" TEXT, "attempts" INTEGER NOT NULL DEFAULT 0, "consumed" BOOLEAN NOT NULL DEFAULT false, "expires_at" TIMESTAMP(3) NOT NULL, "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, CONSTRAINT "otp_codes_pkey" PRIMARY KEY ("id") ); -- CreateTable CREATE TABLE "campaigns" ( "id" TEXT NOT NULL, "title" TEXT NOT NULL, "slug" TEXT NOT NULL, "description" TEXT, "image" TEXT, "banner" TEXT, "logo" TEXT, "start_at" TIMESTAMP(3) NOT NULL, "end_at" TIMESTAMP(3) NOT NULL, "status" "CampaignStatus" NOT NULL DEFAULT 'DRAFT', "default_chances" INTEGER NOT NULL DEFAULT 0, "rules" TEXT, "cta_text" TEXT, "wheel_design" "WheelDesign" NOT NULL DEFAULT 'CLASSIC_CASINO', "settings" JSONB, "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, "updated_at" TIMESTAMP(3) NOT NULL, CONSTRAINT "campaigns_pkey" PRIMARY KEY ("id") ); -- CreateTable CREATE TABLE "prizes" ( "id" TEXT NOT NULL, "campaign_id" TEXT NOT NULL, "title" TEXT NOT NULL, "description" TEXT, "image" TEXT, "type" "PrizeType" NOT NULL, "stock_type" "StockType" NOT NULL, "initial_stock" INTEGER, "remaining_stock" INTEGER, "weight" INTEGER NOT NULL, "status" "PrizeStatus" NOT NULL DEFAULT 'ACTIVE', "sort_order" INTEGER NOT NULL DEFAULT 0, "segment_color" TEXT NOT NULL, "expires_at" TIMESTAMP(3), "sms_template" TEXT, "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, "updated_at" TIMESTAMP(3) NOT NULL, CONSTRAINT "prizes_pkey" PRIMARY KEY ("id") ); -- CreateTable CREATE TABLE "user_campaigns" ( "id" TEXT NOT NULL, "user_id" TEXT NOT NULL, "campaign_id" TEXT NOT NULL, "total_chances" INTEGER NOT NULL DEFAULT 0, "used_chances" INTEGER NOT NULL DEFAULT 0, "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, "updated_at" TIMESTAMP(3) NOT NULL, CONSTRAINT "user_campaigns_pkey" PRIMARY KEY ("id") ); -- CreateTable CREATE TABLE "chance_transactions" ( "id" TEXT NOT NULL, "user_id" TEXT NOT NULL, "campaign_id" TEXT NOT NULL, "amount" INTEGER NOT NULL, "type" "ChanceTxnType" NOT NULL, "reference_type" TEXT, "reference_id" TEXT, "description" TEXT, "created_by" TEXT, "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, CONSTRAINT "chance_transactions_pkey" PRIMARY KEY ("id") ); -- CreateTable CREATE TABLE "spins" ( "id" TEXT NOT NULL, "user_id" TEXT NOT NULL, "campaign_id" TEXT NOT NULL, "prize_id" TEXT, "status" "SpinStatus" NOT NULL DEFAULT 'SUCCESS', "idempotency_key" TEXT NOT NULL, "ip" TEXT, "user_agent" TEXT, "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, CONSTRAINT "spins_pkey" PRIMARY KEY ("id") ); -- CreateTable CREATE TABLE "user_prizes" ( "id" TEXT NOT NULL, "user_id" TEXT NOT NULL, "campaign_id" TEXT NOT NULL, "prize_id" TEXT NOT NULL, "spin_id" TEXT NOT NULL, "code" TEXT, "status" "UserPrizeStatus" NOT NULL DEFAULT 'NEW', "won_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, "redeemed_at" TIMESTAMP(3), CONSTRAINT "user_prizes_pkey" PRIMARY KEY ("id") ); -- CreateTable CREATE TABLE "sms_logs" ( "id" TEXT NOT NULL, "user_id" TEXT, "mobile" TEXT NOT NULL, "type" "SmsType" NOT NULL, "message" TEXT NOT NULL, "provider" TEXT NOT NULL DEFAULT 'raygansms', "status" "SmsStatus" NOT NULL DEFAULT 'PENDING', "provider_response" JSONB, "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, CONSTRAINT "sms_logs_pkey" PRIMARY KEY ("id") ); -- CreateTable CREATE TABLE "admin_logs" ( "id" TEXT NOT NULL, "admin_id" TEXT NOT NULL, "action" TEXT NOT NULL, "entity_type" TEXT NOT NULL, "entity_id" TEXT NOT NULL, "old_value" JSONB, "new_value" JSONB, "ip" TEXT, "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, CONSTRAINT "admin_logs_pkey" PRIMARY KEY ("id") ); -- CreateIndex CREATE UNIQUE INDEX "admins_mobile_key" ON "admins"("mobile"); -- CreateIndex CREATE UNIQUE INDEX "admins_email_key" ON "admins"("email"); -- CreateIndex CREATE UNIQUE INDEX "users_mobile_key" ON "users"("mobile"); -- CreateIndex CREATE INDEX "users_mobile_idx" ON "users"("mobile"); -- CreateIndex CREATE INDEX "otp_codes_mobile_consumed_idx" ON "otp_codes"("mobile", "consumed"); -- CreateIndex CREATE UNIQUE INDEX "campaigns_slug_key" ON "campaigns"("slug"); -- CreateIndex CREATE INDEX "campaigns_status_start_at_end_at_idx" ON "campaigns"("status", "start_at", "end_at"); -- CreateIndex CREATE INDEX "prizes_campaign_id_status_idx" ON "prizes"("campaign_id", "status"); -- CreateIndex CREATE UNIQUE INDEX "user_campaigns_user_id_campaign_id_key" ON "user_campaigns"("user_id", "campaign_id"); -- CreateIndex CREATE INDEX "chance_transactions_user_id_campaign_id_idx" ON "chance_transactions"("user_id", "campaign_id"); -- CreateIndex CREATE UNIQUE INDEX "spins_idempotency_key_key" ON "spins"("idempotency_key"); -- CreateIndex CREATE INDEX "spins_user_id_campaign_id_idx" ON "spins"("user_id", "campaign_id"); -- CreateIndex CREATE INDEX "spins_campaign_id_created_at_idx" ON "spins"("campaign_id", "created_at"); -- CreateIndex CREATE UNIQUE INDEX "user_prizes_spin_id_key" ON "user_prizes"("spin_id"); -- CreateIndex CREATE UNIQUE INDEX "user_prizes_code_key" ON "user_prizes"("code"); -- CreateIndex CREATE INDEX "user_prizes_user_id_idx" ON "user_prizes"("user_id"); -- CreateIndex CREATE INDEX "user_prizes_status_idx" ON "user_prizes"("status"); -- CreateIndex CREATE INDEX "sms_logs_mobile_type_idx" ON "sms_logs"("mobile", "type"); -- CreateIndex CREATE INDEX "admin_logs_entity_type_entity_id_idx" ON "admin_logs"("entity_type", "entity_id"); -- AddForeignKey ALTER TABLE "otp_codes" ADD CONSTRAINT "otp_codes_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE SET NULL ON UPDATE CASCADE; -- AddForeignKey ALTER TABLE "prizes" ADD CONSTRAINT "prizes_campaign_id_fkey" FOREIGN KEY ("campaign_id") REFERENCES "campaigns"("id") ON DELETE CASCADE ON UPDATE CASCADE; -- AddForeignKey ALTER TABLE "user_campaigns" ADD CONSTRAINT "user_campaigns_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE; -- AddForeignKey ALTER TABLE "user_campaigns" ADD CONSTRAINT "user_campaigns_campaign_id_fkey" FOREIGN KEY ("campaign_id") REFERENCES "campaigns"("id") ON DELETE RESTRICT ON UPDATE CASCADE; -- AddForeignKey ALTER TABLE "chance_transactions" ADD CONSTRAINT "chance_transactions_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE; -- AddForeignKey ALTER TABLE "chance_transactions" ADD CONSTRAINT "chance_transactions_campaign_id_fkey" FOREIGN KEY ("campaign_id") REFERENCES "campaigns"("id") ON DELETE RESTRICT ON UPDATE CASCADE; -- AddForeignKey ALTER TABLE "chance_transactions" ADD CONSTRAINT "chance_transactions_created_by_fkey" FOREIGN KEY ("created_by") REFERENCES "admins"("id") ON DELETE SET NULL ON UPDATE CASCADE; -- AddForeignKey ALTER TABLE "spins" ADD CONSTRAINT "spins_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE; -- AddForeignKey ALTER TABLE "spins" ADD CONSTRAINT "spins_campaign_id_fkey" FOREIGN KEY ("campaign_id") REFERENCES "campaigns"("id") ON DELETE RESTRICT ON UPDATE CASCADE; -- AddForeignKey ALTER TABLE "spins" ADD CONSTRAINT "spins_prize_id_fkey" FOREIGN KEY ("prize_id") REFERENCES "prizes"("id") ON DELETE SET NULL ON UPDATE CASCADE; -- AddForeignKey ALTER TABLE "user_prizes" ADD CONSTRAINT "user_prizes_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE; -- AddForeignKey ALTER TABLE "user_prizes" ADD CONSTRAINT "user_prizes_campaign_id_fkey" FOREIGN KEY ("campaign_id") REFERENCES "campaigns"("id") ON DELETE RESTRICT ON UPDATE CASCADE; -- AddForeignKey ALTER TABLE "user_prizes" ADD CONSTRAINT "user_prizes_prize_id_fkey" FOREIGN KEY ("prize_id") REFERENCES "prizes"("id") ON DELETE RESTRICT ON UPDATE CASCADE; -- AddForeignKey ALTER TABLE "user_prizes" ADD CONSTRAINT "user_prizes_spin_id_fkey" FOREIGN KEY ("spin_id") REFERENCES "spins"("id") ON DELETE RESTRICT ON UPDATE CASCADE; -- AddForeignKey ALTER TABLE "sms_logs" ADD CONSTRAINT "sms_logs_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE SET NULL ON UPDATE CASCADE; -- AddForeignKey ALTER TABLE "admin_logs" ADD CONSTRAINT "admin_logs_admin_id_fkey" FOREIGN KEY ("admin_id") REFERENCES "admins"("id") ON DELETE RESTRICT ON UPDATE CASCADE;