mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-26 18:42:49 +00:00
1286 lines
32 KiB
Plaintext
1286 lines
32 KiB
Plaintext
generator client {
|
|
provider = "prisma-client-js"
|
|
}
|
|
|
|
datasource db {
|
|
provider = "postgresql"
|
|
url = env("DATABASE_URL")
|
|
schemas = ["passenger"]
|
|
}
|
|
|
|
enum UserRole {
|
|
PASSENGER
|
|
AGENT
|
|
SUPERVISOR
|
|
ADMIN
|
|
STAFF
|
|
|
|
@@schema("passenger")
|
|
}
|
|
|
|
enum TripStatus {
|
|
SCHEDULED
|
|
BOARDING
|
|
EN_ROUTE
|
|
ARRIVED
|
|
CANCELLED
|
|
DELAYED
|
|
|
|
@@schema("passenger")
|
|
}
|
|
|
|
enum SeatKind {
|
|
STANDARD
|
|
PREMIUM
|
|
ACCESSIBLE
|
|
|
|
@@schema("passenger")
|
|
}
|
|
|
|
enum SeatStatus {
|
|
AVAILABLE
|
|
HELD
|
|
BOOKED
|
|
BLOCKED
|
|
|
|
@@schema("passenger")
|
|
}
|
|
|
|
enum PassengerCategory {
|
|
ADULT
|
|
CHILD
|
|
|
|
@@schema("passenger")
|
|
}
|
|
|
|
enum IdDocumentType {
|
|
NATIONAL_ID
|
|
PASSPORT
|
|
DRIVING_LICENSE
|
|
OTHER
|
|
|
|
@@schema("passenger")
|
|
}
|
|
|
|
enum Currency {
|
|
ETB
|
|
DJF
|
|
USD
|
|
|
|
@@schema("passenger")
|
|
}
|
|
|
|
model SeatClass {
|
|
id String @id @default(uuid())
|
|
name String @unique
|
|
description String?
|
|
basePrice Int
|
|
isActive Boolean @default(true)
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
coaches Coach[]
|
|
fareRules FareRule[]
|
|
routeFareRules RouteFareRule[]
|
|
|
|
@@schema("passenger")
|
|
}
|
|
|
|
enum BookingStatus {
|
|
DRAFT
|
|
PENDING_PAYMENT
|
|
CONFIRMED
|
|
CANCELLED
|
|
COMPLETED
|
|
NO_SHOW
|
|
REFUNDED
|
|
|
|
@@schema("passenger")
|
|
}
|
|
|
|
enum PaymentMethodType {
|
|
TELEBIRR
|
|
CBE_BIRR
|
|
EBIRR
|
|
CARD
|
|
WALLET
|
|
WAAFI
|
|
|
|
@@schema("passenger")
|
|
}
|
|
|
|
enum PaymentIntentStatus {
|
|
REQUIRES_ACTION
|
|
PROCESSING
|
|
SUCCEEDED
|
|
FAILED
|
|
CANCELLED
|
|
REFUNDED
|
|
|
|
@@schema("passenger")
|
|
}
|
|
|
|
enum WalletLedgerType {
|
|
CREDIT
|
|
DEBIT
|
|
|
|
@@schema("passenger")
|
|
}
|
|
|
|
enum NotificationCategory {
|
|
BOOKING
|
|
PAYMENT
|
|
DISRUPTION
|
|
PROMOTION
|
|
SYSTEM
|
|
|
|
@@schema("passenger")
|
|
}
|
|
|
|
enum StopStatus {
|
|
COMPLETED
|
|
APPROACHING
|
|
CURRENT
|
|
UPCOMING
|
|
|
|
@@schema("passenger")
|
|
}
|
|
|
|
enum SupportConversationStatus {
|
|
OPEN
|
|
RESOLVED
|
|
CLOSED
|
|
|
|
@@schema("passenger")
|
|
}
|
|
|
|
enum SupportSender {
|
|
USER
|
|
BOT
|
|
AGENT
|
|
|
|
@@schema("passenger")
|
|
}
|
|
|
|
enum LoyaltyTier {
|
|
BRONZE
|
|
SILVER
|
|
GOLD
|
|
PLATINUM
|
|
|
|
@@schema("passenger")
|
|
}
|
|
|
|
enum LoyaltyLedgerReason {
|
|
TRIP_COMPLETED
|
|
REWARD_REDEEMED
|
|
PROMO_BONUS
|
|
MANUAL_ADJUSTMENT
|
|
EXPIRY
|
|
|
|
@@schema("passenger")
|
|
}
|
|
|
|
enum FoodOrderStatus {
|
|
PENDING
|
|
PREPARING
|
|
READY
|
|
DELIVERED
|
|
CANCELLED
|
|
|
|
@@schema("passenger")
|
|
}
|
|
|
|
enum DevicePlatform {
|
|
IOS
|
|
ANDROID
|
|
WEB
|
|
|
|
@@schema("passenger")
|
|
}
|
|
|
|
model User {
|
|
id String @id @default(uuid())
|
|
email String @unique
|
|
phone String @unique
|
|
fullName String
|
|
passwordHash String
|
|
role UserRole @default(PASSENGER)
|
|
nationality String?
|
|
nationalityCode String?
|
|
passportNumber String?
|
|
nationalId String?
|
|
failedLoginAttempts Int @default(0)
|
|
lockedUntil DateTime?
|
|
blockedUntil DateTime?
|
|
lastLoginAt DateTime?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
faydaVerified Boolean @default(false)
|
|
faydaVerifiedAt DateTime?
|
|
faydaSub String? @unique
|
|
|
|
passenger Passenger?
|
|
agent Agent?
|
|
sessions Session[]
|
|
devices Device[]
|
|
preferences UserPreferences?
|
|
auditLogs AuditLog[]
|
|
fraudAlerts FraudAlert[]
|
|
|
|
faydaVerificationSessions FaydaVerificationSession[]
|
|
|
|
@@schema("passenger")
|
|
}
|
|
|
|
model Session {
|
|
id String @id @default(uuid())
|
|
userId String
|
|
token String @unique
|
|
expiresAt DateTime
|
|
ipAddress String?
|
|
userAgent String?
|
|
lastActivityAt DateTime @default(now())
|
|
createdAt DateTime @default(now())
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
|
|
@@schema("passenger")
|
|
}
|
|
|
|
model Passenger {
|
|
id String @id @default(uuid())
|
|
userId String @unique
|
|
defaultTravelerProfileId String?
|
|
preferredLanguage String?
|
|
createdAt DateTime @default(now())
|
|
user User @relation(fields: [userId], references: [id])
|
|
bookings Booking[]
|
|
loyalty LoyaltyAccount?
|
|
wallet WalletAccount?
|
|
notifications Notification[]
|
|
travelerProfiles TravelerProfile[]
|
|
savedRoutes SavedRoute[]
|
|
@@index([userId])
|
|
|
|
@@schema("passenger")
|
|
}
|
|
|
|
model TravelerProfile {
|
|
id String @id @default(uuid())
|
|
passengerId String
|
|
fullName String
|
|
relationship String
|
|
dateOfBirth DateTime?
|
|
nationalId String?
|
|
notes String?
|
|
createdAt DateTime @default(now())
|
|
passenger Passenger @relation(fields: [passengerId], references: [id])
|
|
|
|
@@schema("passenger")
|
|
}
|
|
|
|
model Station {
|
|
id String @id @default(uuid())
|
|
code String @unique
|
|
name String
|
|
city String
|
|
countryCode String?
|
|
isOperational Boolean @default(true)
|
|
timezone String @default("Africa/Addis_Ababa")
|
|
lat Decimal @db.Decimal(9, 6)
|
|
lng Decimal @db.Decimal(9, 6)
|
|
originSchedules TrainSchedule[] @relation("OriginTrips")
|
|
destinationSchedules TrainSchedule[] @relation("DestinationTrips")
|
|
stopTimes TripStopTime[]
|
|
crowdSignals StationCrowdSignal[]
|
|
@@index([city, countryCode])
|
|
|
|
@@schema("passenger")
|
|
}
|
|
|
|
model Train {
|
|
id String @id @default(uuid())
|
|
number String @unique
|
|
name String
|
|
operatorId String @default("op_edr")
|
|
operatorName String?
|
|
description String?
|
|
isActive Boolean @default(true)
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
schedules TrainSchedule[]
|
|
|
|
@@schema("passenger")
|
|
}
|
|
|
|
model TrainSchedule {
|
|
id String @id @default(uuid())
|
|
trainId String
|
|
routeId String?
|
|
originStationId String
|
|
destinationStationId String
|
|
departureAt DateTime
|
|
arrivalAt DateTime
|
|
durationMinutes Int
|
|
status TripStatus @default(SCHEDULED)
|
|
stopsCount Int @default(0)
|
|
reservedCount Int @default(0)
|
|
onTimePercent Int @default(100)
|
|
carbonRating String @default("A")
|
|
notes String?
|
|
train Train @relation(fields: [trainId], references: [id])
|
|
originStation Station @relation("OriginTrips", fields: [originStationId], references: [id])
|
|
destinationStation Station @relation("DestinationTrips", fields: [destinationStationId], references: [id])
|
|
coachAssignments CoachAssignment[]
|
|
bookings Booking[]
|
|
stopTimes TripStopTime[]
|
|
liveStatus TripLiveStatus?
|
|
menuItems MenuItem[]
|
|
journeySegments JourneySegment[]
|
|
@@index([departureAt, originStationId])
|
|
|
|
@@schema("passenger")
|
|
}
|
|
|
|
model TripStopTime {
|
|
id String @id @default(uuid())
|
|
scheduleId String
|
|
stationId String
|
|
sequence Int
|
|
plannedArrivalAt DateTime?
|
|
plannedDepartureAt DateTime?
|
|
actualArrivalAt DateTime?
|
|
status StopStatus @default(UPCOMING)
|
|
schedule TrainSchedule @relation(fields: [scheduleId], references: [id])
|
|
station Station @relation(fields: [stationId], references: [id])
|
|
@@unique([scheduleId, sequence])
|
|
|
|
@@schema("passenger")
|
|
}
|
|
|
|
model TripLiveStatus {
|
|
id String @id @default(uuid())
|
|
scheduleId String @unique
|
|
state String
|
|
currentLocationLabel String?
|
|
progressPercent Int @default(0)
|
|
delayMinutes Int @default(0)
|
|
currentSpeedKph Int?
|
|
platformLabel String?
|
|
updatedAt DateTime @updatedAt
|
|
schedule TrainSchedule @relation(fields: [scheduleId], references: [id])
|
|
|
|
@@schema("passenger")
|
|
}
|
|
|
|
model Coach {
|
|
id String @id @default(uuid())
|
|
coachNumber String @unique
|
|
label String
|
|
seatClassId String
|
|
coachType String?
|
|
mode String @default("seat") // 'seat', 'bed', 'convertible'
|
|
seatArrangement String?
|
|
bedArrangement String?
|
|
amenities Json?
|
|
totalUnits Int @default(0)
|
|
isActive Boolean @default(true)
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
seatClass SeatClass @relation(fields: [seatClassId], references: [id])
|
|
seats Seat[]
|
|
assignments CoachAssignment[]
|
|
|
|
@@schema("passenger")
|
|
}
|
|
|
|
model CoachAssignment {
|
|
id String @id @default(uuid())
|
|
scheduleId String
|
|
coachId String
|
|
positionNumber Int
|
|
isOperational Boolean @default(true)
|
|
createdAt DateTime @default(now())
|
|
schedule TrainSchedule @relation(fields: [scheduleId], references: [id])
|
|
coach Coach @relation(fields: [coachId], references: [id])
|
|
@@unique([scheduleId, positionNumber])
|
|
@@index([scheduleId])
|
|
|
|
@@schema("passenger")
|
|
}
|
|
|
|
model Seat {
|
|
id String @id @default(uuid())
|
|
coachId String
|
|
row Int
|
|
col String
|
|
label String
|
|
seatNumber String?
|
|
kind SeatKind @default(STANDARD)
|
|
status SeatStatus @default(AVAILABLE)
|
|
heldUntil DateTime?
|
|
isWindow Boolean @default(false)
|
|
isAisle Boolean @default(false)
|
|
bedPosition String? // 'lower', 'middle', 'upper'
|
|
premiumFeeMinor Int @default(0)
|
|
eligibility String?
|
|
coach Coach @relation(fields: [coachId], references: [id])
|
|
bookingSeats BookingSeat[]
|
|
blocks SeatBlock[]
|
|
@@unique([coachId, row, col])
|
|
@@unique([coachId, seatNumber])
|
|
|
|
@@schema("passenger")
|
|
}
|
|
|
|
model SeatHold {
|
|
id String @id @default(uuid())
|
|
scheduleId String
|
|
seatIds String[]
|
|
fareQuoteId String?
|
|
passengerId String
|
|
createdBy String?
|
|
expiresAt DateTime
|
|
createdAt DateTime @default(now())
|
|
@@index([expiresAt])
|
|
|
|
@@schema("passenger")
|
|
}
|
|
|
|
model FareRule {
|
|
id String @id @default(uuid())
|
|
tripId String?
|
|
route String?
|
|
nationality String? // Ethiopian, Djiboutian, Other
|
|
seatClassId String
|
|
baseFareMinor Int
|
|
seatClass SeatClass @relation(fields: [seatClassId], references: [id])
|
|
currency String @default("ETB")
|
|
refundable Boolean @default(true)
|
|
validFrom DateTime
|
|
validUntil DateTime?
|
|
createdAt DateTime @default(now())
|
|
|
|
@@schema("passenger")
|
|
}
|
|
|
|
model Booking {
|
|
id String @id @default(uuid())
|
|
bookingRef String @unique
|
|
passengerId String
|
|
scheduleId String
|
|
status BookingStatus @default(DRAFT)
|
|
currency String @default("ETB")
|
|
totalMinor Int
|
|
adultCount Int @default(1)
|
|
childCount Int @default(0)
|
|
displayCurrency Currency?
|
|
displayTotalMinor Int?
|
|
bookingType String @default("ONE_WAY")
|
|
contactEmail String?
|
|
contactPhone String?
|
|
userAgent String?
|
|
source String @default("WEB")
|
|
promoCode String?
|
|
paidAt DateTime?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
passenger Passenger @relation(fields: [passengerId], references: [id])
|
|
schedule TrainSchedule @relation(fields: [scheduleId], references: [id])
|
|
seats BookingSeat[]
|
|
paymentIntent PaymentIntent?
|
|
ticket Ticket?
|
|
foodOrders FoodOrder[]
|
|
agentBooking AgentBooking?
|
|
modifications BookingModification[]
|
|
cancellation BookingCancellation?
|
|
baggage BaggageBooking[]
|
|
@@index([passengerId, status])
|
|
|
|
@@schema("passenger")
|
|
}
|
|
|
|
model BookingSeat {
|
|
id String @id @default(uuid())
|
|
bookingId String
|
|
seatId String
|
|
passengerName String
|
|
dateOfBirth DateTime?
|
|
passengerCategory PassengerCategory @default(ADULT)
|
|
idDocumentType IdDocumentType?
|
|
idDocumentNumber String?
|
|
passportNumber String?
|
|
passportCountry String?
|
|
verifaydaVerified Boolean @default(false)
|
|
verifaydaData Json?
|
|
faydaVerifiedAt DateTime?
|
|
faydaSub String?
|
|
faydaVerifiedName String?
|
|
seatLabelSnapshot String?
|
|
fareMinor Int?
|
|
displayCurrency Currency?
|
|
displayFareMinor Int?
|
|
booking Booking @relation(fields: [bookingId], references: [id])
|
|
seat Seat @relation(fields: [seatId], references: [id])
|
|
|
|
@@schema("passenger")
|
|
}
|
|
|
|
model PaymentMethod {
|
|
id String @id @default(uuid())
|
|
userId String
|
|
type PaymentMethodType
|
|
displayName String
|
|
maskedHint String?
|
|
providerId String?
|
|
isDefault Boolean @default(false)
|
|
createdAt DateTime @default(now())
|
|
@@index([userId, isDefault])
|
|
|
|
@@schema("passenger")
|
|
}
|
|
|
|
model PaymentIntent {
|
|
id String @id @default(uuid())
|
|
bookingId String @unique
|
|
amountMinor Int
|
|
currency String @default("ETB")
|
|
method PaymentMethodType
|
|
provider String?
|
|
status PaymentIntentStatus @default(REQUIRES_ACTION)
|
|
providerRef String?
|
|
clientAction Json?
|
|
merchantOrderId String? @unique
|
|
providerOrderId String?
|
|
providerTxnId String?
|
|
rawInitiation Json?
|
|
paidAt DateTime?
|
|
refundedAt DateTime?
|
|
captureMethod String?
|
|
failureCode String?
|
|
failureMessage String?
|
|
expiresAt DateTime?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
booking Booking @relation(fields: [bookingId], references: [id])
|
|
refunds PaymentRefund[]
|
|
@@index([providerOrderId])
|
|
@@index([providerTxnId])
|
|
|
|
@@schema("passenger")
|
|
}
|
|
|
|
model PaymentWebhookEvent {
|
|
id String @id @default(uuid())
|
|
provider PaymentMethodType
|
|
externalEventId String
|
|
merchantOrderId String?
|
|
providerTxnId String?
|
|
signatureValid Boolean
|
|
status String
|
|
payload Json
|
|
receivedAt DateTime @default(now())
|
|
processedAt DateTime?
|
|
processingError String?
|
|
@@unique([provider, externalEventId])
|
|
@@index([merchantOrderId])
|
|
|
|
@@schema("passenger")
|
|
}
|
|
|
|
model PaymentRefund {
|
|
id String @id @default(uuid())
|
|
paymentIntentId String
|
|
amountMinor Int
|
|
reason String?
|
|
providerRefundId String?
|
|
status String
|
|
createdAt DateTime @default(now())
|
|
paymentIntent PaymentIntent @relation(fields: [paymentIntentId], references: [id])
|
|
|
|
@@schema("passenger")
|
|
}
|
|
|
|
model Ticket {
|
|
id String @id @default(uuid())
|
|
bookingId String @unique
|
|
bookingRef String
|
|
status String @default("CONFIRMED")
|
|
qrPayload String
|
|
barcodePayload String?
|
|
pdfUrl String?
|
|
deliveryChannel String @default("EMAIL")
|
|
issuedAt DateTime @default(now())
|
|
validatedAt DateTime?
|
|
validatorId String?
|
|
booking Booking @relation(fields: [bookingId], references: [id])
|
|
validationLogs GateValidationLog[]
|
|
|
|
@@schema("passenger")
|
|
}
|
|
|
|
model LoyaltyAccount {
|
|
id String @id @default(uuid())
|
|
passengerId String @unique
|
|
pointsBalance Int @default(0)
|
|
lifetimePoints Int @default(0)
|
|
tier LoyaltyTier @default(BRONZE)
|
|
tierUpdatedAt DateTime?
|
|
updatedAt DateTime @updatedAt
|
|
passenger Passenger @relation(fields: [passengerId], references: [id])
|
|
ledger LoyaltyLedgerEntry[]
|
|
rewards LoyaltyReward[]
|
|
|
|
@@schema("passenger")
|
|
}
|
|
|
|
model LoyaltyLedgerEntry {
|
|
id String @id @default(uuid())
|
|
accountId String
|
|
delta Int
|
|
reason LoyaltyLedgerReason
|
|
bookingId String?
|
|
balanceAfter Int
|
|
createdAt DateTime @default(now())
|
|
account LoyaltyAccount @relation(fields: [accountId], references: [id])
|
|
|
|
@@schema("passenger")
|
|
}
|
|
|
|
model LoyaltyReward {
|
|
id String @id @default(uuid())
|
|
accountId String
|
|
title String
|
|
costPoints Int
|
|
available Boolean @default(true)
|
|
description String?
|
|
account LoyaltyAccount @relation(fields: [accountId], references: [id])
|
|
|
|
@@schema("passenger")
|
|
}
|
|
|
|
model WalletAccount {
|
|
id String @id @default(uuid())
|
|
passengerId String @unique
|
|
balanceMinor Int @default(0)
|
|
status String @default("ACTIVE")
|
|
holdMinor Int @default(0)
|
|
currency String @default("ETB")
|
|
updatedAt DateTime @updatedAt
|
|
passenger Passenger @relation(fields: [passengerId], references: [id])
|
|
ledger WalletLedgerEntry[]
|
|
@@index([passengerId])
|
|
|
|
@@schema("passenger")
|
|
}
|
|
|
|
model WalletLedgerEntry {
|
|
id String @id @default(uuid())
|
|
walletId String
|
|
type WalletLedgerType
|
|
amountMinor Int
|
|
balanceAfterMinor Int
|
|
description String
|
|
relatedBookingId String?
|
|
createdAt DateTime @default(now())
|
|
wallet WalletAccount @relation(fields: [walletId], references: [id])
|
|
|
|
@@schema("passenger")
|
|
}
|
|
|
|
model Notification {
|
|
id String @id @default(uuid())
|
|
passengerId String
|
|
title String
|
|
body String
|
|
category NotificationCategory
|
|
read Boolean @default(false)
|
|
deepLink String?
|
|
metadata Json?
|
|
createdAt DateTime @default(now())
|
|
passenger Passenger @relation(fields: [passengerId], references: [id])
|
|
|
|
@@schema("passenger")
|
|
}
|
|
|
|
model Promotion {
|
|
id String @id @default(uuid())
|
|
title String
|
|
subtitle String?
|
|
code String @unique
|
|
percentOff Int?
|
|
amountOffMinor Int?
|
|
validUntil DateTime
|
|
ctaLabel String?
|
|
deepLink String?
|
|
active Boolean @default(true)
|
|
createdAt DateTime @default(now())
|
|
|
|
@@schema("passenger")
|
|
}
|
|
|
|
model StationCrowdSignal {
|
|
id String @id @default(uuid())
|
|
stationId String
|
|
level String
|
|
label String
|
|
statusLabel String
|
|
confidence Int?
|
|
observedAt DateTime?
|
|
updatedAt DateTime @updatedAt
|
|
station Station @relation(fields: [stationId], references: [id])
|
|
|
|
@@schema("passenger")
|
|
}
|
|
|
|
model WeatherAlert {
|
|
id String @id @default(uuid())
|
|
region String
|
|
severity String
|
|
title String
|
|
message String
|
|
validUntil DateTime
|
|
createdAt DateTime @default(now())
|
|
|
|
@@schema("passenger")
|
|
}
|
|
|
|
model MenuCategory {
|
|
id String @id @default(uuid())
|
|
name String
|
|
items MenuItem[]
|
|
|
|
@@schema("passenger")
|
|
}
|
|
|
|
model MenuItem {
|
|
id String @id @default(uuid())
|
|
scheduleId String
|
|
categoryId String
|
|
name String
|
|
priceMinor Int
|
|
currency String @default("ETB")
|
|
available Boolean @default(true)
|
|
availableUntil DateTime?
|
|
schedule TrainSchedule @relation(fields: [scheduleId], references: [id])
|
|
category MenuCategory @relation(fields: [categoryId], references: [id])
|
|
|
|
@@schema("passenger")
|
|
}
|
|
|
|
model FoodOrder {
|
|
id String @id @default(uuid())
|
|
bookingId String
|
|
status FoodOrderStatus @default(PENDING)
|
|
totalMinor Int
|
|
currency String @default("ETB")
|
|
specialInstructions String?
|
|
estimatedReadyAt DateTime?
|
|
createdAt DateTime @default(now())
|
|
booking Booking @relation(fields: [bookingId], references: [id])
|
|
items FoodOrderItem[]
|
|
|
|
@@schema("passenger")
|
|
}
|
|
|
|
model FoodOrderItem {
|
|
id String @id @default(uuid())
|
|
orderId String
|
|
menuItemId String
|
|
name String
|
|
quantity Int
|
|
unitPriceMinor Int?
|
|
lineTotalMinor Int
|
|
order FoodOrder @relation(fields: [orderId], references: [id])
|
|
|
|
@@schema("passenger")
|
|
}
|
|
|
|
model FaqCategory {
|
|
id String @id @default(uuid())
|
|
title String
|
|
iconKey String?
|
|
articles FaqArticle[]
|
|
|
|
@@schema("passenger")
|
|
}
|
|
|
|
model FaqArticle {
|
|
id String @id @default(uuid())
|
|
categoryId String
|
|
question String
|
|
answerMarkdown String
|
|
rank Int @default(0)
|
|
category FaqCategory @relation(fields: [categoryId], references: [id])
|
|
|
|
@@schema("passenger")
|
|
}
|
|
|
|
model SupportConversation {
|
|
id String @id @default(uuid())
|
|
userId String
|
|
assignedAgentId String?
|
|
status SupportConversationStatus @default(OPEN)
|
|
createdAt DateTime @default(now())
|
|
messages SupportMessage[]
|
|
|
|
@@schema("passenger")
|
|
}
|
|
|
|
model SupportMessage {
|
|
id String @id @default(uuid())
|
|
conversationId String
|
|
sender SupportSender
|
|
text String
|
|
attachments Json?
|
|
createdAt DateTime @default(now())
|
|
conversation SupportConversation @relation(fields: [conversationId], references: [id])
|
|
|
|
@@schema("passenger")
|
|
}
|
|
|
|
model UserPreferences {
|
|
id String @id @default(uuid())
|
|
userId String @unique
|
|
pushEnabled Boolean @default(true)
|
|
emailEnabled Boolean @default(true)
|
|
smsEnabled Boolean @default(false)
|
|
promosEnabled Boolean @default(true)
|
|
biometricEnabled Boolean @default(false)
|
|
twoFactorEnabled Boolean @default(false)
|
|
defaultPaymentMethodId String?
|
|
autoDownloadTickets Boolean @default(true)
|
|
dataSharing Boolean @default(false)
|
|
locale String @default("en")
|
|
darkMode Boolean @default(false)
|
|
language String @default("en")
|
|
user User @relation(fields: [userId], references: [id])
|
|
|
|
@@schema("passenger")
|
|
}
|
|
|
|
model Device {
|
|
id String @id @default(uuid())
|
|
userId String
|
|
platform DevicePlatform
|
|
name String
|
|
pushToken String?
|
|
trusted Boolean @default(false)
|
|
lastSeenAt DateTime @default(now())
|
|
user User @relation(fields: [userId], references: [id])
|
|
|
|
@@schema("passenger")
|
|
}
|
|
|
|
model SavedRoute {
|
|
id String @id @default(uuid())
|
|
passengerId String
|
|
fromStationId String
|
|
toStationId String
|
|
fromName String
|
|
toName String
|
|
tripCount Int @default(0)
|
|
createdAt DateTime @default(now())
|
|
passenger Passenger @relation(fields: [passengerId], references: [id])
|
|
|
|
@@schema("passenger")
|
|
}
|
|
|
|
model Journey {
|
|
id String @id @default(uuid())
|
|
passengerId String
|
|
status String
|
|
totalMinor Int
|
|
currency String @default("ETB")
|
|
createdAt DateTime @default(now())
|
|
journeySegments JourneySegment[]
|
|
|
|
@@schema("passenger")
|
|
}
|
|
|
|
model JourneySegment {
|
|
id String @id @default(uuid())
|
|
journeyId String
|
|
scheduleId String
|
|
segmentOrder Int
|
|
seatId String?
|
|
coachId String?
|
|
departureStationId String
|
|
arrivalStationId String
|
|
journey Journey @relation(fields: [journeyId], references: [id])
|
|
schedule TrainSchedule @relation(fields: [scheduleId], references: [id])
|
|
|
|
@@schema("passenger")
|
|
}
|
|
|
|
model OtpCode {
|
|
id String @id @default(uuid())
|
|
userId String?
|
|
email String?
|
|
phone String?
|
|
code String
|
|
purpose String
|
|
expiresAt DateTime
|
|
verified Boolean @default(false)
|
|
createdAt DateTime @default(now())
|
|
@@index([email, phone])
|
|
|
|
@@schema("passenger")
|
|
}
|
|
|
|
model PasswordResetToken {
|
|
id String @id @default(uuid())
|
|
userId String
|
|
token String @unique
|
|
expiresAt DateTime
|
|
used Boolean @default(false)
|
|
createdAt DateTime @default(now())
|
|
@@index([userId])
|
|
|
|
@@schema("passenger")
|
|
}
|
|
|
|
model Route {
|
|
id String @id @default(uuid())
|
|
code String @unique
|
|
name String
|
|
description String?
|
|
effectiveFrom DateTime
|
|
effectiveUntil DateTime?
|
|
active Boolean @default(true)
|
|
createdAt DateTime @default(now())
|
|
stops RouteStop[]
|
|
fareRules RouteFareRule[]
|
|
|
|
@@schema("passenger")
|
|
}
|
|
|
|
model RouteStop {
|
|
id String @id @default(uuid())
|
|
routeId String
|
|
stationId String
|
|
sequence Int
|
|
distanceKm Int?
|
|
createdAt DateTime @default(now())
|
|
route Route @relation(fields: [routeId], references: [id], onDelete: Cascade)
|
|
@@unique([routeId, sequence])
|
|
@@index([routeId, stationId])
|
|
|
|
@@schema("passenger")
|
|
}
|
|
|
|
model RouteFareRule {
|
|
id String @id @default(uuid())
|
|
routeId String
|
|
seatClassId String
|
|
passengerCategory PassengerCategory @default(ADULT)
|
|
baseFareMinor Int
|
|
discountPercent Int?
|
|
taxPercent Int?
|
|
surchargeMinor Int?
|
|
currency String @default("ETB")
|
|
validFrom DateTime
|
|
validUntil DateTime?
|
|
createdAt DateTime @default(now())
|
|
route Route @relation(fields: [routeId], references: [id], onDelete: Cascade)
|
|
seatClass SeatClass @relation(fields: [seatClassId], references: [id])
|
|
@@index([routeId, seatClassId])
|
|
|
|
@@schema("passenger")
|
|
}
|
|
|
|
model Agent {
|
|
id String @id @default(uuid())
|
|
userId String @unique
|
|
agentCode String @unique
|
|
stationId String?
|
|
commissionRate Int @default(5)
|
|
active Boolean @default(true)
|
|
createdAt DateTime @default(now())
|
|
user User @relation(fields: [userId], references: [id])
|
|
bookings AgentBooking[]
|
|
shifts AgentShift[]
|
|
commissions AgentCommission[]
|
|
|
|
@@schema("passenger")
|
|
}
|
|
|
|
model AgentBooking {
|
|
id String @id @default(uuid())
|
|
agentId String
|
|
bookingId String @unique
|
|
paymentMethod String
|
|
cashReceived Int?
|
|
changeGiven Int?
|
|
paperTicket Boolean @default(false)
|
|
createdAt DateTime @default(now())
|
|
agent Agent @relation(fields: [agentId], references: [id])
|
|
booking Booking @relation(fields: [bookingId], references: [id])
|
|
|
|
@@schema("passenger")
|
|
}
|
|
|
|
model AgentShift {
|
|
id String @id @default(uuid())
|
|
agentId String
|
|
openedAt DateTime @default(now())
|
|
closedAt DateTime?
|
|
openingBalance Int @default(0)
|
|
closingBalance Int?
|
|
reconciled Boolean @default(false)
|
|
notes String?
|
|
agent Agent @relation(fields: [agentId], references: [id])
|
|
@@index([agentId, openedAt])
|
|
|
|
@@schema("passenger")
|
|
}
|
|
|
|
model AgentCommission {
|
|
id String @id @default(uuid())
|
|
agentId String
|
|
bookingId String
|
|
amountMinor Int
|
|
rate Int
|
|
paidAt DateTime?
|
|
createdAt DateTime @default(now())
|
|
agent Agent @relation(fields: [agentId], references: [id])
|
|
@@index([agentId, paidAt])
|
|
|
|
@@schema("passenger")
|
|
}
|
|
|
|
model BookingModification {
|
|
id String @id @default(uuid())
|
|
bookingId String
|
|
modifiedBy String
|
|
modificationType String
|
|
oldData Json
|
|
newData Json
|
|
fareAdjustment Int @default(0)
|
|
reason String?
|
|
createdAt DateTime @default(now())
|
|
booking Booking @relation(fields: [bookingId], references: [id])
|
|
@@index([bookingId])
|
|
|
|
@@schema("passenger")
|
|
}
|
|
|
|
model BookingCancellation {
|
|
id String @id @default(uuid())
|
|
bookingId String @unique
|
|
cancelledBy String
|
|
reason String?
|
|
refundAmount Int
|
|
refundMethod String
|
|
refundStatus String
|
|
processedAt DateTime?
|
|
createdAt DateTime @default(now())
|
|
booking Booking @relation(fields: [bookingId], references: [id])
|
|
|
|
@@schema("passenger")
|
|
}
|
|
|
|
model GateValidationLog {
|
|
id String @id @default(uuid())
|
|
ticketId String
|
|
validatorId String
|
|
gateId String?
|
|
status String
|
|
reason String?
|
|
validatedAt DateTime @default(now())
|
|
ticket Ticket @relation(fields: [ticketId], references: [id])
|
|
@@index([ticketId])
|
|
@@index([validatorId])
|
|
|
|
@@schema("passenger")
|
|
}
|
|
|
|
model BaggageAllowance {
|
|
id String @id @default(uuid())
|
|
seatClassId String
|
|
maxWeightKg Int
|
|
maxPiecesCount Int
|
|
excessFeePerKg Int
|
|
currency String @default("ETB")
|
|
createdAt DateTime @default(now())
|
|
|
|
@@schema("passenger")
|
|
}
|
|
|
|
model BaggageBooking {
|
|
id String @id @default(uuid())
|
|
bookingId String
|
|
weightKg Int
|
|
piecesCount Int
|
|
excessFeeMinor Int @default(0)
|
|
paid Boolean @default(false)
|
|
createdAt DateTime @default(now())
|
|
booking Booking @relation(fields: [bookingId], references: [id])
|
|
@@index([bookingId])
|
|
|
|
@@schema("passenger")
|
|
}
|
|
|
|
model AuditLog {
|
|
id String @id @default(uuid())
|
|
userId String?
|
|
action String
|
|
entityType String
|
|
entityId String?
|
|
oldData Json?
|
|
newData Json?
|
|
ipAddress String?
|
|
userAgent String?
|
|
createdAt DateTime @default(now())
|
|
user User? @relation(fields: [userId], references: [id])
|
|
@@index([userId, createdAt])
|
|
@@index([entityType, entityId])
|
|
|
|
@@schema("passenger")
|
|
}
|
|
|
|
model NotificationTemplate {
|
|
id String @id @default(uuid())
|
|
code String @unique
|
|
channel String
|
|
subject String?
|
|
bodyTemplate String
|
|
active Boolean @default(true)
|
|
createdAt DateTime @default(now())
|
|
|
|
@@schema("passenger")
|
|
}
|
|
|
|
model SeatBlock {
|
|
id String @id @default(uuid())
|
|
seatId String
|
|
reason String
|
|
blockedBy String
|
|
approvedBy String?
|
|
blockedAt DateTime @default(now())
|
|
unblockAt DateTime?
|
|
seat Seat @relation(fields: [seatId], references: [id])
|
|
@@index([seatId])
|
|
|
|
@@schema("passenger")
|
|
}
|
|
|
|
model OperationalReport {
|
|
id String @id @default(uuid())
|
|
reportType String
|
|
dateFrom DateTime
|
|
dateTo DateTime
|
|
data Json
|
|
generatedBy String?
|
|
createdAt DateTime @default(now())
|
|
@@index([reportType, dateFrom])
|
|
|
|
@@schema("passenger")
|
|
}
|
|
|
|
model FraudRule {
|
|
id String @id @default(uuid())
|
|
type String @unique
|
|
enabled Boolean @default(true)
|
|
threshold Float
|
|
config Json?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@schema("passenger")
|
|
}
|
|
|
|
model FraudAlert {
|
|
id String @id @default(uuid())
|
|
userId String
|
|
eventType String
|
|
triggeredRules String[]
|
|
context Json
|
|
severity String @default("MEDIUM")
|
|
acknowledged Boolean @default(false)
|
|
createdAt DateTime @default(now())
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
@@index([userId, createdAt])
|
|
@@index([acknowledged])
|
|
|
|
@@schema("passenger")
|
|
}
|
|
|
|
model CurrencyExchangeRate {
|
|
id String @id @default(uuid())
|
|
fromCurrency Currency
|
|
toCurrency Currency
|
|
rate Decimal @db.Decimal(18, 6)
|
|
effectiveDate DateTime @default(now())
|
|
source String @default("MANUAL")
|
|
createdAt DateTime @default(now())
|
|
@@unique([fromCurrency, toCurrency, effectiveDate])
|
|
@@index([fromCurrency, toCurrency])
|
|
|
|
@@schema("passenger")
|
|
}
|
|
|
|
model VerifaydaVerification {
|
|
id String @id @default(uuid())
|
|
bookingId String?
|
|
nationalId String
|
|
requestPayload Json
|
|
responsePayload Json?
|
|
verified Boolean @default(false)
|
|
failureReason String?
|
|
verifiedAt DateTime?
|
|
createdAt DateTime @default(now())
|
|
@@index([nationalId])
|
|
@@index([bookingId])
|
|
|
|
@@schema("passenger")
|
|
}
|
|
|
|
model SavedPassengerProfile {
|
|
id String @id @default(uuid())
|
|
userId String?
|
|
deviceId String?
|
|
passengerName String
|
|
dateOfBirth DateTime
|
|
idDocumentType IdDocumentType
|
|
passportNumber String?
|
|
passportCountry String?
|
|
nationality String?
|
|
phone String?
|
|
email String?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
@@index([userId])
|
|
@@index([deviceId])
|
|
|
|
@@schema("passenger")
|
|
}
|
|
|
|
model FaydaVerificationSession {
|
|
id String @id @default(uuid())
|
|
state String @unique
|
|
codeVerifier String
|
|
purpose String @default("PURCHASE")
|
|
platform String @default("WEB") // WEB | MOBILE — recorded for audit
|
|
saveToAccount Boolean @default(false)
|
|
status String @default("PENDING")
|
|
errorCode String?
|
|
errorDescription String?
|
|
createdAt DateTime @default(now())
|
|
expiresAt DateTime
|
|
completedAt DateTime?
|
|
|
|
userId String?
|
|
bookingId String?
|
|
|
|
user User? @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
|
|
@@index([userId])
|
|
@@index([bookingId])
|
|
@@index([state])
|
|
@@index([expiresAt])
|
|
|
|
@@schema("passenger")
|
|
}
|
|
|