import "reflect-metadata"; import { NestFactory } from "@nestjs/core"; import { ValidationPipe } from "@nestjs/common"; import { DocumentBuilder, SwaggerModule } from "@nestjs/swagger"; import { AppModule } from "./app.module"; import { HttpExceptionFilter } from "./common/filters/http-exception.filter"; import { ResponseTransformInterceptor } from "./common/interceptors/response-transform.interceptor"; import { SessionActivityInterceptor } from "./common/interceptors/session-activity.interceptor"; async function bootstrap() { // rawBody: true buffers the unparsed request body onto req.rawBody so webhook handlers // (e.g. Waafi HMAC verification) can sign over the exact bytes the provider signed. const app = await NestFactory.create(AppModule, { rawBody: true }); app.enableCors({ origin: [ process.env.PORTAL_URL ?? "http://localhost:5174", process.env.BACK_OFFICE_URL ?? "http://localhost:5184", ], }); app.useGlobalFilters(new HttpExceptionFilter()); app.useGlobalInterceptors( new ResponseTransformInterceptor(), app.get(SessionActivityInterceptor), ); app.useGlobalPipes(new ValidationPipe({ whitelist: true, transform: true, forbidUnknownValues: false })); const config = new DocumentBuilder() .setTitle("EDR Passenger API") .setDescription( `# Ethio-Djibouti Railway Passenger Booking API ## Overview Enterprise-grade REST API for the Ethio-Djibouti Railway passenger booking and management platform. Built with NestJS, TypeScript, PostgreSQL, and Prisma ORM. ## 🆕 Latest Updates - **Sequence Ordering:** Stations and coaches now sorted by sequence field for consistent UI display - **User Profile Data:** Gender, DOB, passport, and national ID fields for comprehensive passenger profiles - **Seat Class Fees:** Premium charges and insurance fees per seat class for transparent pricing - **Booking Types:** Support for ONE_WAY and ROUND_TRIP booking categories - **Multi-Currency Display:** Bookings track display currency and converted amounts - **Ticket Lifecycle:** Tickets now include validatedAt and boardedAt timestamps for complete audit trail ## Key Features ### 🎫 Booking Lifecycle - Search trips with real-time availability - Age-based passenger categorization (Adult ≥5 years, Child <5 years) - Nationality-based verification (Ethiopian Fayda, International Passport) - Passenger information collection with verification - Coach and seat selection with real-time availability - Seat holding (15-minute expiry) - Create bookings with verified passenger data - Modify bookings (seat changes, passenger updates) - Cancel bookings with automatic refunds - Multi-segment journey support - Cross-border journeys via Dire Dawa transit (Ethiopia → Djibouti) - Round-trip booking with return journey scheduling - Coach type selection with seat class and pricing options - **NEW:** Booking type tracking (ONE_WAY vs ROUND_TRIP) - **NEW:** Display currency and converted pricing per booking ### 👤 Passenger Verification 1. **Ethiopian Nationals:** - Automatic Fayda verification for adults (≥5 years) - Real-time national ID verification via government database - Retrieves verified passenger data (name, DOB, gender) - National IDs not stored (policy compliant) 2. **International Passengers:** - Passport information collection - Manual verification for Djiboutian and other nationals - No government database verification required ### 💰 Age-Based Pricing - **ADULT** (≥5 years): Pay 100% of base fare - **CHILD** (<5 years): First child travels FREE, subsequent children pay 100% - Automatic age calculation from date of birth - Example: 2 adults + 3 children = 4× base fare (first child free) - **NEW:** Premium charges and insurance fees per seat class - **NEW:** Transparent fee breakdown in pricing calculations ### 💳 Payment Integration 1. **Ethiopian Payment Methods:** - **Telebirr** - Ethiopia's leading mobile money - **CBE Birr** - Commercial Bank of Ethiopia 2. **Djiboutian Payment Methods:** - **Waafi** - Djibouti's mobile money service 3. **International Payment Methods:** - **Card** - International card payments (Visa, Mastercard) - **Wallet** - Internal wallet system ### 🪑 Seat Management - Real-time seat availability by coach and class - Seat holds with 15-minute expiry - Auto-assign seats with contiguous algorithm - Seat blocking for maintenance - Coach-level seat maps (ordered by sequence) - Class-based seating (Economy Regular, Economy Bed, VIP Bed) - **NEW:** Sequence-based coach ordering for consistent display ### 🎟️ Ticketing - QR code and barcode generation - PDF ticket generation - Gate validation with audit logs - Offline validation support - Multi-passenger tickets - **NEW:** Ticket lifecycle tracking (validatedAt, boardedAt timestamps) - **NEW:** Complete audit trail for compliance and reporting ### 🏆 Loyalty Program - 4 tiers: Bronze, Silver, Gold, Platinum - Points accumulation on trips - Reward redemption - Tier-based benefits ### 💰 Wallet System - Top-up via payment methods - Pay with wallet balance - Transaction ledger - Refund to wallet ### 📍 Live Tracking - Real-time trip status - Location updates - Delay notifications - Station crowd signals ### 🔒 Fraud Detection - Velocity checks (multiple bookings) - High-value transaction monitoring - Failed payment pattern detection - Automatic user blocking ### 👤 Passenger Profiles - Comprehensive profile data: gender, date of birth, nationality - National ID for Ethiopian citizens (Fayda verified) - Passport information for international passengers - **NEW:** Complete demographic data for personalized services - **NEW:** Improved user targeting and communications ### 🌍 Internationalization - Multi-language support (English, Amharic, French, Oromo) - Locale-based responses - Currency formatting (ETB, DJF, USD) - **NEW:** Multi-currency display per booking (ETB, DJF, USD) ### 🚌 Transit Stop Management - Automatic detection of cross-border journeys (Ethiopia → Djibouti) - Dire Dawa as mandatory transit hub for international journeys - Dual-leg fare calculation (domestic + international) - Age-based pricing applied independently per leg - Seamless multi-segment booking workflow - Transit stop optimization and route planning ### 🔄 Round-Trip Booking - One-way and round-trip journey options - Flexible return date selection - Combined pricing for outbound + return legs - Separate seat management per leg - Independent modification/cancellation per leg - Return journey tracking and notifications - **NEW:** Booking type stored for analytics and reporting ### 🚐 Coach Type & Class Selection - Browse available coach types per route (standard coaches, premium coaches) - View seat classes per coach (Economy Regular, Economy Bed, VIP Bed) - Compare base prices by coach type and class - Real-time availability per coach configuration - Deferred pricing at seat selection stage - Coach amenities and features display - **NEW:** Sequence-based coach ordering for consistent UI - **NEW:** Premium and insurance fee transparency per class ### 📊 Data Organization - **Stations:** Ordered by sequence (1-15) for consistent route display - **Coaches:** Ordered by sequence (1+) per type for predictable configuration - **Booking History:** Sorted chronologically with filtering options ## Authentication ### Passenger Authentication (JWT-auth) Used for passenger-facing endpoints. Obtain token via \`POST /auth/login\`. **Usage:** Add header \`Authorization: Bearer \` ### Back-office Authentication (IAM-auth) Used for agent, fraud, and reporting endpoints. Requires corporate IAM token. **Usage:** Add header \`Authorization: Bearer \` ## Passenger Booking Flow ### Step 1: Search Trips \`POST /search\` with origin, destination, date, passenger counts, and nationality ### Step 2: Get Fare Quote \`POST /search/fare-quote\` with passenger counts and display currency ### Step 3: Passenger Information & Verification **For Ethiopian Passengers:** \`POST /passengers/verify-fayda\` - Automatic Fayda verification for adults (≥5 years) **For International Passengers:** \`POST /passengers/register-international\` - Passport information collection ### Step 4: View Seat Map \`GET /seats/seatmap/{scheduleId}\` - Show available coaches and seats ### Step 5: Login & Hold Seats \`POST /auth/login\` then \`POST /seats/hold\` to reserve seats for 15 minutes ### Step 6: Create Booking \`POST /bookings/guest\` with verified passenger details and held seats ### Step 7: Process Payment \`POST /payments/telebirr\` (Ethiopian) or \`POST /payments/waafi\` (Djiboutian) ### Step 8: Get Tickets \`GET /payments/{paymentId}/status\` to confirm payment and retrieve tickets with QR codes ## Rate Limiting - Auth endpoints: 5 requests/minute - General endpoints: 100 requests/minute - Webhook endpoints: No limit ## Error Handling All errors follow standard format: \`\`\`json { "statusCode": 400, "message": "Validation failed", "error": "Bad Request", "timestamp": "2026-05-20T14:30:00.000Z", "path": "/bookings" } \`\`\` ## Pagination List endpoints support pagination: - \`limit\`: Number of items (default: 20, max: 100) - \`offset\`: Skip items (default: 0) ## Webhooks Payment providers send notifications to: - \`POST /payments/webhooks/telebirr\` (Ethiopia) - \`POST /payments/webhooks/cbe-birr\` (Ethiopia) - \`POST /payments/webhooks/waafi\` (Djibouti) - \`POST /payments/webhooks/card\` (International) ## Support - **Email:** support@edr-platform.com - **Documentation:** https://docs.edr-platform.com - **Status Page:** https://status.edr-platform.com `, ) .setVersion("1.0.0") .addBearerAuth( { type: "http", scheme: "bearer", bearerFormat: "JWT", in: "header" }, "JWT-auth", ) .addTag("Agents", "Counter booking, shift management, commission tracking, and reconciliation") .addTag("Audit", "User activity logging, system changes, compliance tracking, and audit trails") .addTag("Auth", "Passenger registration, login, OTP, password reset, and profile management") .addTag("Booking", "Complete booking lifecycle: create, modify, cancel, guest checkout") .addTag("Config", "System settings, feature flags, and configuration management") .addTag("Currencies", "Multi-currency support, exchange rates, and currency conversion") .addTag("Dashboard", "Home screen aggregations: trips, loyalty, wallet, notifications") .addTag("Fare Engine", "Distance-based fare calculation with age-based pricing and multi-currency") .addTag("Fayda Verification", "Ethiopian national ID verification via Verifayda 2.0 government API") .addTag("Fleet", "Train services, coaches, coach types, seat classes, amenities, and configurations") .addTag("Fraud Detection", "Velocity checks, monitoring alerts, pattern detection, and user blocking") .addTag("Internal Payments", "Internal payment tracking, wallet transactions, and balance management") .addTag("Live Tracking", "Real-time trip status, location updates, delays, and crowd signals") .addTag("Loyalty", "Points ledger, tier management (Bronze/Silver/Gold/Platinum), rewards") .addTag("Notifications", "Multi-channel delivery (email, SMS, push) and preference management") .addTag("Passengers", "Registration, Fayda verification, international passports, saved profiles") .addTag("Payment", "Telebirr, CBE Birr, Waafi, Card, Wallet payment processing and refunds") .addTag("Payment Webhooks", "Payment provider webhook handlers and transaction confirmation") .addTag("Promotions", "Promo codes, campaigns, discounts, and redemption tracking") .addTag("Reports", "Revenue analytics, occupancy reports, agent sales, and KPI dashboards") .addTag("Round Trip", "Round-trip bookings, return scheduling, combined pricing, and management (NEW)") .addTag("Routes", "Route templates with ordered stops, fare rules, and baggage allowance") .addTag("Schedule", "Trip schedules, availability windows, status tracking, and timing") .addTag("Search", "Trip search, fare quotes, coach types, and real-time availability") .addTag("Seat Classes", "Economy Regular, Economy Bed, VIP Bed class configuration and pricing") .addTag("Seats", "Seat maps, holds (15-min expiry), releases, blocking, and inventory") .addTag("Segment-based Seats", "Multi-leg journey seats, segment allocation, and per-leg availability") .addTag("Stations", "Station directory, location data, baggage facilities, and amenities") .addTag("Support", "FAQ management, search, live chat conversations, and ticket resolution") .addTag("Tickets", "QR/barcode generation, PDF tickets, gate validation, and audit trails") .addTag("Transit Stops", "Cross-border journey management, Dire Dawa hub, multi-leg routing (NEW)") .addTag("Wallet", "Balance management, top-ups, withdrawals, and transaction ledger") //.addServer('http://localhost:4000', 'Development') // .addServer("https://api.edr-platform.com", "Production") .build(); const document = SwaggerModule.createDocument(app, config); SwaggerModule.setup("api-docs", app, document, { customSiteTitle: "EDR Passenger API", swaggerOptions: { persistAuthorization: true, docExpansion: "none", filter: true, tagsSorter: "alpha", operationsSorter: "alpha", }, }); const port = process.env.PORT ?? 4000; await app.listen(port); console.log(`🚀 EDR Passenger API running on port ${port}`); console.log(`📚 Swagger: http://localhost:${port}/api-docs`); } bootstrap();