Files
Lucky_Wheel/apps/api/release/prisma/schema.prisma
T
2026-09-11 11:22:33 +03:30

316 lines
9.0 KiB
Plaintext

generator client {
provider = "prisma-client-js"
// native = ویندوز/مک لوکال؛ debian = ایمیج node:20-bookworm-slim در Docker
binaryTargets = ["native", "debian-openssl-3.0.x"]
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
// ==================== ENUMS ====================
enum AdminStatus {
ACTIVE
DISABLED
}
enum AdminRole {
SUPER_ADMIN
OPERATOR
SUPPORT
}
enum UserStatus {
ACTIVE
BLOCKED
}
enum CampaignStatus {
DRAFT
ACTIVE
PAUSED
FINISHED
}
enum PrizeType {
PHYSICAL
DISCOUNT_CODE
CREDIT
CASH
NO_PRIZE
OTHER
}
enum StockType {
LIMITED
UNLIMITED
}
enum PrizeStatus {
ACTIVE
INACTIVE
}
enum SpinStatus {
SUCCESS
FAILED
DUPLICATE
}
enum ChanceTxnType {
SIGNUP_BONUS
ADMIN_ADJUSTMENT
SPIN_CONSUME
CAMPAIGN_BONUS
REFUND
}
enum UserPrizeStatus {
NEW
CONTACTED
DELIVERED
ACTIVE_CODE
USED
EXPIRED
}
enum SmsType {
OTP
WINNING
NO_PRIZE
PRIZE_REMINDER
}
enum SmsStatus {
PENDING
SENT
FAILED
}
enum WheelDesign {
CLASSIC_CASINO
NEON_CYBER
MINIMAL_FLAT
LUXURY_GOLD
PLAYFUL_CARTOON
}
// ==================== MODELS ====================
model Admin {
id String @id @default(uuid())
name String
mobile String @unique
email String @unique
passwordHash String @map("password_hash")
role AdminRole @default(OPERATOR)
status AdminStatus @default(ACTIVE)
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
auditLogs AdminLog[]
chanceTxns ChanceTransaction[] @relation("AdminCreatedTxn")
@@map("admins")
}
model User {
id String @id @default(uuid())
mobile String @unique
name String?
status UserStatus @default(ACTIVE)
lastLoginAt DateTime? @map("last_login_at")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
userCampaigns UserCampaign[]
chanceTransactions ChanceTransaction[]
spins Spin[]
userPrizes UserPrize[]
otpCodes OtpCode[]
smsLogs SmsLog[]
@@index([mobile])
@@map("users")
}
model OtpCode {
id String @id @default(uuid())
mobile String
code String
userId String? @map("user_id")
user User? @relation(fields: [userId], references: [id])
attempts Int @default(0)
consumed Boolean @default(false)
expiresAt DateTime @map("expires_at")
createdAt DateTime @default(now()) @map("created_at")
@@index([mobile, consumed])
@@map("otp_codes")
}
model Campaign {
id String @id @default(uuid())
title String
slug String @unique
description String?
image String?
banner String?
logo String?
startAt DateTime @map("start_at")
endAt DateTime @map("end_at")
status CampaignStatus @default(DRAFT)
defaultChances Int @default(0) @map("default_chances")
rules String?
ctaText String? @map("cta_text")
wheelDesign WheelDesign @default(CLASSIC_CASINO) @map("wheel_design")
settings Json? // primaryColor, secondaryColor, headerText, buttonText, headerImage, celebrationEffect...
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
prizes Prize[]
userCampaigns UserCampaign[]
chanceTxns ChanceTransaction[]
spins Spin[]
userPrizes UserPrize[]
@@index([status, startAt, endAt])
@@map("campaigns")
}
model Prize {
id String @id @default(uuid())
campaignId String @map("campaign_id")
campaign Campaign @relation(fields: [campaignId], references: [id], onDelete: Cascade)
title String
description String?
image String?
type PrizeType
stockType StockType @map("stock_type")
initialStock Int? @map("initial_stock")
remainingStock Int? @map("remaining_stock")
weight Int
status PrizeStatus @default(ACTIVE)
sortOrder Int @default(0) @map("sort_order")
segmentColor String @map("segment_color")
expiresAt DateTime? @map("expires_at")
smsTemplate String? @map("sms_template")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
spins Spin[]
userPrizes UserPrize[]
@@index([campaignId, status])
@@map("prizes")
}
model UserCampaign {
id String @id @default(uuid())
userId String @map("user_id")
user User @relation(fields: [userId], references: [id])
campaignId String @map("campaign_id")
campaign Campaign @relation(fields: [campaignId], references: [id])
totalChances Int @default(0) @map("total_chances")
usedChances Int @default(0) @map("used_chances")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
@@unique([userId, campaignId])
@@map("user_campaigns")
}
model ChanceTransaction {
id String @id @default(uuid())
userId String @map("user_id")
user User @relation(fields: [userId], references: [id])
campaignId String @map("campaign_id")
campaign Campaign @relation(fields: [campaignId], references: [id])
amount Int // مثبت یا منفی
type ChanceTxnType
referenceType String? @map("reference_type") // e.g. "spin", "manual"
referenceId String? @map("reference_id")
description String?
createdById String? @map("created_by") // admin id در صورت تغییر دستی
createdBy Admin? @relation("AdminCreatedTxn", fields: [createdById], references: [id])
createdAt DateTime @default(now()) @map("created_at")
@@index([userId, campaignId])
@@map("chance_transactions")
}
model Spin {
id String @id @default(uuid())
userId String @map("user_id")
user User @relation(fields: [userId], references: [id])
campaignId String @map("campaign_id")
campaign Campaign @relation(fields: [campaignId], references: [id])
prizeId String? @map("prize_id")
prize Prize? @relation(fields: [prizeId], references: [id])
status SpinStatus @default(SUCCESS)
idempotencyKey String @unique @map("idempotency_key")
ip String?
userAgent String? @map("user_agent")
createdAt DateTime @default(now()) @map("created_at")
userPrize UserPrize?
@@index([userId, campaignId])
@@index([campaignId, createdAt])
@@map("spins")
}
model UserPrize {
id String @id @default(uuid())
userId String @map("user_id")
user User @relation(fields: [userId], references: [id])
campaignId String @map("campaign_id")
campaign Campaign @relation(fields: [campaignId], references: [id])
prizeId String @map("prize_id")
prize Prize @relation(fields: [prizeId], references: [id])
spinId String @unique @map("spin_id")
spin Spin @relation(fields: [spinId], references: [id])
code String? @unique
status UserPrizeStatus @default(NEW)
wonAt DateTime @default(now()) @map("won_at")
redeemedAt DateTime? @map("redeemed_at")
@@index([userId])
@@index([status])
@@map("user_prizes")
}
model SmsLog {
id String @id @default(uuid())
userId String? @map("user_id")
user User? @relation(fields: [userId], references: [id])
mobile String
type SmsType
message String
provider String @default("raygansms")
status SmsStatus @default(PENDING)
providerResponse Json? @map("provider_response")
createdAt DateTime @default(now()) @map("created_at")
@@index([mobile, type])
@@map("sms_logs")
}
model AdminLog {
id String @id @default(uuid())
adminId String @map("admin_id")
admin Admin @relation(fields: [adminId], references: [id])
action String // e.g. "prize.update", "chance.add"
entityType String @map("entity_type")
entityId String @map("entity_id")
oldValue Json? @map("old_value")
newValue Json? @map("new_value")
ip String?
createdAt DateTime @default(now()) @map("created_at")
@@index([entityType, entityId])
@@map("admin_logs")
}