mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-26 18:42:49 +00:00
768 lines
27 KiB
Markdown
768 lines
27 KiB
Markdown
# EDR Platform - Ethio-Djibouti Railway Passenger API
|
||
|
||
Enterprise-grade NestJS REST API for the Ethio-Djibouti Railway passenger booking and management platform. Built with TypeScript, PostgreSQL, and Prisma ORM.
|
||
|
||
## 🚀 Features
|
||
|
||
### 🆕 NEW: Age-Based Pricing, Verifayda 2.0 & Multi-Currency
|
||
|
||
#### 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)
|
||
|
||
#### Verifayda 2.0 Integration
|
||
- Real-time Ethiopian national ID verification
|
||
- Retrieves passenger data from government database
|
||
- National IDs NOT stored (policy compliant)
|
||
- Non-Ethiopians use passport (no verification required)
|
||
- Booking fails if verification unsuccessful
|
||
|
||
#### Multi-Currency Support
|
||
- **Transaction Currency**: ETB (Ethiopian Birr)
|
||
- **Display Currencies**: ETB, DJF (Djiboutian Franc), USD (US Dollar)
|
||
- Real-time exchange rate conversion
|
||
- Prices shown in user's preferred currency
|
||
- Exchange rates: ETB→DJF=3.25, ETB→USD=0.018
|
||
|
||
### Core Modules
|
||
- **Authentication & Authorization** - Dual authentication system:
|
||
- **Passenger Auth**: JWT-based auth with OTP verification, password reset, account lockout
|
||
- **Corporate IAM**: Integration with @tria-plc corporate identity system for back-office operations (agents, supervisors, admins)
|
||
- Role-based access control (RBAC) with granular permissions
|
||
- **Age-Based Pricing** - Smart passenger categorization:
|
||
- **ADULT** (≥5 years): Full fare
|
||
- **CHILD** (<5 years): First child free, subsequent children full fare
|
||
- Automatic age calculation from date of birth
|
||
- **Verifayda 2.0 Integration** - Ethiopian national ID verification:
|
||
- Real-time verification via government API
|
||
- Retrieves passenger data (name, DOB, nationality)
|
||
- National IDs NOT stored (policy compliant)
|
||
- Non-Ethiopians use passport (no verification)
|
||
- **Multi-Currency Support** - Display prices in multiple currencies:
|
||
- **ETB** (Ethiopian Birr) - Transaction currency
|
||
- **DJF** (Djiboutian Franc) - Display option
|
||
- **USD** (US Dollar) - Display option
|
||
- Real-time exchange rate conversion
|
||
- **Booking Management** - Complete booking lifecycle:
|
||
- **Guest Booking**: Book without login, optional account creation
|
||
- **Saved Passengers**: Store passenger details for quick rebooking
|
||
- Modification, cancellation, refunds, and fare breakdown
|
||
- Multi-segment journey support
|
||
- **Payment Integration** - Multi-provider support (Telebirr, CBE Birr, eBirr, Card, Wallet) with webhook handling
|
||
- **Seat Management** - Real-time seat inventory:
|
||
- Seat holds with 5-minute expiry
|
||
- Seat releases and blocking with coach/class management
|
||
- Segment-based seat availability (partial journey bookings)
|
||
- Auto-assign seats with contiguous algorithm
|
||
- CSV import/export for seat configurations
|
||
- **Ticketing** - QR code and barcode generation, PDF tickets, gate validation with audit logs
|
||
- **Agent Operations** - Counter booking, shift management, commission tracking, and reconciliation
|
||
- **Passenger Services** - Profile management, traveler profiles, saved routes, and preferences
|
||
- **Loyalty Program** - Points accumulation, tier management (Bronze/Silver/Gold/Platinum), and rewards
|
||
- **Wallet System** - Balance management, top-up, transaction ledger
|
||
- **Live Tracking** - Real-time trip status, location updates, delay notifications, crowd signals
|
||
- **Notifications** - Multi-channel (Email, SMS, Push) with templating engine
|
||
- **Support System** - FAQ management, live chat conversations
|
||
- **Reports & Analytics** - Revenue reports, occupancy analytics, agent sales tracking
|
||
- **Route Management** - Route configuration, stops, fare rules, baggage allowance
|
||
|
||
### Technical Features
|
||
- **Security** - Password hashing (bcrypt), JWT tokens, rate limiting, audit logging
|
||
- **Validation** - Request validation with class-validator, DTO transformation
|
||
- **Documentation** - Auto-generated Swagger/OpenAPI docs at `/api-docs`
|
||
- **Error Handling** - Global exception filters with standardized error responses
|
||
- **Database** - PostgreSQL with Prisma ORM, migrations, and comprehensive seeding
|
||
- **Scheduling** - Cron jobs for automated tasks (seat release, report generation)
|
||
- **Event System** - Event-driven architecture with @nestjs/event-emitter
|
||
|
||
## 📋 Prerequisites
|
||
|
||
- **Node.js** >= 20.x
|
||
- **pnpm** >= 9.x (`npm install -g pnpm`)
|
||
- **PostgreSQL** >= 15.x
|
||
- **Git**
|
||
|
||
## 🛠️ Installation & Setup
|
||
|
||
### 1. Clone Repository
|
||
```bash
|
||
git clone <repository-url>
|
||
cd edr-platform
|
||
```
|
||
|
||
### 2. Install Dependencies
|
||
```bash
|
||
pnpm install
|
||
```
|
||
|
||
### 3. Environment Configuration
|
||
```bash
|
||
# Copy environment template
|
||
cp apps/edr-passenger-api/.env.example apps/edr-passenger-api/.env
|
||
|
||
# Edit .env file with your configuration
|
||
```
|
||
|
||
#### Required Environment Variables
|
||
|
||
| Variable | Description | Example |
|
||
|----------|-------------|---------|
|
||
| `NODE_ENV` | Environment mode | `development` |
|
||
| `PORT` | HTTP server port | `4000` |
|
||
| `DATABASE_URL` | PostgreSQL connection string | `postgresql://user:pass@localhost:5432/edr_passenger` |
|
||
| `JWT_SECRET` | JWT signing secret (change in production) | `your-secret-key` |
|
||
| `JWT_EXPIRES_IN` | JWT token expiry | `7d` |
|
||
| `PORTAL_URL` | Web app CORS origin | `http://localhost:3000` |
|
||
| `BACK_OFFICE_URL` | Admin portal CORS origin | `http://localhost:3001` |
|
||
| `SENDGRID_API_KEY` | SendGrid API key (optional) | `SG.xxx` |
|
||
| `SENDGRID_FROM_EMAIL` | Email sender address | `noreply@edr-platform.com` |
|
||
|
||
#### Verifayda 2.0 Configuration (Ethiopian National ID Verification)
|
||
|
||
| Variable | Description | Example |
|
||
|----------|-------------|---------|
|
||
| `VERIFAYDA_ENABLED` | Enable Verifayda integration | `true` or `false` |
|
||
| `VERIFAYDA_API_URL` | Verifayda API endpoint | `https://api.verifayda.gov.et/v2` |
|
||
| `VERIFAYDA_API_KEY` | API key for Verifayda service | `your-verifayda-api-key` |
|
||
|
||
**Note:** When `VERIFAYDA_ENABLED=false`, verification is skipped (development mode only).
|
||
|
||
#### Corporate IAM Configuration (Back-office Authentication)
|
||
|
||
| Variable | Description | Example |
|
||
|----------|-------------|---------|
|
||
| `IAM_ENABLED` | Enable corporate IAM integration | `true` or `false` |
|
||
| `IAM_API_URL` | Corporate IAM API endpoint | `https://iam.tria-plc.com/api` |
|
||
| `IAM_API_KEY` | API key for IAM service | `your-iam-api-key` |
|
||
|
||
**Note:** When `IAM_ENABLED=false`, IAM-protected routes allow access without validation (development mode only).
|
||
|
||
#### Optional: Payment Provider Configuration
|
||
```bash
|
||
# Telebirr Configuration
|
||
TELEBIRR_BASE_URL=https://api.telebirr.com
|
||
TELEBIRR_MERCHANT_CODE=your-merchant-code
|
||
TELEBIRR_APP_SECRET=your-app-secret
|
||
# ... see .env.example for complete list
|
||
```
|
||
|
||
### 4. Database Setup
|
||
|
||
#### Start PostgreSQL
|
||
```bash
|
||
# Using Docker (recommended)
|
||
docker run --name edr-postgres \
|
||
-e POSTGRES_USER=edr \
|
||
-e POSTGRES_PASSWORD=edr_secret \
|
||
-e POSTGRES_DB=edr_passenger \
|
||
-p 5432:5432 \
|
||
-d postgres:15
|
||
|
||
# Or use your local PostgreSQL installation
|
||
```
|
||
|
||
#### Generate Prisma Client
|
||
```bash
|
||
pnpm --filter @edr/passenger-api run prisma:generate
|
||
```
|
||
|
||
#### Run Migrations
|
||
```bash
|
||
pnpm --filter @edr/passenger-api run prisma:migrate:dev
|
||
```
|
||
|
||
#### Seed Database
|
||
```bash
|
||
pnpm --filter @edr/passenger-api run prisma:seed
|
||
```
|
||
|
||
**Seed Data Includes:**
|
||
- 21 Stations (Complete Ethiopian-Djibouti Railway with country codes)
|
||
- 1 Route with 21 stops and fare rules
|
||
- 2 Train services with 4 trips
|
||
- 360 seats across 12 coaches (Economy Regular, Economy Bed, VIP Bed classes)
|
||
- 3 User accounts (Admin, Passenger, Agent)
|
||
- Fare rules for ADULT and CHILD passenger categories
|
||
- Currency exchange rates (ETB, DJF, USD)
|
||
- Baggage allowance rules
|
||
- Notification templates
|
||
- Promotions and FAQ content
|
||
- Menu items and station crowd signals
|
||
- Fraud detection rules
|
||
- Saved passenger profiles for testing
|
||
|
||
### 5. Start Development Server
|
||
```bash
|
||
pnpm --filter @edr/passenger-api run dev
|
||
```
|
||
|
||
**API Server:** http://localhost:4000
|
||
**Swagger Docs:** http://localhost:4000/api-docs
|
||
|
||
## 🔑 Default Credentials
|
||
|
||
After seeding, use these credentials to test the API:
|
||
|
||
| Role | Email | Password | Description |
|
||
|------|-------|----------|-------------|
|
||
| **Admin** | `admin@edr-platform.com` | `admin123` | Full system access, reports, agent management |
|
||
| **Passenger** | `kelemu@email.com` | `password123` | Regular user with loyalty (Silver) and wallet |
|
||
| **Agent** | `agent@edr-platform.com` | `agent123` | Counter booking agent with commission tracking |
|
||
|
||
## 📚 API Documentation
|
||
|
||
### Swagger UI
|
||
Interactive API documentation available at: **http://localhost:4000/api-docs**
|
||
|
||
### Authentication Methods
|
||
|
||
The API uses two authentication schemes:
|
||
|
||
#### 1. JWT Authentication (Passenger-facing)
|
||
- **Used for**: Passenger bookings, profile management, wallet, loyalty
|
||
- **Header**: `Authorization: Bearer <jwt-token>`
|
||
- **Obtain token**: `POST /auth/login` with passenger credentials
|
||
- **Swagger Security**: `JWT-auth`
|
||
|
||
#### 2. IAM Authentication (Back-office)
|
||
- **Used for**: Agent operations, fraud detection, reports, admin functions
|
||
- **Header**: `Authorization: Bearer <iam-token>`
|
||
- **Obtain token**: From corporate IAM system (https://iam.tria-plc.com)
|
||
- **Swagger Security**: `IAM-auth`
|
||
- **Roles**: AGENT, SUPERVISOR, ADMIN, STAFF
|
||
|
||
### API Endpoints Overview
|
||
|
||
| Module | Base Path | Auth Type | Description |
|
||
|--------|-----------|-----------|-------------|
|
||
| **Auth** | `/auth` | Public/JWT | Register, login, OTP verification, password reset |
|
||
| **Passengers** | `/passengers` | Public/JWT | Verifayda verification, international registration, profiles |
|
||
| **Search** | `/search` | Public | Trip search, availability, fare quotes |
|
||
| **Stations** | `/stations` | Public/JWT | Station directory and information |
|
||
| **Seats** | `/seats` | JWT/IAM | Seat maps, holds, releases, blocking |
|
||
| **Bookings** | `/bookings` | Public/JWT | Guest booking, create, modify, cancel bookings |
|
||
| **Payments** | `/payments` | JWT/Public | Payment initiation, webhooks, refunds |
|
||
| **Tickets** | `/tickets` | JWT/IAM | Ticket generation, QR/barcode, validation |
|
||
| **Notifications** | `/notifications` | JWT | In-app notifications, preferences |
|
||
| **Loyalty** | `/loyalty` | JWT | Points, tiers, rewards redemption |
|
||
| **Wallet** | `/wallet` | JWT | Balance, top-up, transaction history |
|
||
| **Promotions** | `/promos` | Public/JWT | Active promotions, promo code validation |
|
||
| **Live Tracking** | `/live` | Public/JWT | Real-time trip status, crowd signals |
|
||
| **Support** | `/support` | Public/JWT | FAQ, chat conversations |
|
||
| **Dashboard** | `/dashboard` | JWT | Home screen aggregated data |
|
||
| **Routes** | `/routes` | JWT/IAM | Reusable route templates with ordered stops |
|
||
| **Schedules** | `/schedules` | JWT/IAM | Trip schedules, fare rules, status updates |
|
||
| **Fleet** | `/fleet` | JWT/IAM | Train services, coaches, seat configurations |
|
||
| **Seat Classes** | `/seat-classes` | Public/JWT/IAM | Seat class management and configuration |
|
||
| **Segment Seats** | `/segments/seats` | Public/JWT | Segment-based seat availability and booking |
|
||
| **Agents** | `/agents` | IAM | Agent booking, shifts, commissions, reconciliation |
|
||
| **Fraud Detection** | `/fraud` | IAM | Fraud alerts, rules management, user blocking |
|
||
| **Reports** | `/reports` | IAM | Revenue, occupancy, agent sales analytics |
|
||
|
||
### Example API Calls
|
||
|
||
#### 1. Register Passenger
|
||
```bash
|
||
POST /auth/register
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"email": "user@example.com",
|
||
"phone": "+251911234567",
|
||
"fullName": "John Doe",
|
||
"password": "SecurePass123"
|
||
}
|
||
```
|
||
|
||
#### 2. Login (Passenger)
|
||
```bash
|
||
POST /auth/login
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"email": "user@example.com",
|
||
"password": "SecurePass123"
|
||
}
|
||
|
||
# Response includes JWT token
|
||
{
|
||
"accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
|
||
"user": { "id": "uuid", "role": "PASSENGER" }
|
||
}
|
||
```
|
||
|
||
#### 3. Verify Ethiopian National ID (Verifayda)
|
||
```bash
|
||
POST /passengers/verify-fayda
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"nationalId": "ET123456789"
|
||
}
|
||
|
||
# Response with verified passenger data
|
||
{
|
||
"verified": true,
|
||
"passengerData": {
|
||
"fullName": "Abebe Kebede",
|
||
"dateOfBirth": "1985-03-15T00:00:00.000Z",
|
||
"gender": "Male",
|
||
"nationality": "Ethiopian"
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 4. Universal Passenger Registration (NEW)
|
||
```bash
|
||
# Guest Ethiopian with Fayda verification
|
||
POST /passengers/register
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"passengerName": "Abebe Kebede",
|
||
"dateOfBirth": "1985-03-15",
|
||
"nationalId": "ET123456789",
|
||
"phone": "+251911234567",
|
||
"deviceId": "device-uuid-123"
|
||
}
|
||
|
||
# Logged-in user with JWT token
|
||
POST /passengers/register
|
||
Authorization: Bearer <jwt-token>
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"passengerName": "Abebe Kebede",
|
||
"dateOfBirth": "1985-03-15",
|
||
"nationalId": "ET123456789",
|
||
"phone": "+251911234567"
|
||
}
|
||
|
||
# International passenger (passport)
|
||
POST /passengers/register
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"passengerName": "John Smith",
|
||
"dateOfBirth": "1990-07-20",
|
||
"passportNumber": "P1234567",
|
||
"passportCountry": "Kenya",
|
||
"nationality": "Kenyan",
|
||
"phone": "+254712345678",
|
||
"email": "john@example.com",
|
||
"deviceId": "device-uuid-123"
|
||
}
|
||
```
|
||
|
||
#### 5. Get User Profile (NEW)
|
||
```bash
|
||
GET /auth/profile
|
||
Authorization: Bearer <jwt-token>
|
||
|
||
# Response includes user, passenger, loyalty, and wallet details
|
||
{
|
||
"id": "uuid",
|
||
"email": "user@example.com",
|
||
"phone": "+251911234567",
|
||
"fullName": "John Doe",
|
||
"role": "PASSENGER",
|
||
"nationality": "Ethiopian",
|
||
"faydaVerified": true,
|
||
"faydaVerifiedAt": "2024-01-15T10:30:00.000Z",
|
||
"passenger": {
|
||
"id": "uuid",
|
||
"loyalty": {
|
||
"tier": "SILVER",
|
||
"pointsBalance": 1500,
|
||
"lifetimePoints": 3000
|
||
},
|
||
"wallet": {
|
||
"balanceMinor": 50000,
|
||
"currency": "ETB"
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 6. Search Trips
|
||
```bash
|
||
POST /search
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"originStationId": "uuid",
|
||
"destinationStationId": "uuid",
|
||
"date": "2026-06-15",
|
||
"adultCount": 2,
|
||
"childCount": 1
|
||
}
|
||
```
|
||
|
||
#### 7. Get Fare Quote
|
||
```bash
|
||
POST /search/fare-quote
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"tripId": "uuid",
|
||
"serviceClass": "ECONOMY_REGULAR",
|
||
"adultCount": 2,
|
||
"childCount": 1,
|
||
"displayCurrency": "USD"
|
||
}
|
||
|
||
# Response includes age-based pricing breakdown
|
||
{
|
||
"baseFareMinor": 35000,
|
||
"adultCount": 2,
|
||
"adultFareMinor": 70000,
|
||
"childCount": 1,
|
||
"freeChildrenCount": 1,
|
||
"paidChildrenCount": 0,
|
||
"childFareMinor": 0,
|
||
"totalMinor": 73500,
|
||
"currency": "ETB",
|
||
"displayCurrency": "USD",
|
||
"displayTotalMinor": 1323
|
||
}
|
||
```
|
||
|
||
#### 8. Guest Booking (No Login Required)
|
||
```bash
|
||
POST /bookings/guest
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"tripId": "uuid",
|
||
"holdId": "uuid",
|
||
"serviceClass": "ECONOMY_REGULAR",
|
||
"displayCurrency": "ETB",
|
||
"passengers": [
|
||
{
|
||
"seatId": "uuid",
|
||
"passengerName": "Abebe Kebede",
|
||
"dateOfBirth": "1985-03-15",
|
||
"idDocumentType": "NATIONAL_ID",
|
||
"idDocumentNumber": "ET123456789"
|
||
}
|
||
],
|
||
"createAccount": false,
|
||
"savePassengerDetails": true,
|
||
"deviceId": "device-uuid"
|
||
}
|
||
```
|
||
|
||
#### 9. Agent Booking (IAM Auth)
|
||
```bash
|
||
POST /agents/bookings
|
||
Authorization: Bearer <iam-token>
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"tripId": "uuid",
|
||
"seats": [...],
|
||
"paymentMethod": "CASH",
|
||
"cashReceived": 50000
|
||
}
|
||
```
|
||
|
||
## 🏗️ Project Structure
|
||
|
||
```
|
||
apps/edr-passenger-api/
|
||
├── prisma/
|
||
│ ├── schema.prisma # Database schema (40+ models)
|
||
│ ├── seed.ts # Comprehensive seed script
|
||
│ └── migrations/ # Database migrations
|
||
├── src/
|
||
│ ├── common/ # Shared utilities
|
||
│ │ ├── filters/ # Exception filters
|
||
│ │ ├── interceptors/ # Response interceptors
|
||
│ │ ├── pipes/ # Validation pipes
|
||
│ │ ├── i18n/ # Internationalization
|
||
│ │ ├── jwt.guard.ts # JWT authentication guard (passengers)
|
||
│ │ ├── jwt.strategy.ts # Passport JWT strategy
|
||
│ │ ├── iam-adapter.ts # Corporate IAM guard (back-office)
|
||
│ │ ├── iam.module.ts # IAM module
|
||
│ │ ├── roles.guard.ts # RBAC authorization guard
|
||
│ │ ├── roles.decorator.ts # Roles decorator
|
||
│ │ ├── prisma.service.ts # Prisma client service
|
||
│ │ └── prisma.module.ts # Prisma module
|
||
│ ├── config/ # Configuration files
|
||
│ │ ├── app.config.ts # App configuration
|
||
│ │ ├── database.config.ts # Database configuration
|
||
│ │ └── telebirr.config.ts # Payment provider config
|
||
│ ├── modules/ # Feature modules
|
||
│ │ ├── auth/ # Authentication & authorization (JWT)
|
||
│ │ ├── agents/ # Agent operations (IAM-protected)
|
||
│ │ ├── bookings/ # Booking management (JWT)
|
||
│ │ ├── currency/ # Currency conversion service
|
||
│ │ ├── dashboard/ # Dashboard aggregations (JWT)
|
||
│ │ ├── fleet/ # Train fleet management (JWT/IAM)
|
||
│ │ ├── fraud/ # Fraud detection (IAM-protected)
|
||
│ │ ├── live/ # Live tracking (JWT)
|
||
│ │ ├── loyalty/ # Loyalty program (JWT)
|
||
│ │ ├── notifications/ # Notification system (JWT)
|
||
│ │ ├── passengers/ # Passenger management (JWT)
|
||
│ │ ├── payments/ # Payment processing (JWT/Webhooks)
|
||
│ │ ├── promos/ # Promotions (JWT)
|
||
│ │ ├── reports/ # Reports & analytics (IAM-protected)
|
||
│ │ ├── schedules/ # Trip schedules (JWT/IAM)
|
||
│ │ ├── search/ # Trip search (JWT)
|
||
│ │ ├── seats/ # Seat management (JWT/IAM)
|
||
│ │ ├── segments/ # Journey segments (JWT)
|
||
│ │ ├── stations/ # Station management (JWT)
|
||
│ │ ├── support/ # Customer support (JWT)
|
||
│ │ ├── tickets/ # Ticketing (JWT/IAM)
|
||
│ │ ├── verifayda/ # Verifayda 2.0 integration
|
||
│ │ └── wallet/ # Wallet system (JWT)
|
||
│ ├── app.module.ts # Root application module
|
||
│ └── main.ts # Application entry point
|
||
├── test/ # E2E tests
|
||
├── .env.example # Environment template
|
||
├── Dockerfile # Docker configuration
|
||
├── nest-cli.json # NestJS CLI configuration
|
||
├── package.json # Dependencies & scripts
|
||
├── tsconfig.json # TypeScript configuration
|
||
└── tsconfig.build.json # Build configuration
|
||
```
|
||
|
||
## 🗄️ Database Schema
|
||
|
||
### Key Models (40+ total)
|
||
|
||
**Core Entities:**
|
||
- `User`, `Session`, `Passenger`, `Agent`
|
||
- `Station`, `Route`, `RouteStop`, `RouteFareRule`
|
||
- `TrainService`, `Trip`, `TripStopTime`, `Coach`, `Seat`
|
||
- `Booking`, `BookingSeat`, `Ticket`
|
||
- `PaymentIntent`, `PaymentRefund`, `PaymentWebhookEvent`
|
||
|
||
**Enhanced Features:**
|
||
- `OtpCode`, `PasswordResetToken` (Auth)
|
||
- `AgentBooking`, `AgentShift`, `AgentCommission` (Agents)
|
||
- `BookingModification`, `BookingCancellation` (Booking lifecycle)
|
||
- `GateValidationLog` (Ticket validation)
|
||
- `BaggageAllowance`, `BaggageBooking` (Baggage)
|
||
- `LoyaltyAccount`, `LoyaltyLedgerEntry`, `LoyaltyReward`
|
||
- `WalletAccount`, `WalletLedgerEntry`
|
||
- `Notification`, `NotificationTemplate`
|
||
- `AuditLog`, `OperationalReport`
|
||
- `SeatBlock`, `SeatHold`
|
||
- `CurrencyExchangeRate` (Multi-currency)
|
||
- `VerifaydaVerification` (National ID verification)
|
||
- `SavedPassengerProfile` (Guest booking)
|
||
- `SeatClass` (Seat class configuration)
|
||
- `JourneySegment` (Multi-segment journeys)
|
||
|
||
## 🔧 Available Scripts
|
||
|
||
```bash
|
||
# Development
|
||
pnpm --filter @edr/passenger-api run dev # Start with hot-reload
|
||
|
||
# Build
|
||
pnpm --filter @edr/passenger-api run build # Compile TypeScript
|
||
|
||
# Production
|
||
pnpm --filter @edr/passenger-api run start # Run compiled code
|
||
|
||
# Testing
|
||
pnpm --filter @edr/passenger-api run test # Unit tests
|
||
pnpm --filter @edr/passenger-api run test:e2e # E2E tests
|
||
|
||
# Code Quality
|
||
pnpm --filter @edr/passenger-api run lint # ESLint
|
||
pnpm --filter @edr/passenger-api run type-check # TypeScript check
|
||
|
||
# Database
|
||
pnpm --filter @edr/passenger-api run prisma:generate # Generate Prisma client
|
||
pnpm --filter @edr/passenger-api run prisma:migrate:dev # Run migrations (local dev)
|
||
pnpm --filter @edr/passenger-api run prisma:seed # Seed database
|
||
```
|
||
|
||
## 🐳 Docker Deployment
|
||
|
||
All six apps build from Dockerfiles: each API has its own (`apps/edr-freight-api/Dockerfile`, `apps/edr-passenger-api/Dockerfile`); Vite frontends share `infrastructure/docker/Dockerfile.web` and are served with **nginx**. APIs run on **Node 22**.
|
||
|
||
**Prerequisites**
|
||
|
||
- Docker with BuildKit enabled
|
||
- A local [`.npmrc`](.gitignore) with GitHub Packages auth for `@tria-plc/*` (required for **freight** API and web images)
|
||
- External Postgres for each API (compose does **not** include databases)
|
||
- Copy `apps/edr-freight-api/.env.example` → `.env` and `apps/edr-passenger-api/.env.example` → `.env` with real connection strings
|
||
|
||
### Build and run (all apps)
|
||
|
||
```bash
|
||
# From monorepo root
|
||
DOCKER_BUILDKIT=1 pnpm docker:build
|
||
pnpm docker:up
|
||
```
|
||
|
||
Or without pnpm scripts:
|
||
|
||
```bash
|
||
DOCKER_BUILDKIT=1 docker compose build
|
||
docker compose up -d
|
||
```
|
||
|
||
| Service | URL (default) |
|
||
|---------|----------------|
|
||
| Freight API | http://localhost:3001 |
|
||
| Passenger API | http://localhost:4000 |
|
||
| Freight portal | http://localhost:5173 |
|
||
| Freight backoffice | http://localhost:5183 |
|
||
| Passenger portal | http://localhost:5174 |
|
||
| Passenger backoffice | http://localhost:5184 |
|
||
|
||
### Build a single service
|
||
|
||
```bash
|
||
docker compose build freight-api
|
||
docker compose build passenger-portal
|
||
```
|
||
|
||
Freight images mount `.npmrc` as a BuildKit secret during `pnpm install`. Passenger web images do not require private packages.
|
||
|
||
### `VITE_API_URL` (frontends)
|
||
|
||
API URLs are **baked in at image build time** (`import.meta.env.VITE_API_URL`). Defaults in [`docker-compose.yaml`](docker-compose.yaml) use `http://localhost:3001/api` (freight) and `http://localhost:4000` (passenger) for local smoke tests. Override build args for production, e.g.:
|
||
|
||
```bash
|
||
docker compose build freight-portal \
|
||
--build-arg VITE_API_URL=https://freight-api.example.com/api
|
||
```
|
||
|
||
### Migrations
|
||
|
||
- **Freight API:** TypeORM migrations are not run on container startup — apply them separately before deploy.
|
||
- **Passenger API:** On each container start, the entrypoint runs `npm run prisma:migrate` and `npm run prisma:seed` (same `package.json` scripts as `pnpm run`) before starting the server. Ensure `DATABASE_URL` in `.env` points at a reachable Postgres instance.
|
||
|
||
For local development, use `pnpm --filter @edr/passenger-api run prisma:migrate:dev` instead of `prisma:migrate`.
|
||
|
||
### GitHub Actions (self-hosted runner)
|
||
|
||
Two workflows deploy independently on push to `main`, `develop`, or `staging`:
|
||
|
||
| Workflow | Services | Server env root |
|
||
|----------|----------|-----------------|
|
||
| [`.github/workflows/deploy-freight.yml`](.github/workflows/deploy-freight.yml) | freight-api, freight-portal, freight-backoffice | `/home/user/environmen/edr-freight/<branch>/` |
|
||
| [`.github/workflows/deploy-passenger.yml`](.github/workflows/deploy-passenger.yml) | passenger-api, passenger-portal, passenger-backoffice | `/home/user/environmen/edr-passenger/<branch>/` |
|
||
|
||
**On the runner**, place env files before the first deploy (example for branch `main`):
|
||
|
||
```text
|
||
/home/user/environmen/edr-freight/main/
|
||
freight-api.env
|
||
freight-portal.env # optional runtime env for Vite/nginx
|
||
freight-backoffice.env
|
||
freight-web.build.env # exports FREIGHT_VITE_API_URL=...
|
||
|
||
/home/user/environmen/edr-passenger/main/
|
||
passenger-api.env
|
||
passenger-portal.env
|
||
passenger-backoffice.env
|
||
passenger-web.build.env # exports PASSENGER_VITE_API_URL=...
|
||
```
|
||
|
||
Example `freight-web.build.env`:
|
||
|
||
```bash
|
||
export FREIGHT_VITE_API_URL=https://freight-api.example.com/api
|
||
```
|
||
|
||
The workflow copies `*.env` into each app directory, creates `.npmrc` from the `NPM_TOKEN` repository secret, then runs `docker compose build` and `docker compose up -d` for that stack.
|
||
|
||
## 🔒 Security Best Practices
|
||
|
||
1. **Environment Variables** - Never commit `.env` files. Use secrets management in production.
|
||
2. **JWT Secret** - Use strong, randomly generated secrets (min 32 characters).
|
||
3. **Password Hashing** - Bcrypt with salt rounds (default: 10).
|
||
4. **Rate Limiting** - Implement rate limiting for auth endpoints.
|
||
5. **CORS** - Configure allowed origins in production.
|
||
6. **HTTPS** - Always use HTTPS in production.
|
||
7. **Database** - Use connection pooling and prepared statements (Prisma handles this).
|
||
8. **Audit Logging** - All sensitive operations are logged in `AuditLog` table.
|
||
9. **Dual Authentication** - Passenger routes use JWT, back-office routes use corporate IAM.
|
||
10. **IAM Integration** - Corporate IAM validates tokens against centralized identity service.
|
||
11. **Role-Based Access** - Granular permissions enforced via IAM roles (AGENT, SUPERVISOR, ADMIN).
|
||
12. **Token Validation** - IAM tokens validated in real-time with 5-second timeout.
|
||
|
||
## 📊 Monitoring & Logging
|
||
|
||
- **Application Logs** - NestJS built-in logger
|
||
- **Database Queries** - Prisma query logging (enable in development)
|
||
- **Audit Trail** - All user actions logged in `AuditLog` table
|
||
- **Error Tracking** - Global exception filters with detailed error responses
|
||
|
||
## 🧪 Testing
|
||
|
||
```bash
|
||
# Unit tests
|
||
pnpm --filter @edr/passenger-api run test
|
||
|
||
# E2E tests
|
||
pnpm --filter @edr/passenger-api run test:e2e
|
||
|
||
# Test coverage
|
||
pnpm --filter @edr/passenger-api run test:cov
|
||
```
|
||
|
||
## 🚀 Production Deployment
|
||
|
||
### Pre-deployment Checklist
|
||
- [ ] Update environment variables (JWT_SECRET, DATABASE_URL, etc.)
|
||
- [ ] Configure IAM integration (IAM_ENABLED=true, IAM_API_URL, IAM_API_KEY)
|
||
- [ ] Configure Verifayda integration (VERIFAYDA_ENABLED=true, VERIFAYDA_API_KEY)
|
||
- [ ] Set up currency exchange rate sync (external API)
|
||
- [ ] Set NODE_ENV=production
|
||
- [ ] Configure CORS origins (PORTAL_URL, BACK_OFFICE_URL)
|
||
- [ ] Set up SSL/TLS certificates
|
||
- [ ] Configure database connection pooling
|
||
- [ ] Set up monitoring and logging
|
||
- [ ] Configure backup strategy
|
||
- [ ] Test payment provider integrations
|
||
- [ ] Verify IAM token validation endpoint
|
||
- [ ] Test Verifayda verification with real national IDs
|
||
- [ ] Verify currency conversion accuracy
|
||
- [ ] Test age-based pricing calculations
|
||
- [ ] Review security settings and audit logs
|
||
- [ ] Test both JWT and IAM authentication flows
|
||
|
||
### Deployment Steps
|
||
```bash
|
||
# 1. Build application
|
||
pnpm --filter @edr/passenger-api run build
|
||
|
||
# 2. Run migrations
|
||
pnpm --filter @edr/passenger-api run prisma:migrate
|
||
|
||
# 3. Start production server
|
||
NODE_ENV=production pnpm --filter @edr/passenger-api run start:prod
|
||
```
|
||
|
||
## 🤝 Contributing
|
||
|
||
1. Fork the repository
|
||
2. Create feature branch (`git checkout -b feature/amazing-feature`)
|
||
3. Commit changes (`git commit -m 'Add amazing feature'`)
|
||
4. Push to branch (`git push origin feature/amazing-feature`)
|
||
5. Open Pull Request
|
||
|
||
## 📝 License
|
||
|
||
This project is proprietary and confidential.
|
||
|
||
## 📧 Support
|
||
|
||
For technical support or questions:
|
||
- Email: support@edr-platform.com
|
||
- Documentation: http://localhost:4000/api-docs
|
||
|
||
---
|
||
|
||
**Built with ❤️ for Ethio-Djibouti Railway**
|