264 lines
7.7 KiB
Plaintext
264 lines
7.7 KiB
Plaintext
// This is your Prisma schema file,
|
|
// learn more about it in the docs: https://pris.ly/d/prisma-schema
|
|
|
|
generator client {
|
|
provider = "prisma-client-js"
|
|
}
|
|
|
|
datasource db {
|
|
provider = "postgresql"
|
|
url = env("DATABASE_URL")
|
|
}
|
|
|
|
// ============================================================================
|
|
// ENUMS
|
|
// ============================================================================
|
|
|
|
enum UserStatus {
|
|
PENDING_VERIFICATION
|
|
ACTIVE
|
|
SUSPENDED
|
|
}
|
|
|
|
enum StaffRole {
|
|
ADMIN
|
|
SUPPORT
|
|
}
|
|
|
|
enum SubscriptionPlan {
|
|
TRIAL
|
|
STARTER
|
|
PRO
|
|
ENTERPRISE
|
|
}
|
|
|
|
enum SubscriptionTier {
|
|
HUB_DASHBOARD
|
|
ADVANCED
|
|
}
|
|
|
|
enum SubscriptionStatus {
|
|
TRIAL
|
|
ACTIVE
|
|
CANCELED
|
|
PAST_DUE
|
|
}
|
|
|
|
enum OrderStatus {
|
|
PAYMENT_CONFIRMED
|
|
AWAITING_SERVER
|
|
SERVER_READY
|
|
DNS_PENDING
|
|
DNS_READY
|
|
PROVISIONING
|
|
FULFILLED
|
|
EMAIL_CONFIGURED
|
|
FAILED
|
|
}
|
|
|
|
enum JobStatus {
|
|
PENDING
|
|
CLAIMED
|
|
RUNNING
|
|
COMPLETED
|
|
FAILED
|
|
DEAD
|
|
}
|
|
|
|
enum LogLevel {
|
|
DEBUG
|
|
INFO
|
|
WARN
|
|
ERROR
|
|
}
|
|
|
|
// ============================================================================
|
|
// USER & STAFF MODELS
|
|
// ============================================================================
|
|
|
|
model User {
|
|
id String @id @default(cuid())
|
|
email String @unique
|
|
passwordHash String @map("password_hash")
|
|
name String?
|
|
company String?
|
|
status UserStatus @default(PENDING_VERIFICATION)
|
|
emailVerified DateTime? @map("email_verified")
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
updatedAt DateTime @updatedAt @map("updated_at")
|
|
|
|
subscriptions Subscription[]
|
|
orders Order[]
|
|
tokenUsage TokenUsage[]
|
|
|
|
@@map("users")
|
|
}
|
|
|
|
model Staff {
|
|
id String @id @default(cuid())
|
|
email String @unique
|
|
passwordHash String @map("password_hash")
|
|
name String
|
|
role StaffRole @default(SUPPORT)
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
updatedAt DateTime @updatedAt @map("updated_at")
|
|
|
|
@@map("staff")
|
|
}
|
|
|
|
// ============================================================================
|
|
// SUBSCRIPTION & BILLING
|
|
// ============================================================================
|
|
|
|
model Subscription {
|
|
id String @id @default(cuid())
|
|
userId String @map("user_id")
|
|
plan SubscriptionPlan @default(TRIAL)
|
|
tier SubscriptionTier @default(HUB_DASHBOARD)
|
|
tokenLimit Int @default(10000) @map("token_limit")
|
|
tokensUsed Int @default(0) @map("tokens_used")
|
|
trialEndsAt DateTime? @map("trial_ends_at")
|
|
stripeCustomerId String? @map("stripe_customer_id")
|
|
stripeSubscriptionId String? @map("stripe_subscription_id")
|
|
status SubscriptionStatus @default(TRIAL)
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
updatedAt DateTime @updatedAt @map("updated_at")
|
|
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
|
|
@@map("subscriptions")
|
|
}
|
|
|
|
// ============================================================================
|
|
// ORDERS & PROVISIONING
|
|
// ============================================================================
|
|
|
|
model Order {
|
|
id String @id @default(cuid())
|
|
userId String @map("user_id")
|
|
status OrderStatus @default(PAYMENT_CONFIRMED)
|
|
tier SubscriptionTier
|
|
domain String
|
|
tools String[]
|
|
configJson Json @map("config_json")
|
|
|
|
// Server credentials (entered by staff)
|
|
serverIp String? @map("server_ip")
|
|
serverPasswordEncrypted String? @map("server_password_encrypted")
|
|
sshPort Int @default(22) @map("ssh_port")
|
|
|
|
// Generated after provisioning
|
|
portainerUrl String? @map("portainer_url")
|
|
dashboardUrl String? @map("dashboard_url")
|
|
failureReason String? @map("failure_reason")
|
|
|
|
// Timestamps
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
updatedAt DateTime @updatedAt @map("updated_at")
|
|
serverReadyAt DateTime? @map("server_ready_at")
|
|
provisioningStartedAt DateTime? @map("provisioning_started_at")
|
|
completedAt DateTime? @map("completed_at")
|
|
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
provisioningLogs ProvisioningLog[]
|
|
jobs ProvisioningJob[]
|
|
|
|
@@map("orders")
|
|
}
|
|
|
|
model ProvisioningLog {
|
|
id String @id @default(cuid())
|
|
orderId String @map("order_id")
|
|
level LogLevel @default(INFO)
|
|
message String
|
|
step String?
|
|
timestamp DateTime @default(now())
|
|
|
|
order Order @relation(fields: [orderId], references: [id], onDelete: Cascade)
|
|
|
|
@@index([orderId, timestamp])
|
|
@@map("provisioning_logs")
|
|
}
|
|
|
|
// ============================================================================
|
|
// JOB QUEUE
|
|
// ============================================================================
|
|
|
|
model ProvisioningJob {
|
|
id String @id @default(cuid())
|
|
orderId String @map("order_id")
|
|
jobType String @map("job_type")
|
|
status JobStatus @default(PENDING)
|
|
priority Int @default(0)
|
|
claimedAt DateTime? @map("claimed_at")
|
|
claimedBy String? @map("claimed_by")
|
|
containerName String? @map("container_name")
|
|
attempt Int @default(1)
|
|
maxAttempts Int @default(3) @map("max_attempts")
|
|
nextRetryAt DateTime? @map("next_retry_at")
|
|
configSnapshot Json @map("config_snapshot")
|
|
runnerTokenHash String? @map("runner_token_hash")
|
|
result Json?
|
|
error String?
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
updatedAt DateTime @updatedAt @map("updated_at")
|
|
completedAt DateTime? @map("completed_at")
|
|
|
|
order Order @relation(fields: [orderId], references: [id], onDelete: Cascade)
|
|
logs JobLog[]
|
|
|
|
@@index([status, priority, createdAt])
|
|
@@index([orderId])
|
|
@@map("provisioning_jobs")
|
|
}
|
|
|
|
model JobLog {
|
|
id String @id @default(cuid())
|
|
jobId String @map("job_id")
|
|
level LogLevel @default(INFO)
|
|
message String
|
|
step String?
|
|
progress Int?
|
|
timestamp DateTime @default(now())
|
|
|
|
job ProvisioningJob @relation(fields: [jobId], references: [id], onDelete: Cascade)
|
|
|
|
@@index([jobId, timestamp])
|
|
@@map("job_logs")
|
|
}
|
|
|
|
// ============================================================================
|
|
// TOKEN USAGE (AI Tracking)
|
|
// ============================================================================
|
|
|
|
model TokenUsage {
|
|
id String @id @default(cuid())
|
|
userId String @map("user_id")
|
|
instanceId String? @map("instance_id")
|
|
operation String // chat, analysis, setup
|
|
tokensInput Int @map("tokens_input")
|
|
tokensOutput Int @map("tokens_output")
|
|
model String
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
|
|
@@index([userId, createdAt])
|
|
@@map("token_usage")
|
|
}
|
|
|
|
// ============================================================================
|
|
// RUNNER TOKENS
|
|
// ============================================================================
|
|
|
|
model RunnerToken {
|
|
id String @id @default(cuid())
|
|
tokenHash String @unique @map("token_hash")
|
|
name String
|
|
isActive Boolean @default(true) @map("is_active")
|
|
lastUsed DateTime? @map("last_used")
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
|
|
@@map("runner_tokens")
|
|
}
|