- NextAuth v5 with email+password credentials, JWT sessions - Registration, login, email verification, password reset flows - Stripe integration: Free (15/day), Starter ($5/1k/mo), Pro ($20/100k/mo) - API key management (cb_ prefix) with hash-based validation - Dashboard with generations history, settings, billing management - Rate limiting: Redis daily counter (free), DB monthly (paid) - Generate route auth: Bearer API key + session, anonymous allowed - Worker userId propagation for generation history - Pricing section on landing page, auth-aware navbar - Middleware with route protection, CORS for codeboard.vectry.tech - Docker env vars for auth, Stripe, email (smtp.migadu.com)
148 lines
3.4 KiB
Plaintext
148 lines
3.4 KiB
Plaintext
datasource db {
|
|
provider = "postgresql"
|
|
url = env("DATABASE_URL")
|
|
}
|
|
|
|
generator client {
|
|
provider = "prisma-client-js"
|
|
}
|
|
|
|
model User {
|
|
id String @id @default(cuid())
|
|
email String @unique
|
|
passwordHash String
|
|
name String?
|
|
emailVerified Boolean @default(false)
|
|
image String?
|
|
stripeCustomerId String? @unique
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
subscription Subscription?
|
|
apiKeys ApiKey[]
|
|
generations Generation[]
|
|
passwordResetTokens PasswordResetToken[]
|
|
emailVerificationTokens EmailVerificationToken[]
|
|
|
|
@@index([email])
|
|
}
|
|
|
|
model Subscription {
|
|
id String @id @default(cuid())
|
|
userId String @unique
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
|
|
tier SubscriptionTier @default(FREE)
|
|
stripeCustomerId String? @unique
|
|
stripeSubscriptionId String? @unique
|
|
stripePriceId String?
|
|
|
|
currentPeriodStart DateTime?
|
|
currentPeriodEnd DateTime?
|
|
|
|
generationsUsed Int @default(0)
|
|
generationsLimit Int @default(15)
|
|
|
|
status SubscriptionStatus @default(ACTIVE)
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@index([stripeCustomerId])
|
|
@@index([stripeSubscriptionId])
|
|
}
|
|
|
|
model ApiKey {
|
|
id String @id @default(cuid())
|
|
userId String
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
|
|
name String @default("Default")
|
|
keyHash String @unique
|
|
keyPrefix String
|
|
lastUsedAt DateTime?
|
|
|
|
revoked Boolean @default(false)
|
|
createdAt DateTime @default(now())
|
|
|
|
@@index([keyHash])
|
|
@@index([userId])
|
|
}
|
|
|
|
model PasswordResetToken {
|
|
id String @id @default(cuid())
|
|
userId String
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
|
|
token String @unique
|
|
expiresAt DateTime
|
|
used Boolean @default(false)
|
|
|
|
createdAt DateTime @default(now())
|
|
|
|
@@index([token])
|
|
@@index([userId])
|
|
}
|
|
|
|
model EmailVerificationToken {
|
|
id String @id @default(cuid())
|
|
userId String
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
|
|
token String @unique
|
|
expiresAt DateTime
|
|
used Boolean @default(false)
|
|
|
|
createdAt DateTime @default(now())
|
|
|
|
@@index([token])
|
|
@@index([userId])
|
|
}
|
|
|
|
enum SubscriptionTier {
|
|
FREE
|
|
STARTER
|
|
PRO
|
|
}
|
|
|
|
enum SubscriptionStatus {
|
|
ACTIVE
|
|
PAST_DUE
|
|
CANCELED
|
|
UNPAID
|
|
}
|
|
|
|
model Generation {
|
|
id String @id @default(cuid())
|
|
repoUrl String
|
|
repoName String
|
|
commitHash String
|
|
status Status @default(QUEUED)
|
|
progress Int @default(0)
|
|
result Json?
|
|
error String?
|
|
costUsd Float?
|
|
duration Int?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
userId String?
|
|
user User? @relation(fields: [userId], references: [id])
|
|
viewCount Int @default(0)
|
|
|
|
@@unique([repoUrl, commitHash])
|
|
@@index([repoUrl])
|
|
@@index([status])
|
|
@@index([userId])
|
|
}
|
|
|
|
enum Status {
|
|
QUEUED
|
|
CLONING
|
|
PARSING
|
|
GENERATING
|
|
RENDERING
|
|
COMPLETED
|
|
FAILED
|
|
}
|