first commit
This commit is contained in:
@@ -0,0 +1,313 @@
|
||||
generator client {
|
||||
provider = "prisma-client-js"
|
||||
}
|
||||
|
||||
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")
|
||||
}
|
||||
Reference in New Issue
Block a user