Assist_Design/apps/bff/prisma/schema.prisma
tema f49e5d7574 Enhance SIM management features and introduce new cancellation and plan change flows
- Added new models and request types for enhanced SIM cancellation and plan change functionalities.
- Implemented full cancellation flow with email notifications and confirmation handling.
- Introduced enhanced plan change request with Salesforce product mapping and scheduling.
- Updated UI components for better user experience during SIM management actions.
- Improved error handling and validation for cancellation and plan change requests.
2025-11-29 18:27:58 +09:00

258 lines
8.4 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.

generator client {
provider = "prisma-client-js"
}
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")
}