Assist_Design/apps/bff/prisma/schema.prisma
barsa 29ad4236d6 Enhance development scripts and update package dependencies
- Added a new script command `dev:studio` to facilitate studio management in development.
- Updated the Prisma dependency in BFF package to version 6.16.0 for improved features and bug fixes.
- Refactored Dockerfiles for BFF and Portal to enhance health check mechanisms during startup.
- Removed deprecated WhmcsApiMethodsService to streamline the integration services.
- Cleaned up various components and services in the SIM management module for better maintainability and clarity.
2025-12-02 18:56:38 +09:00

269 lines
9.1 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// =============================================================================
// 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"
url = env("DATABASE_URL")
}
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?
idempotencyKeys IdempotencyKey[]
invoicesMirror InvoiceMirror[]
subscriptionsMirror SubscriptionMirror[]
@@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 InvoiceMirror {
invoiceId Int @id @map("invoice_id")
userId String @map("user_id")
number String
status String
amountCents Int @map("amount_cents")
currency String @db.Char(3)
dueDate DateTime? @map("due_date") @db.Date
issuedAt DateTime? @map("issued_at")
paidAt DateTime? @map("paid_at")
updatedAt DateTime @updatedAt @map("updated_at")
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@index([userId, status])
@@index([userId, dueDate])
@@map("invoices_mirror")
}
model SubscriptionMirror {
serviceId Int @id @map("service_id")
userId String @map("user_id")
productName String @map("product_name")
domain String?
cycle String
status String
nextDue DateTime? @map("next_due")
amountCents Int @map("amount_cents")
currency String @db.Char(3)
registeredAt DateTime @map("registered_at")
updatedAt DateTime @updatedAt @map("updated_at")
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@index([userId, status])
@@index([userId, nextDue])
@@map("subscriptions_mirror")
}
model IdempotencyKey {
key String @id
userId String @map("user_id")
createdAt DateTime @default(now()) @map("created_at")
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@index([userId])
@@index([createdAt])
@@map("idempotency_keys")
}
model Job {
id String @id @default(uuid())
name String
data Json
status JobStatus @default(PENDING)
attempts Int @default(0)
maxRetries Int @default(3) @map("max_retries")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
processedAt DateTime? @map("processed_at")
failedAt DateTime? @map("failed_at")
error String?
@@index([status, createdAt])
@@map("jobs")
}
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 JobStatus {
PENDING
PROCESSING
COMPLETED
FAILED
RETRYING
}
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
}
// 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")
}