Airbourne is a microservices-based flight booking platform composed of independently deployable Node.js services. It supports flight search and management, user authentication and authorization, ticket booking, and email reminders/notifications. An API Gateway provides rate limiting and routing to backend services.

- API Gateway (
API_gateway)- Express reverse proxy with rate limiting via
express-rate-limit - Proxies
/bookingserviceto Booking Service (localhost:3002) - Auth check via
Auth_serviceGET /api/v1/isAuthenticatedbefore forwarding - Port:
3005
- Express reverse proxy with rate limiting via
- Auth Service (
Auth_service)- User signup/signin, JWT auth, role-based checks
- Sequelize + MySQL; Swagger UI at
/api-docs - Port: from
PORTenv (commonly3001)
- Flights and Search (
FlightsAndSearch)- CRUD for
City,Airport,Airplane,Flight - Input validation middleware for creating flights
- Sequelize + MySQL
- Port: from
PORTenv
- CRUD for
- Reminder Service (
reminderService)- Consumes AMQP messages for notifications and schedules email jobs
- Nodemailer for email; Sequelize + MySQL
- Port: from
PORTenv
- Air Ticket Booking Service (
AirTicketBookingService)- Booking workflows (entrypoint present, source not fully scanned here)
- Port: from
PORTenv (commonly3002)
- Client authenticates against
Auth_serviceand receives a JWT. - Requests to
/bookingservice/**go throughAPI_gatewaywhere the JWT is verified byAuth_service. - Gateway proxies authorized requests to Booking Service.
- Booking/flight changes may emit AMQP events;
reminderServiceconsumes and sends emails.
- Decouples services so producers (e.g., Booking) and consumers (Reminder) can scale independently.
- Improves reliability and user experience by handling asynchronous work (emails, notifications) off the critical request path.
- Adds resilience via queueing and retries; transient failures in consumers do not impact producers immediately.
- Enables fan-out and selective routing using exchanges and binding keys.
- Reminder Service subscribes to messages to create and send notifications.
- Queue:
notification_queue - Binding key (from env):
EXCHANGE_BINDING_KEY(exposed asREMINDER_BINDING_KEYin code) - Exchange:
EXCHANGE_NAME - Consumer setup:
subscribeMessage(channel, 'notification_queue', EmailService.subscribeEvents, REMINDER_BINDING_KEY)
- Queue:
- Producers (e.g., Booking Service and/or Flights Service) publish events such as ticket creation, payment success, or flight updates. These events are routed to the
notification_queuefor downstream processing by the Reminder Service.
- The Reminder Service’s
EmailService.subscribeEvents(payload)switches onpayload.serviceto trigger actions:CREATE_TICKET: persists a notification ticket for later sendingSEND_BASIC_MAIL: sends a basic email via Nodemailer
- A scheduled job scans for
PENDINGtickets and dispatches emails, updating ticket status afterward.
Add to .env in reminderService (and to producers where applicable):
MESSAGE_BROKER_URL(e.g.,amqp://localhost)EXCHANGE_NAMEEXCHANGE_BINDING_KEY(used asREMINDER_BINDING_KEYin code)
- Node.js, Express, Sequelize (MySQL)
- JWT for auth (
jsonwebtoken), password hashing (bcrypt) - Reverse proxy (
http-proxy-middleware), logging (morgan) - Rate limiting (
express-rate-limit) - Messaging via AMQP (
amqplib) - Email via
nodemailer - Dev tooling:
nodemon, Swagger (swagger-jsdoc,swagger-ui-express)
Create a .env file in each service with the following (adjust as needed):
-
Auth Service (
Auth_service)PORT(e.g., 3001)JWT_key(secret for signing tokens)DB_SYNC(optional; truthy to runsequelize.sync({ alter: true }))- Standard Sequelize environment via
src/config/config.json
-
Flights and Search (
FlightsAndSearch)PORTSYNC(truthy to runsequelize.sync({ force: true }))- Standard Sequelize environment via
src/config/config.json
-
Reminder Service (
reminderService)PORTEMAIL_ID,EMAIL_PASSMESSAGE_BROKER_URL(e.g.,amqp://localhost)EXCHANGE_NAMEEXCHANGE_BINDING_KEY(used asREMINDER_BINDING_KEYin code)- Standard Sequelize environment via
src/config/config.json
-
API Gateway (
API_gateway)- Typically no
.envneeded; update target URLs inindex.jsif changed
- Typically no
-
Air Ticket Booking Service (
AirTicketBookingService)PORT- Database and any AMQP config (follow the pattern from other services)
For services using Sequelize, create src/config/config.json:
{
"development": {
"username": "root",
"password": "<password>",
"database": "<db_name>",
"host": "127.0.0.1",
"dialect": "mysql"
}
}Initialize databases per service:
npx sequelize db:create
# Optional during development
DB_SYNC=true node src/index.jsGET /home→ health check- Proxies
/bookingservice/**tohttp://localhost:3002/**after callingAuth_serviceGET http://localhost:3001/api/v1/isAuthenticatedwith headerx-access-token - Rate limit: 5 requests per 2 minutes per IP
- Base path:
/api/v1 POST /signup→ body:{ email, password }POST /signin→ body:{ email, password }→ returns tokenGET /isAuthenticated→ header:x-access-tokenGET /dummy→ quick OKGET /isAdmin→ body:{ id }GET /health→ service healthGET /api-docs→ Swagger UI
- Base path:
/api/v1 - Cities
POST /cityGET /city/:idGET /cityPATCH /city/:idDELETE /city/:id
- Airplanes
POST /airplaneGET /airplane/:idGET /airplanePATCH /airplane/:idDELETE /airplane/:id
- Airports
POST /airportsGET /airports/:idGET /airportsPATCH /airports/:idDELETE /airports/:id
- Flights
POST /flights(requires body:flightNumber, airplaneId, departureAirportID, arrivalAirportId, arrivalTime, departureTime, price)GET /flightsGET /flights/:idPATCH /flights/:idDELETE /flights/:id
- Subscribes to AMQP queue
notification_queuewith binding keyEXCHANGE_BINDING_KEY POST /api/v1/tickets→ create notification ticket- Scheduled job runner triggers email sends for
PENDINGtickets
- Exposed via API Gateway at
/bookingservice/** - Health:
GET /health - Additional routes depend on implementation (follow existing service patterns)
Open four terminals and start each service after installing dependencies.
Install dependencies:
# In each service directory
npm installStart services:
# API Gateway
node index.js
# Auth Service
npm start # runs nodemon src/index.js
# Flights and Search
node src/index.js
# Reminder Service
node src/index.js
# Air Ticket Booking Service
npm start # if nodemon config present; otherwise node src/index.jsSet headers when calling protected routes via Gateway:
# Example: calling booking service via gateway after signin
curl -H "x-access-token: <JWT_TOKEN>" http://localhost:3005/bookingservice/health- Security: JWT-based auth; input validation for critical endpoints; role-check endpoint (
/isAdmin). - Reliability: Rate limiting in gateway; structured error codes; health endpoints.
- Scalability: Microservices with independent ports; AMQP-based decoupling for async tasks.
- Observability: Request logging via
morganin gateway; Swagger documentation in Auth Service. - Database: Sequelize models and migrations for core domain entities; optional
DB_SYNC/SYNCmodes for iterative dev. - Messaging: Centralized message queue consumption in Reminder Service with pluggable handlers (
subscribeEvents).
The Airbourne platform has undergone comprehensive performance testing using k6 load testing framework with InfluxDB for metrics storage and Grafana for visualization. The testing suite includes four distinct test types to evaluate different aspects of system performance under various load conditions.
| Test Type | Purpose | Max Load | Duration | Key Focus |
|---|---|---|---|---|
| Load Test | Baseline performance | 100 VUs | ~5 min | Normal operation metrics |
| Soak Test | Long-term stability | 50 VUs | 30 min | Memory leaks, resource exhaustion |
| Stress Test | Breaking point analysis | 500 VUs | ~6 min | Maximum capacity limits |
| Spike Test | Burst traffic handling | 200 VUs | ~50 sec | Sudden load changes |
All tests follow a realistic user journey: Authentication → Flight Booking via API Gateway
// Example k6 configuration
export let options = {
stages: [
{ duration: "30s", target: 20 },
{ duration: "1m", target: 20 },
{ duration: "30s", target: 50 },
{ duration: "1m", target: 50 },
{ duration: "30s", target: 100 },
{ duration: "1m", target: 100 },
{ duration: "30s", target: 0 },
],
thresholds: {
"http_req_duration{operation:booking}": ["p(95)<2000", "p(99)<5000"],
"http_req_duration{operation:login}": ["p(95)<300"],
"http_req_failed{operation:booking}": ["rate<0.05"],
"checks{check:booking_success}": ["rate>0.95"],
},
};- Total Requests: 13,133
- Peak Throughput: ~42 requests/second
- Booking p95 Latency: 39.09ms (Target: <2000ms)
- Booking p99 Latency: 86.92ms (Target: <5000ms)
- Failure Rate: 0.00% (Target: <5%)
- Success Rate: 100.00%
- Total Requests: 93,841
- Sustained Throughput: ~38 requests/second
- Booking p95 Latency: 66.69ms (Target: <2000ms)
- Failure Rate: 0.00% over 30 minutes
- Stability: No performance degradation detected
- Total Requests: 45,465
- Peak Throughput: ~124 requests/second
- Booking p95 Latency: 1.25s (Target: <2000ms)
- Failure Rate: 0.00% even at 5x normal load
- Capacity: System stable up to 500 concurrent users
- Total Requests: 2,975
- Peak Throughput: ~52 requests/second
- Booking p95 Latency: 58.02ms (Target: <2000ms)
- Failure Rate: 0.00% during rapid load changes
- Elasticity: Perfect handling of sudden traffic bursts
-
Exceptional Baseline Performance: The system consistently delivers sub-100ms p95 latency for booking operations, far exceeding the 2000ms threshold.
-
Perfect Reliability: Across all test scenarios, the system maintained 0.00% failure rates, demonstrating robust error handling and fault tolerance.
-
High Scalability: Successfully handled 500 concurrent users (5x normal load) while maintaining acceptable performance levels.
-
Excellent Elasticity: Rapid load changes (0→200 VUs in 10 seconds) caused no performance degradation or failures.
-
Long-term Stability: 30-minute soak test showed no memory leaks or resource exhaustion issues.
# Install dependencies
npm --prefix tests install
# Run specific test
k6 run tests/booking_load_test.js
# Run with custom output
k6 run --out json=results.json tests/booking_load_test.js- Load Test Script:
tests/booking_load_test.js - Detailed Reports: Available in
docs/Load Test/,docs/Soak Test/,docs/Stress Test/,docs/Spike Test/ - Visual Dashboards: Grafana screenshots included in each test directory
- JSON Reports: Machine-readable results for further analysis
For comprehensive test setup, methodology, and detailed analysis, see the complete documentation in the docs/ directory.
- Use feature branches and conventional commits.
- Add/adjust Swagger docs when changing
Auth_serviceroutes. - Ensure migrations are created for DB schema changes.
ISC