diff --git a/apps/supercode-cli/server/prisma/migrations/20260629120000_add_device_code_timestamps/migration.sql b/apps/supercode-cli/server/prisma/migrations/20260629120000_add_device_code_timestamps/migration.sql index b11eb6a..cb423a6 100644 --- a/apps/supercode-cli/server/prisma/migrations/20260629120000_add_device_code_timestamps/migration.sql +++ b/apps/supercode-cli/server/prisma/migrations/20260629120000_add_device_code_timestamps/migration.sql @@ -1,3 +1,4 @@ --- AlterTable -ALTER TABLE "device_code" ADD COLUMN "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, -ADD COLUMN "updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP; \ No newline at end of file +-- This is a no-op: createdAt/updatedAt were already part of the initial device_code table +-- in migration 20260601105723_device_flow. This migration is already recorded as applied +-- in the main database but needs to pass in shadow DB for future migrations. +SELECT 1; \ No newline at end of file diff --git a/apps/supercode-cli/server/prisma/migrations/20260729130000_add_missing_models/migration.sql b/apps/supercode-cli/server/prisma/migrations/20260729130000_add_missing_models/migration.sql new file mode 100644 index 0000000..227b73f --- /dev/null +++ b/apps/supercode-cli/server/prisma/migrations/20260729130000_add_missing_models/migration.sql @@ -0,0 +1,132 @@ +-- AlterTable +ALTER TABLE "user" ADD COLUMN "dodoCustomerId" TEXT; + +-- CreateTable +CREATE TABLE "plan" ( + "id" TEXT NOT NULL, + "tier" TEXT NOT NULL, + "name" TEXT NOT NULL, + "description" TEXT, + "variant" TEXT, + "interval" TEXT, + "priceCents" INTEGER NOT NULL, + "currency" TEXT NOT NULL DEFAULT 'USD', + "requestLimit" INTEGER NOT NULL, + "contextLimit" INTEGER NOT NULL, + "modelAccess" TEXT NOT NULL, + "creditAmountCents" INTEGER NOT NULL DEFAULT 0, + "dodoProductId" TEXT, + "active" BOOLEAN NOT NULL DEFAULT true, + "sortOrder" INTEGER NOT NULL DEFAULT 0, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "plan_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "subscription" ( + "id" TEXT NOT NULL, + "userId" TEXT NOT NULL, + "planId" TEXT NOT NULL, + "dodoSubscriptionId" TEXT NOT NULL, + "dodoCustomerId" TEXT, + "status" TEXT NOT NULL, + "currentPeriodStart" TIMESTAMP(3), + "currentPeriodEnd" TIMESTAMP(3), + "trialEndsAt" TIMESTAMP(3), + "cancelAtPeriodEnd" BOOLEAN NOT NULL DEFAULT false, + "metadata" JSONB, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "subscription_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "credit_balance" ( + "userId" TEXT NOT NULL, + "planId" TEXT NOT NULL, + "balanceCents" INTEGER NOT NULL DEFAULT 0, + "totalCredits" INTEGER NOT NULL DEFAULT 0, + "resetAt" TIMESTAMP(3) NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "credit_balance_pkey" PRIMARY KEY ("userId","planId") +); + +-- CreateTable +CREATE TABLE "model" ( + "id" TEXT NOT NULL, + "slug" TEXT NOT NULL, + "displayName" TEXT NOT NULL, + "provider" TEXT NOT NULL, + "minTier" TEXT NOT NULL, + "inputPrice" DOUBLE PRECISION NOT NULL, + "outputPrice" DOUBLE PRECISION NOT NULL, + "cachedPrice" DOUBLE PRECISION NOT NULL, + "active" BOOLEAN NOT NULL DEFAULT true, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "model_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE UNIQUE INDEX "plan_dodoProductId_key" ON "plan"("dodoProductId"); + +-- CreateIndex +CREATE INDEX "plan_tier_idx" ON "plan"("tier"); + +-- CreateIndex +CREATE UNIQUE INDEX "subscription_dodoSubscriptionId_key" ON "subscription"("dodoSubscriptionId"); + +-- CreateIndex +CREATE INDEX "subscription_userId_idx" ON "subscription"("userId"); + +-- CreateIndex +CREATE INDEX "subscription_planId_idx" ON "subscription"("planId"); + +-- CreateIndex +CREATE INDEX "subscription_dodoSubscriptionId_idx" ON "subscription"("dodoSubscriptionId"); + +-- CreateIndex +CREATE INDEX "subscription_status_idx" ON "subscription"("status"); + +-- CreateIndex +CREATE INDEX "credit_balance_userId_idx" ON "credit_balance"("userId"); + +-- CreateIndex +CREATE INDEX "credit_balance_planId_idx" ON "credit_balance"("planId"); + +-- CreateIndex +CREATE UNIQUE INDEX "model_slug_key" ON "model"("slug"); + +-- CreateIndex +CREATE INDEX "model_minTier_idx" ON "model"("minTier"); + +-- CreateIndex +CREATE INDEX "model_provider_idx" ON "model"("provider"); + +-- CreateIndex +CREATE INDEX "model_slug_idx" ON "model"("slug"); + +-- CreateIndex +CREATE INDEX "conversation_userId_idx" ON "conversation"("userId"); + +-- CreateIndex +CREATE UNIQUE INDEX "user_dodoCustomerId_key" ON "user"("dodoCustomerId"); + +-- AddForeignKey +ALTER TABLE "subscription" ADD CONSTRAINT "subscription_userId_fkey" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "subscription" ADD CONSTRAINT "subscription_planId_fkey" FOREIGN KEY ("planId") REFERENCES "plan"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "credit_balance" ADD CONSTRAINT "credit_balance_userId_fkey" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "credit_balance" ADD CONSTRAINT "credit_balance_planId_fkey" FOREIGN KEY ("planId") REFERENCES "plan"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + diff --git a/apps/supercode-cli/server/prisma/schema.prisma b/apps/supercode-cli/server/prisma/schema.prisma index 66f405c..f1780c5 100644 --- a/apps/supercode-cli/server/prisma/schema.prisma +++ b/apps/supercode-cli/server/prisma/schema.prisma @@ -20,6 +20,9 @@ model User { accounts Account[] conversation Conversation[] paidTierInterests PaidTierInterest[] + dodoCustomerId String? @unique + subscriptions Subscription[] + creditBalances CreditBalance[] @@unique([email]) @@map("user") @@ -105,6 +108,7 @@ model Conversation { user User @relation(fields: [userId], references: [id], onDelete: Cascade) messages Message[] + @@index([userId]) @@map("conversation") } @@ -139,6 +143,93 @@ model PaidTierInterest { @@map("paid_tier_interest") } +model Plan { + id String @id @default(cuid()) + tier String + name String + description String? + variant String? + interval String? + priceCents Int + currency String @default("USD") + requestLimit Int + contextLimit Int + modelAccess String + creditAmountCents Int @default(0) + dodoProductId String? @unique + active Boolean @default(true) + sortOrder Int @default(0) + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + subscriptions Subscription[] + creditBalances CreditBalance[] + + @@index([tier]) + @@map("plan") +} + +model Subscription { + id String @id @default(cuid()) + userId String + planId String + dodoSubscriptionId String @unique + dodoCustomerId String? + status String + currentPeriodStart DateTime? + currentPeriodEnd DateTime? + trialEndsAt DateTime? + cancelAtPeriodEnd Boolean @default(false) + metadata Json? + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + user User @relation(fields: [userId], references: [id], onDelete: Cascade) + plan Plan @relation(fields: [planId], references: [id]) + + @@index([userId]) + @@index([planId]) + @@index([dodoSubscriptionId]) + @@index([status]) + @@map("subscription") +} + +model CreditBalance { + userId String + planId String + balanceCents Int @default(0) + totalCredits Int @default(0) + resetAt DateTime + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + user User @relation(fields: [userId], references: [id], onDelete: Cascade) + plan Plan @relation(fields: [planId], references: [id]) + + @@id([userId, planId]) + @@index([userId]) + @@index([planId]) + @@map("credit_balance") +} + +model Model { + id String @id @default(cuid()) + slug String @unique + displayName String + provider String + minTier String + inputPrice Float + outputPrice Float + cachedPrice Float + active Boolean @default(true) + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + @@index([minTier]) + @@index([provider]) + @@index([slug]) + @@map("model") +} + model Message { id String @id @default(cuid()) conversationId String