mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-30 09:58:12 +00:00
Merge branch 'dev' into passenger/feat/iam
This commit is contained in:
@@ -12,7 +12,9 @@ import { ResponseTransformInterceptor } from "./common/interceptors/response-tra
|
||||
import { SessionActivityInterceptor } from "./common/interceptors/session-activity.interceptor";
|
||||
|
||||
async function bootstrap() {
|
||||
const app = await NestFactory.create(AppModule);
|
||||
// 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 });
|
||||
|
||||
// URI versioning: the @tria-plc IAM controllers declare `version: "1"` so they register under
|
||||
// `/v1/...` (e.g. /v1/auth/login). Passenger controllers declare no version, so they stay
|
||||
@@ -41,11 +43,25 @@ async function bootstrap() {
|
||||
## 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
|
||||
- **TRANSIT & ROUND_TRIP_TRANSIT Booking Types:** Full multi-leg booking support. TRANSIT = single journey via connecting train (single PNR). ROUND_TRIP_TRANSIT = round trip where one or both directions use a connecting train (4 holds, 4 seat sets).
|
||||
- **returnSeatId on Passenger Payloads:** For ROUND_TRIP and ROUND_TRIP_TRANSIT bookings each passenger object must include \`returnSeatId\` (the seat on the return leg-1). Guest and authenticated booking endpoints both enforce this.
|
||||
- **Unified Booking Type Matrix:** bookingType field on Booking now accepts ONE_WAY | ROUND_TRIP | TRANSIT | ROUND_TRIP_TRANSIT across all create endpoints (POST /bookings and POST /bookings/guest).
|
||||
- **Round-Trip Leg Tracking:** returnLegStatus on every booking tracks outbound/return leg usage (NEITHER_USED, OUTBOUND_ONLY, INBOUND_ONLY, BOTH_USED). Gate validation accepts a leg field (OUTBOUND | RETURN | LEG1 | LEG2 | OUTBOUND_LEG1 | OUTBOUND_LEG2 | RETURN_LEG1 | RETURN_LEG2).
|
||||
- **Auto No-Show Detection:** Cron marks OUTBOUND_ONLY 30 min after return departure when return leg was never scanned.
|
||||
- **Offline Batch Validation:** validateOfflineBatch now accepts leg per entry and handles both legs of a round-trip in one batch.
|
||||
- **Booking Filters:** GET /bookings now accepts ?returnLegStatus= to filter no-show/inbound-only cases in back-office.
|
||||
- **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.
|
||||
- **Multi-Currency Display:** Bookings track display currency and converted amounts.
|
||||
- **Ticket Lifecycle:** Tickets now include validatedAt, outboundBoardedAt, returnBoardedAt for complete audit trail.
|
||||
|
||||
## Key Features
|
||||
|
||||
### 🎫 Booking Lifecycle
|
||||
### Booking Lifecycle
|
||||
- Search trips with real-time availability
|
||||
- Age-based passenger categorization (Adult ≥5 years, Child <5 years)
|
||||
- Age-based passenger categorization (Adult 5+ years, Child under 5)
|
||||
- Nationality-based verification (Ethiopian Fayda, International Passport)
|
||||
- Passenger information collection with verification
|
||||
- Coach and seat selection with real-time availability
|
||||
@@ -54,87 +70,143 @@ Enterprise-grade REST API for the Ethio-Djibouti Railway passenger booking and m
|
||||
- Modify bookings (seat changes, passenger updates)
|
||||
- Cancel bookings with automatic refunds
|
||||
- Multi-segment journey support
|
||||
- Cross-border journeys via Dire Dawa transit (Ethiopia to Djibouti)
|
||||
- Round-trip booking with return journey scheduling
|
||||
- Transit booking (single journey via connecting train, single PNR, single ticket)
|
||||
- Round-trip transit booking (round trip where one or both directions use a connecting train)
|
||||
- Coach type selection with seat class and pricing options
|
||||
- Booking type field: ONE_WAY | ROUND_TRIP | TRANSIT | ROUND_TRIP_TRANSIT
|
||||
- Display currency and converted pricing per booking
|
||||
- returnLegStatus field tracks which legs of a round-trip were used
|
||||
- GET /bookings?returnLegStatus=OUTBOUND_ONLY filters no-show returns in back-office
|
||||
|
||||
### 👤 Passenger Verification
|
||||
1. **Ethiopian Nationals:**
|
||||
- Automatic Fayda verification for adults (≥5 years)
|
||||
### 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:**
|
||||
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%
|
||||
### Age-Based Pricing
|
||||
- ADULT (5+ years): Pay 100% of base fare
|
||||
- CHILD (under 5): 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)
|
||||
- Example: 2 adults + 3 children = 4x 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
|
||||
- **eBirr** - Electronic payment gateway
|
||||
### Payment Integration
|
||||
1. Ethiopian Payment Methods: Telebirr, CBE Birr
|
||||
2. Djiboutian Payment Methods: Waafi
|
||||
3. International Payment Methods: Card, Wallet
|
||||
|
||||
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
|
||||
### 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
|
||||
- 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
|
||||
### 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, outboundBoardedAt, returnBoardedAt timestamps)
|
||||
- NEW: Gate validation accepts leg (OUTBOUND or RETURN) for round-trip tickets
|
||||
- NEW: Complete audit trail per leg for compliance and reporting
|
||||
|
||||
### 🏆 Loyalty Program
|
||||
### Booking Type Matrix
|
||||
|
||||
| bookingType | Holds required | Passenger seat fields | Legs in DB |
|
||||
|---|---|---|---|
|
||||
| ONE_WAY | holdId | seatId | 1 |
|
||||
| ROUND_TRIP | holdId + returnHoldId | seatId + returnSeatId | 2 (leg=1 outbound, leg=2 return) |
|
||||
| TRANSIT | holdId + leg2HoldId | seatId + leg2SeatId | 2 (leg=1, leg=2 on same direction) |
|
||||
| ROUND_TRIP_TRANSIT | holdId + leg2HoldId + returnHoldId + returnLeg2HoldId | seatId + leg2SeatId + returnSeatId + returnLeg2SeatId | 4 |
|
||||
|
||||
### Round-Trip Leg Tracking
|
||||
- returnLegStatus on Booking: NOT_APPLICABLE, NEITHER_USED, OUTBOUND_ONLY, INBOUND_ONLY, BOTH_USED
|
||||
- Gate validation POST /tickets/:ref/validate accepts optional leg field:
|
||||
- ONE_WAY: omit
|
||||
- TRANSIT: LEG1 | LEG2
|
||||
- ROUND_TRIP: OUTBOUND | RETURN
|
||||
- ROUND_TRIP_TRANSIT: OUTBOUND_LEG1 | OUTBOUND_LEG2 | RETURN_LEG1 | RETURN_LEG2
|
||||
- Auto no-show cron: sets OUTBOUND_ONLY 30 min after return departure when return leg unscanned
|
||||
- Back-office filter: GET /bookings?returnLegStatus=OUTBOUND_ONLY surfaces no-shows
|
||||
- Offline batch: validateOfflineBatch accepts leg per entry, handles both legs of same booking
|
||||
|
||||
### Round-Trip & Transit Bookings
|
||||
- ONE_WAY and ROUND_TRIP for direct routes
|
||||
- TRANSIT for single connecting journey (Dire Dawa hub), single PNR
|
||||
- ROUND_TRIP_TRANSIT for round trips via connecting trains
|
||||
- Combined pricing: total = sum of all leg base fares, single promo/loyalty deduction
|
||||
- Separate seat management per leg; each leg stored with its scheduleId and leg number
|
||||
- returnLegStatus tracks which legs have been boarded for no-show management
|
||||
|
||||
### Loyalty Program
|
||||
- 4 tiers: Bronze, Silver, Gold, Platinum
|
||||
- Points accumulation on trips
|
||||
- Reward redemption
|
||||
- Tier-based benefits
|
||||
|
||||
### 💰 Wallet System
|
||||
### Wallet System
|
||||
- Top-up via payment methods
|
||||
- Pay with wallet balance
|
||||
- Transaction ledger
|
||||
- Refund to wallet
|
||||
|
||||
### 📍 Live Tracking
|
||||
### Live Tracking
|
||||
- Real-time trip status
|
||||
- Location updates
|
||||
- Delay notifications
|
||||
- Station crowd signals
|
||||
|
||||
### 🔒 Fraud Detection
|
||||
### Fraud Detection
|
||||
- Velocity checks (multiple bookings)
|
||||
- High-value transaction monitoring
|
||||
- Failed payment pattern detection
|
||||
- Automatic user blocking
|
||||
|
||||
### 🌍 Internationalization
|
||||
### 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
|
||||
|
||||
### 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)
|
||||
|
||||
### 👨💼 Agent Operations
|
||||
- Counter booking
|
||||
- Shift management
|
||||
- Commission tracking
|
||||
- Cash reconciliation
|
||||
### Transit Stop Management
|
||||
- Automatic detection of cross-border journeys (Ethiopia to 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
|
||||
|
||||
### Coach Type & Class Selection
|
||||
- Browse available coach types per route
|
||||
- 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
|
||||
- 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
|
||||
|
||||
@@ -151,26 +223,37 @@ Used for agent, fraud, and reporting endpoints. Requires corporate IAM token.
|
||||
## Passenger Booking Flow
|
||||
|
||||
### Step 1: Search Trips
|
||||
\`POST /search\` with origin, destination, date, passenger counts, and nationality
|
||||
\`POST /search\` with origin, destination, date, passenger counts, and nationality.
|
||||
For round-trips also pass \`journeyType=ROUND_TRIP\` and \`returnDate\`.
|
||||
|
||||
### Step 2: Get Fare Quote
|
||||
\`POST /search/fare-quote\` with passenger counts and display currency
|
||||
\`POST /search/fare-quote\` with passenger counts and display currency.
|
||||
For round-trips also pass \`returnScheduleId\`, \`returnOriginStationId\`, \`returnDestinationStationId\`.
|
||||
|
||||
### Step 3: Passenger Information & Verification
|
||||
**For Ethiopian Passengers:**
|
||||
\`POST /passengers/verify-fayda\` - Automatic Fayda verification for adults (≥5 years)
|
||||
\`POST /passengers/verify-fayda\` — Automatic Fayda verification for adults (5+ years)
|
||||
|
||||
**For International Passengers:**
|
||||
\`POST /passengers/register-international\` - Passport information collection
|
||||
\`POST /passengers/register-international\` — Passport information collection
|
||||
|
||||
### Step 4: View Seat Map
|
||||
\`GET /seats/seatmap/{scheduleId}\` - Show available coaches and seats
|
||||
\`GET /seats/seatmap/{scheduleId}\` — Show available coaches and seats.
|
||||
For round-trips, call this twice: once for outbound scheduleId, once for return scheduleId.
|
||||
|
||||
### Step 5: Login & Hold Seats
|
||||
\`POST /auth/login\` then \`POST /seats/hold\` to reserve seats for 15 minutes
|
||||
### Step 5: Hold Seats
|
||||
\`POST /seats/hold\` to reserve seats for 15 minutes.
|
||||
- ONE_WAY / TRANSIT outbound leg: one hold call → \`holdId\`
|
||||
- TRANSIT leg-2: second hold call → \`leg2HoldId\`
|
||||
- ROUND_TRIP return: second hold call → \`returnHoldId\`
|
||||
- ROUND_TRIP_TRANSIT: four hold calls → \`holdId\`, \`leg2HoldId\`, \`returnHoldId\`, \`returnLeg2HoldId\`
|
||||
|
||||
### Step 6: Create Booking
|
||||
\`POST /bookings/guest\` with verified passenger details and held seats
|
||||
Choose the right endpoint and bookingType:
|
||||
- **ONE_WAY** → \`POST /bookings/guest\` or \`POST /bookings\` with \`bookingType: ONE_WAY\`, passenger \`seatId\`
|
||||
- **ROUND_TRIP** → same endpoint with \`bookingType: ROUND_TRIP\`, \`returnScheduleId/returnHoldId/returnOriginStationId/returnDestinationStationId\`, passenger \`seatId + returnSeatId\`
|
||||
- **TRANSIT** → same endpoint with \`bookingType: TRANSIT\`, \`leg2ScheduleId/leg2HoldId/transitStationId/leg2DestinationStationId\`, passenger \`seatId + leg2SeatId\`
|
||||
- **ROUND_TRIP_TRANSIT** → same endpoint with \`bookingType: ROUND_TRIP_TRANSIT\`, all 4 sets of schedule/hold/station fields, passenger \`seatId + leg2SeatId + returnSeatId + returnLeg2SeatId\`
|
||||
|
||||
### Step 7: Process Payment
|
||||
\`POST /payments/telebirr\` (Ethiopian) or \`POST /payments/waafi\` (Djiboutian)
|
||||
@@ -204,7 +287,6 @@ List endpoints support pagination:
|
||||
Payment providers send notifications to:
|
||||
- \`POST /payments/webhooks/telebirr\` (Ethiopia)
|
||||
- \`POST /payments/webhooks/cbe-birr\` (Ethiopia)
|
||||
- \`POST /payments/webhooks/ebirr\` (Ethiopia)
|
||||
- \`POST /payments/webhooks/waafi\` (Djibouti)
|
||||
- \`POST /payments/webhooks/card\` (International)
|
||||
|
||||
@@ -219,33 +301,37 @@ Payment providers send notifications to:
|
||||
{ type: "http", scheme: "bearer", bearerFormat: "JWT", in: "header" },
|
||||
"JWT-auth",
|
||||
)
|
||||
.addTag("Agents", "Counter booking, shift management, and commission tracking")
|
||||
.addTag("Auth", "User registration, login, and profile management")
|
||||
.addTag("Booking", "Complete booking lifecycle: create, modify, cancel")
|
||||
.addTag("Dashboard", "Aggregated dashboard data for home screen")
|
||||
.addTag("Fare Engine", "Distance-based fare calculator with multi-currency support")
|
||||
.addTag("Fayda Verification", "Ethiopian national ID verification via government API")
|
||||
.addTag("Fleet", "Train services, coaches, and seat configurations")
|
||||
.addTag("Fraud Detection", "Fraud monitoring, alerts, and user blocking")
|
||||
.addTag("Live Tracking", "Real-time trip status, delays, and station crowds")
|
||||
.addTag("Loyalty", "Points accumulation, tiers, and reward redemption")
|
||||
.addTag("Notifications", "Multi-channel notifications: email, SMS, push")
|
||||
.addTag("Passengers", "Passenger registration, verification, and profiles")
|
||||
.addTag("Payment", "Payment processing, intents, and refunds")
|
||||
.addTag("Payment Webhooks", "Payment provider webhook handlers")
|
||||
.addTag("Promotions", "Promo codes, campaigns, and discount management")
|
||||
.addTag("Reports", "Sales reports, occupancy analytics, and metrics")
|
||||
.addTag("Routes", "Route templates with stops and fare rules")
|
||||
.addTag("Schedule", "Trip schedules, availability, and status updates")
|
||||
.addTag("Search", "Trip search, availability checks, and fare quotes")
|
||||
.addTag("Seat Classes", "Seat class management: Economy, VIP configurations")
|
||||
.addTag("Seats", "Seat maps, holds, releases, and blocking")
|
||||
.addTag("Segment-based Seats", "Segment-level seat allocation and availability")
|
||||
.addTag("Stations", "Station directory and information")
|
||||
.addTag("Support", "FAQ management and live chat support")
|
||||
.addTag("Tickets", "QR ticket generation, PDFs, and gate validation")
|
||||
.addTag("Wallet", "Wallet balance, top-ups, and transaction ledger")
|
||||
.addTag("Config", "System configuration and settings")
|
||||
.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. Supports ONE_WAY | ROUND_TRIP | TRANSIT | ROUND_TRIP_TRANSIT booking types. returnLegStatus filter for round-trip no-show management")
|
||||
.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("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 with per-leg tracking (OUTBOUND/RETURN/LEG1/LEG2/OUTBOUND_LEG1/OUTBOUND_LEG2/RETURN_LEG1/RETURN_LEG2), and audit trails")
|
||||
.addTag("Transit Stops", "Cross-border journey management, Dire Dawa hub, TRANSIT and ROUND_TRIP_TRANSIT bookings")
|
||||
.addTag("Wallet", "Balance management, top-ups, withdrawals, and transaction ledger")
|
||||
//.addServer('http://localhost:4000', 'Development')
|
||||
// .addServer("https://api.edr-platform.com", "Production")
|
||||
.build();
|
||||
|
||||
Reference in New Issue
Block a user