mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-09-07 14:15:44 +00:00
Initial commit of edr-passenger-api alpha version
This commit is contained in:
@@ -0,0 +1,690 @@
|
||||
-- CreateEnum
|
||||
CREATE TYPE "UserRole" AS ENUM ('PASSENGER', 'ADMIN', 'STAFF');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "TripStatus" AS ENUM ('SCHEDULED', 'BOARDING', 'EN_ROUTE', 'ARRIVED', 'CANCELLED', 'DELAYED');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "SeatKind" AS ENUM ('STANDARD', 'PREMIUM', 'ACCESSIBLE');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "SeatStatus" AS ENUM ('AVAILABLE', 'HELD', 'BOOKED', 'BLOCKED');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "ServiceClass" AS ENUM ('ECONOMY', 'BUSINESS', 'FIRST');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "BookingStatus" AS ENUM ('DRAFT', 'PENDING_PAYMENT', 'CONFIRMED', 'CANCELLED', 'COMPLETED', 'NO_SHOW');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "PaymentMethodType" AS ENUM ('TELEBIRR', 'CBE_BIRR', 'EBIRR', 'CARD', 'WALLET');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "PaymentIntentStatus" AS ENUM ('REQUIRES_ACTION', 'PROCESSING', 'SUCCEEDED', 'FAILED', 'CANCELLED');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "WalletLedgerType" AS ENUM ('CREDIT', 'DEBIT');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "NotificationCategory" AS ENUM ('BOOKING', 'PAYMENT', 'DISRUPTION', 'PROMOTION', 'SYSTEM');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "StopStatus" AS ENUM ('COMPLETED', 'APPROACHING', 'CURRENT', 'UPCOMING');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "SupportConversationStatus" AS ENUM ('OPEN', 'RESOLVED', 'CLOSED');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "SupportSender" AS ENUM ('USER', 'BOT', 'AGENT');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "LoyaltyTier" AS ENUM ('BRONZE', 'SILVER', 'GOLD', 'PLATINUM');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "LoyaltyLedgerReason" AS ENUM ('TRIP_COMPLETED', 'REWARD_REDEEMED', 'PROMO_BONUS', 'MANUAL_ADJUSTMENT', 'EXPIRY');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "FoodOrderStatus" AS ENUM ('PENDING', 'PREPARING', 'READY', 'DELIVERED', 'CANCELLED');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "DevicePlatform" AS ENUM ('IOS', 'ANDROID', 'WEB');
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "User" (
|
||||
"id" TEXT NOT NULL,
|
||||
"email" TEXT NOT NULL,
|
||||
"phone" TEXT NOT NULL,
|
||||
"fullName" TEXT NOT NULL,
|
||||
"passwordHash" TEXT NOT NULL,
|
||||
"role" "UserRole" NOT NULL DEFAULT 'PASSENGER',
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "User_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Session" (
|
||||
"id" TEXT NOT NULL,
|
||||
"userId" TEXT NOT NULL,
|
||||
"token" TEXT NOT NULL,
|
||||
"expiresAt" TIMESTAMP(3) NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
CONSTRAINT "Session_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Passenger" (
|
||||
"id" TEXT NOT NULL,
|
||||
"userId" TEXT NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
CONSTRAINT "Passenger_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "TravelerProfile" (
|
||||
"id" TEXT NOT NULL,
|
||||
"passengerId" TEXT NOT NULL,
|
||||
"fullName" TEXT NOT NULL,
|
||||
"relationship" TEXT NOT NULL,
|
||||
"dateOfBirth" TIMESTAMP(3),
|
||||
"nationalId" TEXT,
|
||||
"notes" TEXT,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
CONSTRAINT "TravelerProfile_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Station" (
|
||||
"id" TEXT NOT NULL,
|
||||
"code" TEXT NOT NULL,
|
||||
"name" TEXT NOT NULL,
|
||||
"city" TEXT NOT NULL,
|
||||
"timezone" TEXT NOT NULL DEFAULT 'Africa/Addis_Ababa',
|
||||
"lat" DECIMAL(9,6) NOT NULL,
|
||||
"lng" DECIMAL(9,6) NOT NULL,
|
||||
|
||||
CONSTRAINT "Station_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "TrainService" (
|
||||
"id" TEXT NOT NULL,
|
||||
"number" TEXT NOT NULL,
|
||||
"name" TEXT NOT NULL,
|
||||
"operatorId" TEXT NOT NULL DEFAULT 'op_edr',
|
||||
|
||||
CONSTRAINT "TrainService_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Trip" (
|
||||
"id" TEXT NOT NULL,
|
||||
"serviceId" TEXT NOT NULL,
|
||||
"originStationId" TEXT NOT NULL,
|
||||
"destinationStationId" TEXT NOT NULL,
|
||||
"departureAt" TIMESTAMP(3) NOT NULL,
|
||||
"arrivalAt" TIMESTAMP(3) NOT NULL,
|
||||
"durationMinutes" INTEGER NOT NULL,
|
||||
"status" "TripStatus" NOT NULL DEFAULT 'SCHEDULED',
|
||||
"stopsCount" INTEGER NOT NULL DEFAULT 0,
|
||||
"onTimePercent" INTEGER NOT NULL DEFAULT 100,
|
||||
"carbonRating" TEXT NOT NULL DEFAULT 'A',
|
||||
|
||||
CONSTRAINT "Trip_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "TripStopTime" (
|
||||
"id" TEXT NOT NULL,
|
||||
"tripId" TEXT NOT NULL,
|
||||
"stationId" TEXT NOT NULL,
|
||||
"sequence" INTEGER NOT NULL,
|
||||
"plannedArrivalAt" TIMESTAMP(3),
|
||||
"plannedDepartureAt" TIMESTAMP(3),
|
||||
"actualArrivalAt" TIMESTAMP(3),
|
||||
"status" "StopStatus" NOT NULL DEFAULT 'UPCOMING',
|
||||
|
||||
CONSTRAINT "TripStopTime_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "TripLiveStatus" (
|
||||
"id" TEXT NOT NULL,
|
||||
"tripId" TEXT NOT NULL,
|
||||
"state" TEXT NOT NULL,
|
||||
"currentLocationLabel" TEXT,
|
||||
"progressPercent" INTEGER NOT NULL DEFAULT 0,
|
||||
"delayMinutes" INTEGER NOT NULL DEFAULT 0,
|
||||
"currentSpeedKph" INTEGER,
|
||||
"platformLabel" TEXT,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "TripLiveStatus_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Coach" (
|
||||
"id" TEXT NOT NULL,
|
||||
"tripId" TEXT NOT NULL,
|
||||
"label" TEXT NOT NULL,
|
||||
"serviceClass" "ServiceClass" NOT NULL,
|
||||
|
||||
CONSTRAINT "Coach_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Seat" (
|
||||
"id" TEXT NOT NULL,
|
||||
"coachId" TEXT NOT NULL,
|
||||
"row" INTEGER NOT NULL,
|
||||
"col" TEXT NOT NULL,
|
||||
"label" TEXT NOT NULL,
|
||||
"kind" "SeatKind" NOT NULL DEFAULT 'STANDARD',
|
||||
"status" "SeatStatus" NOT NULL DEFAULT 'AVAILABLE',
|
||||
"heldUntil" TIMESTAMP(3),
|
||||
|
||||
CONSTRAINT "Seat_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "SeatHold" (
|
||||
"id" TEXT NOT NULL,
|
||||
"tripId" TEXT NOT NULL,
|
||||
"seatIds" TEXT[],
|
||||
"fareQuoteId" TEXT,
|
||||
"passengerId" TEXT NOT NULL,
|
||||
"expiresAt" TIMESTAMP(3) NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
CONSTRAINT "SeatHold_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "FareRule" (
|
||||
"id" TEXT NOT NULL,
|
||||
"tripId" TEXT,
|
||||
"route" TEXT,
|
||||
"serviceClass" "ServiceClass" NOT NULL,
|
||||
"baseFareMinor" INTEGER NOT NULL,
|
||||
"currency" TEXT NOT NULL DEFAULT 'ETB',
|
||||
"refundable" BOOLEAN NOT NULL DEFAULT true,
|
||||
"validFrom" TIMESTAMP(3) NOT NULL,
|
||||
"validUntil" TIMESTAMP(3),
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
CONSTRAINT "FareRule_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Booking" (
|
||||
"id" TEXT NOT NULL,
|
||||
"bookingRef" TEXT NOT NULL,
|
||||
"passengerId" TEXT NOT NULL,
|
||||
"tripId" TEXT NOT NULL,
|
||||
"status" "BookingStatus" NOT NULL DEFAULT 'DRAFT',
|
||||
"currency" TEXT NOT NULL DEFAULT 'ETB',
|
||||
"totalMinor" INTEGER NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "Booking_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "BookingSeat" (
|
||||
"id" TEXT NOT NULL,
|
||||
"bookingId" TEXT NOT NULL,
|
||||
"seatId" TEXT NOT NULL,
|
||||
"passengerName" TEXT NOT NULL,
|
||||
"idDocumentType" TEXT,
|
||||
"idDocumentNumber" TEXT,
|
||||
|
||||
CONSTRAINT "BookingSeat_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "PaymentMethod" (
|
||||
"id" TEXT NOT NULL,
|
||||
"userId" TEXT NOT NULL,
|
||||
"type" "PaymentMethodType" NOT NULL,
|
||||
"displayName" TEXT NOT NULL,
|
||||
"maskedHint" TEXT,
|
||||
"isDefault" BOOLEAN NOT NULL DEFAULT false,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
CONSTRAINT "PaymentMethod_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "PaymentIntent" (
|
||||
"id" TEXT NOT NULL,
|
||||
"bookingId" TEXT NOT NULL,
|
||||
"amountMinor" INTEGER NOT NULL,
|
||||
"currency" TEXT NOT NULL DEFAULT 'ETB',
|
||||
"method" "PaymentMethodType" NOT NULL,
|
||||
"status" "PaymentIntentStatus" NOT NULL DEFAULT 'REQUIRES_ACTION',
|
||||
"providerRef" TEXT,
|
||||
"clientAction" JSONB,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "PaymentIntent_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Ticket" (
|
||||
"id" TEXT NOT NULL,
|
||||
"bookingId" TEXT NOT NULL,
|
||||
"bookingRef" TEXT NOT NULL,
|
||||
"status" TEXT NOT NULL DEFAULT 'CONFIRMED',
|
||||
"qrPayload" TEXT NOT NULL,
|
||||
"issuedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"validatedAt" TIMESTAMP(3),
|
||||
"validatorId" TEXT,
|
||||
|
||||
CONSTRAINT "Ticket_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "LoyaltyAccount" (
|
||||
"id" TEXT NOT NULL,
|
||||
"passengerId" TEXT NOT NULL,
|
||||
"pointsBalance" INTEGER NOT NULL DEFAULT 0,
|
||||
"tier" "LoyaltyTier" NOT NULL DEFAULT 'BRONZE',
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "LoyaltyAccount_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "LoyaltyLedgerEntry" (
|
||||
"id" TEXT NOT NULL,
|
||||
"accountId" TEXT NOT NULL,
|
||||
"delta" INTEGER NOT NULL,
|
||||
"reason" "LoyaltyLedgerReason" NOT NULL,
|
||||
"bookingId" TEXT,
|
||||
"balanceAfter" INTEGER NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
CONSTRAINT "LoyaltyLedgerEntry_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "LoyaltyReward" (
|
||||
"id" TEXT NOT NULL,
|
||||
"accountId" TEXT NOT NULL,
|
||||
"title" TEXT NOT NULL,
|
||||
"costPoints" INTEGER NOT NULL,
|
||||
"available" BOOLEAN NOT NULL DEFAULT true,
|
||||
"description" TEXT,
|
||||
|
||||
CONSTRAINT "LoyaltyReward_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "WalletAccount" (
|
||||
"id" TEXT NOT NULL,
|
||||
"passengerId" TEXT NOT NULL,
|
||||
"balanceMinor" INTEGER NOT NULL DEFAULT 0,
|
||||
"currency" TEXT NOT NULL DEFAULT 'ETB',
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "WalletAccount_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "WalletLedgerEntry" (
|
||||
"id" TEXT NOT NULL,
|
||||
"walletId" TEXT NOT NULL,
|
||||
"type" "WalletLedgerType" NOT NULL,
|
||||
"amountMinor" INTEGER NOT NULL,
|
||||
"balanceAfterMinor" INTEGER NOT NULL,
|
||||
"description" TEXT NOT NULL,
|
||||
"relatedBookingId" TEXT,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
CONSTRAINT "WalletLedgerEntry_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Notification" (
|
||||
"id" TEXT NOT NULL,
|
||||
"passengerId" TEXT NOT NULL,
|
||||
"title" TEXT NOT NULL,
|
||||
"body" TEXT NOT NULL,
|
||||
"category" "NotificationCategory" NOT NULL,
|
||||
"read" BOOLEAN NOT NULL DEFAULT false,
|
||||
"deepLink" TEXT,
|
||||
"metadata" JSONB,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
CONSTRAINT "Notification_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Promotion" (
|
||||
"id" TEXT NOT NULL,
|
||||
"title" TEXT NOT NULL,
|
||||
"subtitle" TEXT,
|
||||
"code" TEXT NOT NULL,
|
||||
"percentOff" INTEGER,
|
||||
"amountOffMinor" INTEGER,
|
||||
"validUntil" TIMESTAMP(3) NOT NULL,
|
||||
"ctaLabel" TEXT,
|
||||
"deepLink" TEXT,
|
||||
"active" BOOLEAN NOT NULL DEFAULT true,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
CONSTRAINT "Promotion_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "StationCrowdSignal" (
|
||||
"id" TEXT NOT NULL,
|
||||
"stationId" TEXT NOT NULL,
|
||||
"level" TEXT NOT NULL,
|
||||
"label" TEXT NOT NULL,
|
||||
"statusLabel" TEXT NOT NULL,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "StationCrowdSignal_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "WeatherAlert" (
|
||||
"id" TEXT NOT NULL,
|
||||
"region" TEXT NOT NULL,
|
||||
"severity" TEXT NOT NULL,
|
||||
"title" TEXT NOT NULL,
|
||||
"message" TEXT NOT NULL,
|
||||
"validUntil" TIMESTAMP(3) NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
CONSTRAINT "WeatherAlert_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "MenuCategory" (
|
||||
"id" TEXT NOT NULL,
|
||||
"name" TEXT NOT NULL,
|
||||
|
||||
CONSTRAINT "MenuCategory_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "MenuItem" (
|
||||
"id" TEXT NOT NULL,
|
||||
"tripId" TEXT NOT NULL,
|
||||
"categoryId" TEXT NOT NULL,
|
||||
"name" TEXT NOT NULL,
|
||||
"priceMinor" INTEGER NOT NULL,
|
||||
"currency" TEXT NOT NULL DEFAULT 'ETB',
|
||||
"available" BOOLEAN NOT NULL DEFAULT true,
|
||||
|
||||
CONSTRAINT "MenuItem_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "FoodOrder" (
|
||||
"id" TEXT NOT NULL,
|
||||
"bookingId" TEXT NOT NULL,
|
||||
"status" "FoodOrderStatus" NOT NULL DEFAULT 'PENDING',
|
||||
"totalMinor" INTEGER NOT NULL,
|
||||
"currency" TEXT NOT NULL DEFAULT 'ETB',
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
CONSTRAINT "FoodOrder_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "FoodOrderItem" (
|
||||
"id" TEXT NOT NULL,
|
||||
"orderId" TEXT NOT NULL,
|
||||
"menuItemId" TEXT NOT NULL,
|
||||
"name" TEXT NOT NULL,
|
||||
"quantity" INTEGER NOT NULL,
|
||||
"lineTotalMinor" INTEGER NOT NULL,
|
||||
|
||||
CONSTRAINT "FoodOrderItem_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "FaqCategory" (
|
||||
"id" TEXT NOT NULL,
|
||||
"title" TEXT NOT NULL,
|
||||
"iconKey" TEXT,
|
||||
|
||||
CONSTRAINT "FaqCategory_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "FaqArticle" (
|
||||
"id" TEXT NOT NULL,
|
||||
"categoryId" TEXT NOT NULL,
|
||||
"question" TEXT NOT NULL,
|
||||
"answerMarkdown" TEXT NOT NULL,
|
||||
"rank" INTEGER NOT NULL DEFAULT 0,
|
||||
|
||||
CONSTRAINT "FaqArticle_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "SupportConversation" (
|
||||
"id" TEXT NOT NULL,
|
||||
"userId" TEXT NOT NULL,
|
||||
"status" "SupportConversationStatus" NOT NULL DEFAULT 'OPEN',
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
CONSTRAINT "SupportConversation_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "SupportMessage" (
|
||||
"id" TEXT NOT NULL,
|
||||
"conversationId" TEXT NOT NULL,
|
||||
"sender" "SupportSender" NOT NULL,
|
||||
"text" TEXT NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
CONSTRAINT "SupportMessage_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "UserPreferences" (
|
||||
"id" TEXT NOT NULL,
|
||||
"userId" TEXT NOT NULL,
|
||||
"pushEnabled" BOOLEAN NOT NULL DEFAULT true,
|
||||
"emailEnabled" BOOLEAN NOT NULL DEFAULT true,
|
||||
"smsEnabled" BOOLEAN NOT NULL DEFAULT false,
|
||||
"promosEnabled" BOOLEAN NOT NULL DEFAULT true,
|
||||
"biometricEnabled" BOOLEAN NOT NULL DEFAULT false,
|
||||
"twoFactorEnabled" BOOLEAN NOT NULL DEFAULT false,
|
||||
"defaultPaymentMethodId" TEXT,
|
||||
"autoDownloadTickets" BOOLEAN NOT NULL DEFAULT true,
|
||||
"dataSharing" BOOLEAN NOT NULL DEFAULT false,
|
||||
"locale" TEXT NOT NULL DEFAULT 'en',
|
||||
"darkMode" BOOLEAN NOT NULL DEFAULT false,
|
||||
|
||||
CONSTRAINT "UserPreferences_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Device" (
|
||||
"id" TEXT NOT NULL,
|
||||
"userId" TEXT NOT NULL,
|
||||
"platform" "DevicePlatform" NOT NULL,
|
||||
"name" TEXT NOT NULL,
|
||||
"pushToken" TEXT,
|
||||
"trusted" BOOLEAN NOT NULL DEFAULT false,
|
||||
"lastSeenAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
CONSTRAINT "Device_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "SavedRoute" (
|
||||
"id" TEXT NOT NULL,
|
||||
"passengerId" TEXT NOT NULL,
|
||||
"fromStationId" TEXT NOT NULL,
|
||||
"toStationId" TEXT NOT NULL,
|
||||
"fromName" TEXT NOT NULL,
|
||||
"toName" TEXT NOT NULL,
|
||||
"tripCount" INTEGER NOT NULL DEFAULT 0,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
CONSTRAINT "SavedRoute_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "User_email_key" ON "User"("email");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "User_phone_key" ON "User"("phone");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "Session_token_key" ON "Session"("token");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "Passenger_userId_key" ON "Passenger"("userId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "Station_code_key" ON "Station"("code");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "TrainService_number_key" ON "TrainService"("number");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "TripStopTime_tripId_sequence_key" ON "TripStopTime"("tripId", "sequence");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "TripLiveStatus_tripId_key" ON "TripLiveStatus"("tripId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "Coach_tripId_label_key" ON "Coach"("tripId", "label");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "Seat_coachId_row_col_key" ON "Seat"("coachId", "row", "col");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "Booking_bookingRef_key" ON "Booking"("bookingRef");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "PaymentIntent_bookingId_key" ON "PaymentIntent"("bookingId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "Ticket_bookingId_key" ON "Ticket"("bookingId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "LoyaltyAccount_passengerId_key" ON "LoyaltyAccount"("passengerId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "WalletAccount_passengerId_key" ON "WalletAccount"("passengerId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "Promotion_code_key" ON "Promotion"("code");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "UserPreferences_userId_key" ON "UserPreferences"("userId");
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Session" ADD CONSTRAINT "Session_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Passenger" ADD CONSTRAINT "Passenger_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "TravelerProfile" ADD CONSTRAINT "TravelerProfile_passengerId_fkey" FOREIGN KEY ("passengerId") REFERENCES "Passenger"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Trip" ADD CONSTRAINT "Trip_serviceId_fkey" FOREIGN KEY ("serviceId") REFERENCES "TrainService"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Trip" ADD CONSTRAINT "Trip_originStationId_fkey" FOREIGN KEY ("originStationId") REFERENCES "Station"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Trip" ADD CONSTRAINT "Trip_destinationStationId_fkey" FOREIGN KEY ("destinationStationId") REFERENCES "Station"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "TripStopTime" ADD CONSTRAINT "TripStopTime_tripId_fkey" FOREIGN KEY ("tripId") REFERENCES "Trip"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "TripStopTime" ADD CONSTRAINT "TripStopTime_stationId_fkey" FOREIGN KEY ("stationId") REFERENCES "Station"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "TripLiveStatus" ADD CONSTRAINT "TripLiveStatus_tripId_fkey" FOREIGN KEY ("tripId") REFERENCES "Trip"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Coach" ADD CONSTRAINT "Coach_tripId_fkey" FOREIGN KEY ("tripId") REFERENCES "Trip"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Seat" ADD CONSTRAINT "Seat_coachId_fkey" FOREIGN KEY ("coachId") REFERENCES "Coach"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Booking" ADD CONSTRAINT "Booking_passengerId_fkey" FOREIGN KEY ("passengerId") REFERENCES "Passenger"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Booking" ADD CONSTRAINT "Booking_tripId_fkey" FOREIGN KEY ("tripId") REFERENCES "Trip"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "BookingSeat" ADD CONSTRAINT "BookingSeat_bookingId_fkey" FOREIGN KEY ("bookingId") REFERENCES "Booking"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "BookingSeat" ADD CONSTRAINT "BookingSeat_seatId_fkey" FOREIGN KEY ("seatId") REFERENCES "Seat"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "PaymentIntent" ADD CONSTRAINT "PaymentIntent_bookingId_fkey" FOREIGN KEY ("bookingId") REFERENCES "Booking"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Ticket" ADD CONSTRAINT "Ticket_bookingId_fkey" FOREIGN KEY ("bookingId") REFERENCES "Booking"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "LoyaltyAccount" ADD CONSTRAINT "LoyaltyAccount_passengerId_fkey" FOREIGN KEY ("passengerId") REFERENCES "Passenger"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "LoyaltyLedgerEntry" ADD CONSTRAINT "LoyaltyLedgerEntry_accountId_fkey" FOREIGN KEY ("accountId") REFERENCES "LoyaltyAccount"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "LoyaltyReward" ADD CONSTRAINT "LoyaltyReward_accountId_fkey" FOREIGN KEY ("accountId") REFERENCES "LoyaltyAccount"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "WalletAccount" ADD CONSTRAINT "WalletAccount_passengerId_fkey" FOREIGN KEY ("passengerId") REFERENCES "Passenger"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "WalletLedgerEntry" ADD CONSTRAINT "WalletLedgerEntry_walletId_fkey" FOREIGN KEY ("walletId") REFERENCES "WalletAccount"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Notification" ADD CONSTRAINT "Notification_passengerId_fkey" FOREIGN KEY ("passengerId") REFERENCES "Passenger"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "StationCrowdSignal" ADD CONSTRAINT "StationCrowdSignal_stationId_fkey" FOREIGN KEY ("stationId") REFERENCES "Station"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "MenuItem" ADD CONSTRAINT "MenuItem_tripId_fkey" FOREIGN KEY ("tripId") REFERENCES "Trip"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "MenuItem" ADD CONSTRAINT "MenuItem_categoryId_fkey" FOREIGN KEY ("categoryId") REFERENCES "MenuCategory"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "FoodOrder" ADD CONSTRAINT "FoodOrder_bookingId_fkey" FOREIGN KEY ("bookingId") REFERENCES "Booking"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "FoodOrderItem" ADD CONSTRAINT "FoodOrderItem_orderId_fkey" FOREIGN KEY ("orderId") REFERENCES "FoodOrder"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "FaqArticle" ADD CONSTRAINT "FaqArticle_categoryId_fkey" FOREIGN KEY ("categoryId") REFERENCES "FaqCategory"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "SupportMessage" ADD CONSTRAINT "SupportMessage_conversationId_fkey" FOREIGN KEY ("conversationId") REFERENCES "SupportConversation"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "UserPreferences" ADD CONSTRAINT "UserPreferences_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Device" ADD CONSTRAINT "Device_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "SavedRoute" ADD CONSTRAINT "SavedRoute_passengerId_fkey" FOREIGN KEY ("passengerId") REFERENCES "Passenger"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
@@ -0,0 +1,3 @@
|
||||
# Please do not edit this file manually
|
||||
# It should be added in your version-control system (i.e. Git)
|
||||
provider = "postgresql"
|
||||
2
apps/edr-passenger-api/prisma/reset-admin.d.ts
vendored
Normal file
2
apps/edr-passenger-api/prisma/reset-admin.d.ts
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
export {};
|
||||
//# sourceMappingURL=reset-admin.d.ts.map
|
||||
1
apps/edr-passenger-api/prisma/reset-admin.d.ts.map
Normal file
1
apps/edr-passenger-api/prisma/reset-admin.d.ts.map
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"reset-admin.d.ts","sourceRoot":"","sources":["reset-admin.ts"],"names":[],"mappings":""}
|
||||
49
apps/edr-passenger-api/prisma/reset-admin.js
Normal file
49
apps/edr-passenger-api/prisma/reset-admin.js
Normal file
@@ -0,0 +1,49 @@
|
||||
"use strict";
|
||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
var desc = Object.getOwnPropertyDescriptor(m, k);
|
||||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
||||
desc = { enumerable: true, get: function() { return m[k]; } };
|
||||
}
|
||||
Object.defineProperty(o, k2, desc);
|
||||
}) : (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
o[k2] = m[k];
|
||||
}));
|
||||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
||||
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
||||
}) : function(o, v) {
|
||||
o["default"] = v;
|
||||
});
|
||||
var __importStar = (this && this.__importStar) || (function () {
|
||||
var ownKeys = function(o) {
|
||||
ownKeys = Object.getOwnPropertyNames || function (o) {
|
||||
var ar = [];
|
||||
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
||||
return ar;
|
||||
};
|
||||
return ownKeys(o);
|
||||
};
|
||||
return function (mod) {
|
||||
if (mod && mod.__esModule) return mod;
|
||||
var result = {};
|
||||
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
||||
__setModuleDefault(result, mod);
|
||||
return result;
|
||||
};
|
||||
})();
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const client_1 = require("@prisma/client");
|
||||
const bcrypt = __importStar(require("bcrypt"));
|
||||
const prisma = new client_1.PrismaClient();
|
||||
async function main() {
|
||||
const passwordHash = await bcrypt.hash('admin123', 10);
|
||||
const user = await prisma.user.upsert({
|
||||
where: { email: 'admin@edr-platform.com' },
|
||||
update: { passwordHash, role: 'ADMIN' },
|
||||
create: { fullName: 'EDR Admin', email: 'admin@edr-platform.com', phone: '+251900000000', passwordHash, role: 'ADMIN' },
|
||||
});
|
||||
console.log('✅ Admin ready:', user.email);
|
||||
}
|
||||
main().catch(console.error).finally(() => prisma.$disconnect());
|
||||
//# sourceMappingURL=reset-admin.js.map
|
||||
1
apps/edr-passenger-api/prisma/reset-admin.js.map
Normal file
1
apps/edr-passenger-api/prisma/reset-admin.js.map
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"reset-admin.js","sourceRoot":"","sources":["reset-admin.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,2CAA8C;AAC9C,+CAAiC;AAEjC,MAAM,MAAM,GAAG,IAAI,qBAAY,EAAE,CAAC;AAElC,KAAK,UAAU,IAAI;IACjB,MAAM,YAAY,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;IACvD,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC;QACpC,KAAK,EAAE,EAAE,KAAK,EAAE,wBAAwB,EAAE;QAC1C,MAAM,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE,OAAO,EAAE;QACvC,MAAM,EAAE,EAAE,QAAQ,EAAE,WAAW,EAAE,KAAK,EAAE,wBAAwB,EAAE,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,IAAI,EAAE,OAAO,EAAE;KACxH,CAAC,CAAC;IACH,OAAO,CAAC,GAAG,CAAC,gBAAgB,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;AAC5C,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC,CAAC"}
|
||||
16
apps/edr-passenger-api/prisma/reset-admin.ts
Normal file
16
apps/edr-passenger-api/prisma/reset-admin.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { PrismaClient } from '@prisma/client';
|
||||
import * as bcrypt from 'bcrypt';
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
async function main() {
|
||||
const passwordHash = await bcrypt.hash('admin123', 10);
|
||||
const user = await prisma.user.upsert({
|
||||
where: { email: 'admin@edr-platform.com' },
|
||||
update: { passwordHash, role: 'ADMIN' },
|
||||
create: { fullName: 'EDR Admin', email: 'admin@edr-platform.com', phone: '+251900000000', passwordHash, role: 'ADMIN' },
|
||||
});
|
||||
console.log('✅ Admin ready:', user.email);
|
||||
}
|
||||
|
||||
main().catch(console.error).finally(() => prisma.$disconnect());
|
||||
573
apps/edr-passenger-api/prisma/schema.prisma
Normal file
573
apps/edr-passenger-api/prisma/schema.prisma
Normal file
@@ -0,0 +1,573 @@
|
||||
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])
|
||||
}
|
||||
2
apps/edr-passenger-api/prisma/seed.d.ts
vendored
Normal file
2
apps/edr-passenger-api/prisma/seed.d.ts
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
export {};
|
||||
//# sourceMappingURL=seed.d.ts.map
|
||||
1
apps/edr-passenger-api/prisma/seed.d.ts.map
Normal file
1
apps/edr-passenger-api/prisma/seed.d.ts.map
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"seed.d.ts","sourceRoot":"","sources":["seed.ts"],"names":[],"mappings":""}
|
||||
73
apps/edr-passenger-api/prisma/seed.js
Normal file
73
apps/edr-passenger-api/prisma/seed.js
Normal file
@@ -0,0 +1,73 @@
|
||||
"use strict";
|
||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
var desc = Object.getOwnPropertyDescriptor(m, k);
|
||||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
||||
desc = { enumerable: true, get: function() { return m[k]; } };
|
||||
}
|
||||
Object.defineProperty(o, k2, desc);
|
||||
}) : (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
o[k2] = m[k];
|
||||
}));
|
||||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
||||
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
||||
}) : function(o, v) {
|
||||
o["default"] = v;
|
||||
});
|
||||
var __importStar = (this && this.__importStar) || (function () {
|
||||
var ownKeys = function(o) {
|
||||
ownKeys = Object.getOwnPropertyNames || function (o) {
|
||||
var ar = [];
|
||||
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
||||
return ar;
|
||||
};
|
||||
return ownKeys(o);
|
||||
};
|
||||
return function (mod) {
|
||||
if (mod && mod.__esModule) return mod;
|
||||
var result = {};
|
||||
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
||||
__setModuleDefault(result, mod);
|
||||
return result;
|
||||
};
|
||||
})();
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const client_1 = require("@prisma/client");
|
||||
const bcrypt = __importStar(require("bcrypt"));
|
||||
const prisma = new client_1.PrismaClient();
|
||||
async function main() {
|
||||
const addis = await prisma.station.upsert({ where: { code: 'ADD' }, update: {}, create: { code: 'ADD', name: 'Addis Ababa', city: 'Addis Ababa', lat: 9.0054, lng: 38.7636 } });
|
||||
const direDawa = await prisma.station.upsert({ where: { code: 'DDW' }, update: {}, create: { code: 'DDW', name: 'Dire Dawa', city: 'Dire Dawa', lat: 9.5931, lng: 41.8661 } });
|
||||
const djibouti = await prisma.station.upsert({ where: { code: 'DJI' }, update: {}, create: { code: 'DJI', name: 'Djibouti', city: 'Djibouti', timezone: 'Africa/Djibouti', lat: 11.5720, lng: 43.1456 } });
|
||||
const service = await prisma.trainService.upsert({ where: { number: '301' }, update: {}, create: { number: '301', name: 'Express 301' } });
|
||||
const trip = await prisma.trip.create({
|
||||
data: { serviceId: service.id, originStationId: addis.id, destinationStationId: djibouti.id, departureAt: new Date('2026-05-11T08:30:00Z'), arrivalAt: new Date('2026-05-11T20:00:00Z'), durationMinutes: 690, stopsCount: 1 },
|
||||
});
|
||||
for (const [label, cls] of [['A', 'ECONOMY'], ['B', 'BUSINESS']]) {
|
||||
const coach = await prisma.coach.create({ data: { tripId: trip.id, label, serviceClass: cls } });
|
||||
const seats = [];
|
||||
for (let row = 1; row <= 10; row++) {
|
||||
for (const col of ['A', 'B', 'C', 'D'])
|
||||
seats.push({ coachId: coach.id, row, col, label: `${row}${col}` });
|
||||
}
|
||||
await prisma.seat.createMany({ data: seats });
|
||||
}
|
||||
await prisma.fareRule.create({ data: { tripId: trip.id, serviceClass: 'ECONOMY', baseFareMinor: 45000, validFrom: new Date('2026-01-01') } });
|
||||
const hash = await bcrypt.hash('password123', 10);
|
||||
const user = await prisma.user.upsert({ where: { email: 'kelemu@email.com' }, update: {}, create: { fullName: 'Kelemu Ketsela', email: 'kelemu@email.com', phone: '+251912345678', passwordHash: hash } });
|
||||
let passenger = await prisma.passenger.findUnique({ where: { userId: user.id } });
|
||||
if (!passenger) {
|
||||
passenger = await prisma.passenger.create({ data: { userId: user.id } });
|
||||
await prisma.loyaltyAccount.create({ data: { passengerId: passenger.id, pointsBalance: 2450, tier: 'SILVER' } });
|
||||
await prisma.walletAccount.create({ data: { passengerId: passenger.id, balanceMinor: 125000 } });
|
||||
}
|
||||
await prisma.userPreferences.upsert({ where: { userId: user.id }, update: {}, create: { userId: user.id } });
|
||||
await prisma.user.upsert({ where: { email: 'admin@edr-platform.com' }, update: { passwordHash: await bcrypt.hash('admin123', 10), role: 'ADMIN' }, create: { fullName: 'EDR Admin', email: 'admin@edr-platform.com', phone: '+251900000000', passwordHash: await bcrypt.hash('admin123', 10), role: 'ADMIN' } });
|
||||
await prisma.promotion.upsert({ where: { code: 'WEEKEND15' }, update: {}, create: { title: 'Weekend Sale', code: 'WEEKEND15', percentOff: 15, validUntil: new Date('2026-12-31') } });
|
||||
const faqCat = await prisma.faqCategory.create({ data: { title: 'Booking & Tickets', iconKey: 'description_outlined' } });
|
||||
await prisma.faqArticle.create({ data: { categoryId: faqCat.id, question: 'How do I book a train ticket?', answerMarkdown: 'Open Search, pick stations and date, select seats, and proceed to payment.', rank: 1 } });
|
||||
console.log('✅ Seed complete');
|
||||
}
|
||||
main().catch(console.error).finally(() => prisma.$disconnect());
|
||||
//# sourceMappingURL=seed.js.map
|
||||
1
apps/edr-passenger-api/prisma/seed.js.map
Normal file
1
apps/edr-passenger-api/prisma/seed.js.map
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"seed.js","sourceRoot":"","sources":["seed.ts"],"names":[],"mappings":"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"}
|
||||
48
apps/edr-passenger-api/prisma/seed.ts
Normal file
48
apps/edr-passenger-api/prisma/seed.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
import { PrismaClient } from '@prisma/client';
|
||||
import * as bcrypt from 'bcrypt';
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
async function main() {
|
||||
const addis = await prisma.station.upsert({ where: { code: 'ADD' }, update: {}, create: { code: 'ADD', name: 'Addis Ababa', city: 'Addis Ababa', lat: 9.0054, lng: 38.7636 } });
|
||||
const direDawa = await prisma.station.upsert({ where: { code: 'DDW' }, update: {}, create: { code: 'DDW', name: 'Dire Dawa', city: 'Dire Dawa', lat: 9.5931, lng: 41.8661 } });
|
||||
const djibouti = await prisma.station.upsert({ where: { code: 'DJI' }, update: {}, create: { code: 'DJI', name: 'Djibouti', city: 'Djibouti', timezone: 'Africa/Djibouti', lat: 11.5720, lng: 43.1456 } });
|
||||
|
||||
const service = await prisma.trainService.upsert({ where: { number: '301' }, update: {}, create: { number: '301', name: 'Express 301' } });
|
||||
|
||||
const trip = await prisma.trip.create({
|
||||
data: { serviceId: service.id, originStationId: addis.id, destinationStationId: djibouti.id, departureAt: new Date('2026-05-11T08:30:00Z'), arrivalAt: new Date('2026-05-11T20:00:00Z'), durationMinutes: 690, stopsCount: 1 },
|
||||
});
|
||||
|
||||
for (const [label, cls] of [['A', 'ECONOMY'], ['B', 'BUSINESS']] as const) {
|
||||
const coach = await prisma.coach.create({ data: { tripId: trip.id, label, serviceClass: cls } });
|
||||
const seats = [];
|
||||
for (let row = 1; row <= 10; row++) {
|
||||
for (const col of ['A', 'B', 'C', 'D']) seats.push({ coachId: coach.id, row, col, label: `${row}${col}` });
|
||||
}
|
||||
await prisma.seat.createMany({ data: seats });
|
||||
}
|
||||
|
||||
await prisma.fareRule.create({ data: { tripId: trip.id, serviceClass: 'ECONOMY', baseFareMinor: 45000, validFrom: new Date('2026-01-01') } });
|
||||
|
||||
const hash = await bcrypt.hash('password123', 10);
|
||||
const user = await prisma.user.upsert({ where: { email: 'kelemu@email.com' }, update: {}, create: { fullName: 'Kelemu Ketsela', email: 'kelemu@email.com', phone: '+251912345678', passwordHash: hash } });
|
||||
let passenger = await prisma.passenger.findUnique({ where: { userId: user.id } });
|
||||
if (!passenger) {
|
||||
passenger = await prisma.passenger.create({ data: { userId: user.id } });
|
||||
await prisma.loyaltyAccount.create({ data: { passengerId: passenger.id, pointsBalance: 2450, tier: 'SILVER' } });
|
||||
await prisma.walletAccount.create({ data: { passengerId: passenger.id, balanceMinor: 125000 } });
|
||||
}
|
||||
await prisma.userPreferences.upsert({ where: { userId: user.id }, update: {}, create: { userId: user.id } });
|
||||
|
||||
await prisma.user.upsert({ where: { email: 'admin@edr-platform.com' }, update: { passwordHash: await bcrypt.hash('admin123', 10), role: 'ADMIN' }, create: { fullName: 'EDR Admin', email: 'admin@edr-platform.com', phone: '+251900000000', passwordHash: await bcrypt.hash('admin123', 10), role: 'ADMIN' } });
|
||||
|
||||
await prisma.promotion.upsert({ where: { code: 'WEEKEND15' }, update: {}, create: { title: 'Weekend Sale', code: 'WEEKEND15', percentOff: 15, validUntil: new Date('2026-12-31') } });
|
||||
|
||||
const faqCat = await prisma.faqCategory.create({ data: { title: 'Booking & Tickets', iconKey: 'description_outlined' } });
|
||||
await prisma.faqArticle.create({ data: { categoryId: faqCat.id, question: 'How do I book a train ticket?', answerMarkdown: 'Open Search, pick stations and date, select seats, and proceed to payment.', rank: 1 } });
|
||||
|
||||
console.log('✅ Seed complete');
|
||||
}
|
||||
|
||||
main().catch(console.error).finally(() => prisma.$disconnect());
|
||||
Reference in New Issue
Block a user