Files
edr-platform/apps/edr-passenger-api/prisma/schema.prisma
2026-05-13 16:58:49 +03:00

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])
}