Assist_Design/apps/bff/prisma/schema.prisma

219 lines
7.8 KiB
Plaintext
Raw Normal View History

// =============================================================================
// Prisma Schema - Customer Portal BFF
// =============================================================================
// IMPORTANT: When building Docker images, the Prisma client must be regenerated
// from the production directory structure. See prisma/README.md for details.
// =============================================================================
generator client {
provider = "prisma-client-js"
// Only include engines we actually need:
// - native: for local development
// - linux-musl-openssl-3.0.x: for Alpine production
binaryTargets = ["native", "linux-musl-openssl-3.0.x"]
}
datasource db {
provider = "postgresql"
// Prisma 7+: URL is configured via prisma.config.ts for migrations
// and via --url flag for studio. Runtime uses the adapter in PrismaClient.
}
model User {
id String @id @default(uuid())
email String @unique
passwordHash String? @map("password_hash")
role UserRole @default(USER)
// Authentication state only - profile data comes from WHMCS
mfaSecret String? @map("mfa_secret")
emailVerified Boolean @default(false) @map("email_verified")
failedLoginAttempts Int @default(0) @map("failed_login_attempts")
lockedUntil DateTime? @map("locked_until")
lastLoginAt DateTime? @map("last_login_at")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
auditLogs AuditLog[]
idMapping IdMapping?
residenceCardSubmission ResidenceCardSubmission?
@@map("users")
}
model IdMapping {
userId String @id @map("user_id")
whmcsClientId Int @unique @map("whmcs_client_id")
sfAccountId String? @map("sf_account_id")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@map("id_mappings")
}
model AuditLog {
id String @id @default(uuid())
userId String? @map("user_id")
action AuditAction
resource String?
details Json?
ipAddress String? @map("ip_address")
userAgent String? @map("user_agent")
success Boolean @default(true)
error String?
createdAt DateTime @default(now()) @map("created_at")
user User? @relation(fields: [userId], references: [id])
@@index([userId, action])
@@index([action, createdAt])
@@index([createdAt])
@@map("audit_logs")
}
enum UserRole {
USER
ADMIN
}
enum AuditAction {
LOGIN_SUCCESS
LOGIN_FAILED
LOGOUT
SIGNUP
PASSWORD_RESET
PASSWORD_CHANGE
ACCOUNT_LOCKED
ACCOUNT_UNLOCKED
PROFILE_UPDATE
MFA_ENABLED
MFA_DISABLED
API_ACCESS
SYSTEM_MAINTENANCE
}
enum ResidenceCardStatus {
PENDING
VERIFIED
REJECTED
}
model ResidenceCardSubmission {
id String @id @default(uuid())
userId String @unique @map("user_id")
status ResidenceCardStatus @default(PENDING)
filename String
mimeType String @map("mime_type")
sizeBytes Int @map("size_bytes")
content Bytes @db.ByteA
submittedAt DateTime @default(now()) @map("submitted_at")
reviewedAt DateTime? @map("reviewed_at")
reviewerNotes String? @map("reviewer_notes")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@map("residence_card_submissions")
}
// Per-SIM daily usage snapshot used to build full-month charts
model SimUsageDaily {
id Int @id @default(autoincrement())
account String
date DateTime @db.Date
usageMb Float
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
@@unique([account, date])
@@index([account, date])
@@map("sim_usage_daily")
}
model SimVoiceOptions {
account String @id
voiceMailEnabled Boolean @default(false) @map("voice_mail_enabled")
callWaitingEnabled Boolean @default(false) @map("call_waiting_enabled")
internationalRoamingEnabled Boolean @default(false) @map("international_roaming_enabled")
networkType String @default("4G") @map("network_type")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
@@map("sim_voice_options")
}
// Call history from SFTP monthly imports (domestic calls)
model SimCallHistoryDomestic {
id String @id @default(uuid())
account String // Customer phone number (e.g., "08077052946")
callDate DateTime @db.Date @map("call_date") // Date the call was made
callTime String @map("call_time") // Start time of the call (HHMMSS)
calledTo String @map("called_to") // Phone number called
location String? // Location info
durationSec Int @map("duration_sec") // Duration in seconds (320 = 32.0 sec)
chargeYen Int @map("charge_yen") // Call charge in JPY
month String // YYYY-MM format for filtering
createdAt DateTime @default(now()) @map("created_at")
@@unique([account, callDate, callTime, calledTo])
@@index([account, month])
@@index([account, callDate])
@@map("sim_call_history_domestic")
}
// Call history from SFTP monthly imports (international calls)
model SimCallHistoryInternational {
id String @id @default(uuid())
account String // Customer phone number
callDate DateTime @db.Date @map("call_date") // Date the call was made
startTime String @map("start_time") // Start time of the call
stopTime String? @map("stop_time") // Stop time (if available)
country String? // Country/location for international calls
calledTo String @map("called_to") // Phone number called
durationSec Int @map("duration_sec") // Duration in seconds
chargeYen Int @map("charge_yen") // Call charge in JPY
month String // YYYY-MM format for filtering
createdAt DateTime @default(now()) @map("created_at")
@@unique([account, callDate, startTime, calledTo])
@@index([account, month])
@@index([account, callDate])
@@map("sim_call_history_international")
}
// SMS history from SFTP monthly imports
model SimSmsHistory {
id String @id @default(uuid())
account String // Customer phone number
smsDate DateTime @db.Date @map("sms_date") // Date the SMS was sent
smsTime String @map("sms_time") // Time the SMS was sent
sentTo String @map("sent_to") // Phone number SMS was sent to
smsType SmsType @default(DOMESTIC) @map("sms_type") // SMS or 国際SMS
month String // YYYY-MM format for filtering
createdAt DateTime @default(now()) @map("created_at")
@@unique([account, smsDate, smsTime, sentTo])
@@index([account, month])
@@index([account, smsDate])
@@map("sim_sms_history")
}
enum SmsType {
DOMESTIC //
INTERNATIONAL // 国際SMS
}
// Track which months have been imported
model SimHistoryImport {
id String @id @default(uuid())
month String @unique // YYYY-MM format
talkFile String? @map("talk_file") // Filename imported
smsFile String? @map("sms_file") // Filename imported
talkRecords Int @default(0) @map("talk_records") // Records imported
smsRecords Int @default(0) @map("sms_records") // Records imported
importedAt DateTime @default(now()) @map("imported_at")
status String @default("completed") // completed, failed, partial
@@map("sim_history_imports")
}