mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-26 18:42:49 +00:00
574 lines
14 KiB
Plaintext
574 lines
14 KiB
Plaintext
generator client {
|
|
provider = "prisma-client-js"
|
|
}
|
|
|
|
datasource db {
|
|
provider = "postgresql"
|
|
url = env("DATABASE_URL")
|
|
}
|
|
|
|
enum UserRole {
|
|
PASSENGER
|
|
ADMIN
|
|
STAFF
|
|
}
|
|
|
|
enum TripStatus {
|
|
SCHEDULED
|
|
BOARDING
|
|
EN_ROUTE
|
|
ARRIVED
|
|
CANCELLED
|
|
DELAYED
|
|
}
|
|
|
|
enum SeatKind {
|
|
STANDARD
|
|
PREMIUM
|
|
ACCESSIBLE
|
|
}
|
|
|
|
enum SeatStatus {
|
|
AVAILABLE
|
|
HELD
|
|
BOOKED
|
|
BLOCKED
|
|
}
|
|
|
|
enum ServiceClass {
|
|
ECONOMY
|
|
BUSINESS
|
|
FIRST
|
|
}
|
|
|
|
enum BookingStatus {
|
|
DRAFT
|
|
PENDING_PAYMENT
|
|
CONFIRMED
|
|
CANCELLED
|
|
COMPLETED
|
|
NO_SHOW
|
|
}
|
|
|
|
enum PaymentMethodType {
|
|
TELEBIRR
|
|
CBE_BIRR
|
|
EBIRR
|
|
CARD
|
|
WALLET
|
|
}
|
|
|
|
enum PaymentIntentStatus {
|
|
REQUIRES_ACTION
|
|
PROCESSING
|
|
SUCCEEDED
|
|
FAILED
|
|
CANCELLED
|
|
}
|
|
|
|
enum WalletLedgerType {
|
|
CREDIT
|
|
DEBIT
|
|
}
|
|
|
|
enum NotificationCategory {
|
|
BOOKING
|
|
PAYMENT
|
|
DISRUPTION
|
|
PROMOTION
|
|
SYSTEM
|
|
}
|
|
|
|
enum StopStatus {
|
|
COMPLETED
|
|
APPROACHING
|
|
CURRENT
|
|
UPCOMING
|
|
}
|
|
|
|
enum SupportConversationStatus {
|
|
OPEN
|
|
RESOLVED
|
|
CLOSED
|
|
}
|
|
|
|
enum SupportSender {
|
|
USER
|
|
BOT
|
|
AGENT
|
|
}
|
|
|
|
enum LoyaltyTier {
|
|
BRONZE
|
|
SILVER
|
|
GOLD
|
|
PLATINUM
|
|
}
|
|
|
|
enum LoyaltyLedgerReason {
|
|
TRIP_COMPLETED
|
|
REWARD_REDEEMED
|
|
PROMO_BONUS
|
|
MANUAL_ADJUSTMENT
|
|
EXPIRY
|
|
}
|
|
|
|
enum FoodOrderStatus {
|
|
PENDING
|
|
PREPARING
|
|
READY
|
|
DELIVERED
|
|
CANCELLED
|
|
}
|
|
|
|
enum DevicePlatform {
|
|
IOS
|
|
ANDROID
|
|
WEB
|
|
}
|
|
|
|
model User {
|
|
id String @id @default(uuid())
|
|
email String @unique
|
|
phone String @unique
|
|
fullName String
|
|
passwordHash String
|
|
role UserRole @default(PASSENGER)
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
passenger Passenger?
|
|
sessions Session[]
|
|
devices Device[]
|
|
preferences UserPreferences?
|
|
}
|
|
|
|
model Session {
|
|
id String @id @default(uuid())
|
|
userId String
|
|
token String @unique
|
|
expiresAt DateTime
|
|
createdAt DateTime @default(now())
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
}
|
|
|
|
model Passenger {
|
|
id String @id @default(uuid())
|
|
userId String @unique
|
|
createdAt DateTime @default(now())
|
|
user User @relation(fields: [userId], references: [id])
|
|
bookings Booking[]
|
|
loyalty LoyaltyAccount?
|
|
wallet WalletAccount?
|
|
notifications Notification[]
|
|
travelerProfiles TravelerProfile[]
|
|
savedRoutes SavedRoute[]
|
|
}
|
|
|
|
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])
|
|
}
|
|
|
|
model Station {
|
|
id String @id @default(uuid())
|
|
code String @unique
|
|
name String
|
|
city String
|
|
timezone String @default("Africa/Addis_Ababa")
|
|
lat Decimal @db.Decimal(9, 6)
|
|
lng Decimal @db.Decimal(9, 6)
|
|
originTrips Trip[] @relation("OriginTrips")
|
|
destinationTrips Trip[] @relation("DestinationTrips")
|
|
stopTimes TripStopTime[]
|
|
crowdSignals StationCrowdSignal[]
|
|
}
|
|
|
|
model TrainService {
|
|
id String @id @default(uuid())
|
|
number String @unique
|
|
name String
|
|
operatorId String @default("op_edr")
|
|
trips Trip[]
|
|
}
|
|
|
|
model Trip {
|
|
id String @id @default(uuid())
|
|
serviceId String
|
|
originStationId String
|
|
destinationStationId String
|
|
departureAt DateTime
|
|
arrivalAt DateTime
|
|
durationMinutes Int
|
|
status TripStatus @default(SCHEDULED)
|
|
stopsCount Int @default(0)
|
|
onTimePercent Int @default(100)
|
|
carbonRating String @default("A")
|
|
service TrainService @relation(fields: [serviceId], references: [id])
|
|
originStation Station @relation("OriginTrips", fields: [originStationId], references: [id])
|
|
destinationStation Station @relation("DestinationTrips", fields: [destinationStationId], references: [id])
|
|
coaches Coach[]
|
|
bookings Booking[]
|
|
stopTimes TripStopTime[]
|
|
liveStatus TripLiveStatus?
|
|
menuItems MenuItem[]
|
|
}
|
|
|
|
model TripStopTime {
|
|
id String @id @default(uuid())
|
|
tripId String
|
|
stationId String
|
|
sequence Int
|
|
plannedArrivalAt DateTime?
|
|
plannedDepartureAt DateTime?
|
|
actualArrivalAt DateTime?
|
|
status StopStatus @default(UPCOMING)
|
|
trip Trip @relation(fields: [tripId], references: [id])
|
|
station Station @relation(fields: [stationId], references: [id])
|
|
@@unique([tripId, sequence])
|
|
}
|
|
|
|
model TripLiveStatus {
|
|
id String @id @default(uuid())
|
|
tripId String @unique
|
|
state String
|
|
currentLocationLabel String?
|
|
progressPercent Int @default(0)
|
|
delayMinutes Int @default(0)
|
|
currentSpeedKph Int?
|
|
platformLabel String?
|
|
updatedAt DateTime @updatedAt
|
|
trip Trip @relation(fields: [tripId], references: [id])
|
|
}
|
|
|
|
model Coach {
|
|
id String @id @default(uuid())
|
|
tripId String
|
|
label String
|
|
serviceClass ServiceClass
|
|
trip Trip @relation(fields: [tripId], references: [id])
|
|
seats Seat[]
|
|
@@unique([tripId, label])
|
|
}
|
|
|
|
model Seat {
|
|
id String @id @default(uuid())
|
|
coachId String
|
|
row Int
|
|
col String
|
|
label String
|
|
kind SeatKind @default(STANDARD)
|
|
status SeatStatus @default(AVAILABLE)
|
|
heldUntil DateTime?
|
|
coach Coach @relation(fields: [coachId], references: [id])
|
|
bookingSeats BookingSeat[]
|
|
@@unique([coachId, row, col])
|
|
}
|
|
|
|
model SeatHold {
|
|
id String @id @default(uuid())
|
|
tripId String
|
|
seatIds String[]
|
|
fareQuoteId String?
|
|
passengerId String
|
|
expiresAt DateTime
|
|
createdAt DateTime @default(now())
|
|
}
|
|
|
|
model FareRule {
|
|
id String @id @default(uuid())
|
|
tripId String?
|
|
route String?
|
|
serviceClass ServiceClass
|
|
baseFareMinor Int
|
|
currency String @default("ETB")
|
|
refundable Boolean @default(true)
|
|
validFrom DateTime
|
|
validUntil DateTime?
|
|
createdAt DateTime @default(now())
|
|
}
|
|
|
|
model Booking {
|
|
id String @id @default(uuid())
|
|
bookingRef String @unique
|
|
passengerId String
|
|
tripId String
|
|
status BookingStatus @default(DRAFT)
|
|
currency String @default("ETB")
|
|
totalMinor Int
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
passenger Passenger @relation(fields: [passengerId], references: [id])
|
|
trip Trip @relation(fields: [tripId], references: [id])
|
|
seats BookingSeat[]
|
|
paymentIntent PaymentIntent?
|
|
ticket Ticket?
|
|
foodOrders FoodOrder[]
|
|
}
|
|
|
|
model BookingSeat {
|
|
id String @id @default(uuid())
|
|
bookingId String
|
|
seatId String
|
|
passengerName String
|
|
idDocumentType String?
|
|
idDocumentNumber String?
|
|
booking Booking @relation(fields: [bookingId], references: [id])
|
|
seat Seat @relation(fields: [seatId], references: [id])
|
|
}
|
|
|
|
model PaymentMethod {
|
|
id String @id @default(uuid())
|
|
userId String
|
|
type PaymentMethodType
|
|
displayName String
|
|
maskedHint String?
|
|
isDefault Boolean @default(false)
|
|
createdAt DateTime @default(now())
|
|
}
|
|
|
|
model PaymentIntent {
|
|
id String @id @default(uuid())
|
|
bookingId String @unique
|
|
amountMinor Int
|
|
currency String @default("ETB")
|
|
method PaymentMethodType
|
|
status PaymentIntentStatus @default(REQUIRES_ACTION)
|
|
providerRef String?
|
|
clientAction Json?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
booking Booking @relation(fields: [bookingId], references: [id])
|
|
}
|
|
|
|
model Ticket {
|
|
id String @id @default(uuid())
|
|
bookingId String @unique
|
|
bookingRef String
|
|
status String @default("CONFIRMED")
|
|
qrPayload String
|
|
issuedAt DateTime @default(now())
|
|
validatedAt DateTime?
|
|
validatorId String?
|
|
booking Booking @relation(fields: [bookingId], references: [id])
|
|
}
|
|
|
|
model LoyaltyAccount {
|
|
id String @id @default(uuid())
|
|
passengerId String @unique
|
|
pointsBalance Int @default(0)
|
|
tier LoyaltyTier @default(BRONZE)
|
|
updatedAt DateTime @updatedAt
|
|
passenger Passenger @relation(fields: [passengerId], references: [id])
|
|
ledger LoyaltyLedgerEntry[]
|
|
rewards LoyaltyReward[]
|
|
}
|
|
|
|
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])
|
|
}
|
|
|
|
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])
|
|
}
|
|
|
|
model WalletAccount {
|
|
id String @id @default(uuid())
|
|
passengerId String @unique
|
|
balanceMinor Int @default(0)
|
|
currency String @default("ETB")
|
|
updatedAt DateTime @updatedAt
|
|
passenger Passenger @relation(fields: [passengerId], references: [id])
|
|
ledger WalletLedgerEntry[]
|
|
}
|
|
|
|
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])
|
|
}
|
|
|
|
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])
|
|
}
|
|
|
|
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())
|
|
}
|
|
|
|
model StationCrowdSignal {
|
|
id String @id @default(uuid())
|
|
stationId String
|
|
level String
|
|
label String
|
|
statusLabel String
|
|
updatedAt DateTime @updatedAt
|
|
station Station @relation(fields: [stationId], references: [id])
|
|
}
|
|
|
|
model WeatherAlert {
|
|
id String @id @default(uuid())
|
|
region String
|
|
severity String
|
|
title String
|
|
message String
|
|
validUntil DateTime
|
|
createdAt DateTime @default(now())
|
|
}
|
|
|
|
model MenuCategory {
|
|
id String @id @default(uuid())
|
|
name String
|
|
items MenuItem[]
|
|
}
|
|
|
|
model MenuItem {
|
|
id String @id @default(uuid())
|
|
tripId String
|
|
categoryId String
|
|
name String
|
|
priceMinor Int
|
|
currency String @default("ETB")
|
|
available Boolean @default(true)
|
|
trip Trip @relation(fields: [tripId], references: [id])
|
|
category MenuCategory @relation(fields: [categoryId], references: [id])
|
|
}
|
|
|
|
model FoodOrder {
|
|
id String @id @default(uuid())
|
|
bookingId String
|
|
status FoodOrderStatus @default(PENDING)
|
|
totalMinor Int
|
|
currency String @default("ETB")
|
|
createdAt DateTime @default(now())
|
|
booking Booking @relation(fields: [bookingId], references: [id])
|
|
items FoodOrderItem[]
|
|
}
|
|
|
|
model FoodOrderItem {
|
|
id String @id @default(uuid())
|
|
orderId String
|
|
menuItemId String
|
|
name String
|
|
quantity Int
|
|
lineTotalMinor Int
|
|
order FoodOrder @relation(fields: [orderId], references: [id])
|
|
}
|
|
|
|
model FaqCategory {
|
|
id String @id @default(uuid())
|
|
title String
|
|
iconKey String?
|
|
articles FaqArticle[]
|
|
}
|
|
|
|
model FaqArticle {
|
|
id String @id @default(uuid())
|
|
categoryId String
|
|
question String
|
|
answerMarkdown String
|
|
rank Int @default(0)
|
|
category FaqCategory @relation(fields: [categoryId], references: [id])
|
|
}
|
|
|
|
model SupportConversation {
|
|
id String @id @default(uuid())
|
|
userId String
|
|
status SupportConversationStatus @default(OPEN)
|
|
createdAt DateTime @default(now())
|
|
messages SupportMessage[]
|
|
}
|
|
|
|
model SupportMessage {
|
|
id String @id @default(uuid())
|
|
conversationId String
|
|
sender SupportSender
|
|
text String
|
|
createdAt DateTime @default(now())
|
|
conversation SupportConversation @relation(fields: [conversationId], references: [id])
|
|
}
|
|
|
|
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)
|
|
user User @relation(fields: [userId], references: [id])
|
|
}
|
|
|
|
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])
|
|
}
|
|
|
|
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])
|
|
}
|