A modern, event-driven microservices platform for airport operations. AirOps combines flight information, ground operations, team coordination, and account management into a single workflow-driven application.
AirOps is built as a collection of independently runnable services connected through RabbitMQ. The frontend is served through one reverse proxy, while the backend services communicate through internal Kubernetes services and REST endpoints.
Current status: Kubernetes manifests, ingress configuration, and deployment automation are still under development. The current application is a local development setup; ports are only relevant for local execution.
flowchart LR
User[User] -->|HTTPS| Proxy[Reverse Proxy<br/>Ingress / Gateway]
Proxy --> Frontend[Frontend<br/>React + Vite]
subgraph AuthLayer[Auth]
direction TB
Auth[Auth Service<br/>Fastify]
AuthDB[(Auth Database)]
end
subgraph FlightLayer[Flight]
direction TB
Flight[Flight Service<br/>Fastify]
FlightDB[(Flight Database)]
end
subgraph GroundOpsLayer[GroundOps]
direction TB
GroundOps[GroundOps Service<br/>Fastify]
GroundOpsDB[(GroundOps Database)]
end
subgraph Messaging[Messaging]
direction TB
RabbitMQ[RabbitMQ]
end
Frontend -->|/api/auth| Auth
Frontend -->|/api/arrivals| Flight
Frontend -->|/api/departures| Flight
Frontend -->|/api/tasks| GroundOps
Frontend -->|/api/turnarounds| GroundOps
Frontend -->|/api/teams| GroundOps
Auth --> AuthDB
Flight --> FlightDB
GroundOps --> GroundOpsDB
Auth <-->|Events| RabbitMQ
Flight <-->|Events| RabbitMQ
GroundOps <-->|Events| RabbitMQ
In Kubernetes, the backend service ports should not be exposed directly to end users. The reverse proxy should route public requests to the appropriate application service, such as / for the frontend and /api/... for backend APIs.
| Service | Local development port | Responsibility |
|---|---|---|
auth-service |
3005 | Authentication, sessions, account verification, password reset, and email delivery |
flight-service |
3000 | Flight arrivals, departures, and lifecycle updates |
groundops-service |
3001 | Ground operations, tasks, teams, and turnaround records |
frontend |
5173 | React and TanStack Router user interface |
RabbitMQ |
5672 | Event transport between services |
PostgreSQL |
5432 | Service persistence |
- Event-driven communication between services through RabbitMQ
- PostgreSQL persistence with Drizzle ORM
- Fastify-based REST APIs with Zod validation
- JWT and session-based authentication
- Email verification and password-reset workflows
- Flight and ground-operations business domains separated into independent services
- React frontend with TanStack Query and routing
- Bruno collection for API exploration and testing
.
├── auth-service/ # Authentication and identity service
├── flight-service/ # Flight operations API
├── groundops-service/ # Ground operations API
├── frontend/ # React application
├── Bruno/ # Bruno API collections and environment configuration
├── package.json # Root workspace scripts (if added later)
└── readme.md # Project documentation
Before starting the project, install:
- Node.js 20 or newer
- npm
- PostgreSQL
- RabbitMQ
- A mail provider or SMTP-compatible server for account emails
From the repository root, install the dependencies for each application:
cd auth-service && npm install
cd ../flight-service && npm install
cd ../groundops-service && npm install
cd ../frontend && npm installAlternatively, run the install commands in separate terminals or use a workspace manager if you add a root package manager configuration.
Create an .env file inside each backend service. The frontend uses localhost endpoints and does not currently require an environment file.
DATABASE_URL=postgresql://postgres:postgres@localhost:5432/auth
RABBITMQ_URL=amqp://localhost
SESSION_SECRET=replace-with-a-long-random-secret
JWT_SECRET=replace-with-another-long-random-secret
SMTP_HOST=smtp.example.com
SMTP_PORT=587
SMTP_USER=your-smtp-user
SMTP_PASS=your-smtp-password
SMTP_FROM="AirOps <no-reply@example.com>"
FRONTEND_URL=http://localhost:5173
NODE_ENV=developmentThe auth service currently validates DATABASE_URL, RABBITMQ_URL, SESSION_SECRET, JWT_SECRET, and FRONTEND_URL through its runtime configuration.
DATABASE_URL=postgresql://postgres:postgres@localhost:5432/flight
RABBITMQ_URL=amqp://localhost
NODE_ENV=developmentDATABASE_URL=postgresql://postgres:postgres@localhost:5432/groundops
RABBITMQ_URL=amqp://localhost
NODE_ENV=developmentThe database names and credentials above are examples. Update them to match your local PostgreSQL setup.
Create the PostgreSQL databases referenced by the environment files, then run the migrations from each service directory:
cd auth-service
npx drizzle-kit migrate
cd ../flight-service
npx drizzle-kit migrate
cd ../groundops-service
npx drizzle-kit migrateThe migration files are already included in each service's drizzle/ directory.
Ensure PostgreSQL and RabbitMQ are running before launching the services.
# PostgreSQL and RabbitMQ must be available locally
# Start the services in separate terminalsOpen separate terminals for each service:
# Auth service
cd auth-service
npm run dev
# Flight service
cd flight-service
npm run dev
# GroundOps service
cd groundops-service
npm run dev
# Frontend
cd frontend
npm run devFor local development, the services listen on the following ports:
- Auth service:
http://localhost:3005 - Flight service:
http://localhost:3000 - GroundOps service:
http://localhost:3001 - Frontend:
http://localhost:5173
Kubernetes deployment is the target deployment model, but no manifests, Helm charts, or ingress configuration are included yet.
Planned deployment architecture:
Internet
│
▼
Reverse Proxy / Ingress
│
├── / → frontend service
├── /api/auth → auth service
├── /api/arrivals → flight service
├── /api/departures → flight service
├── /api/tasks → groundops service
├── /api/turnarounds → groundops service
└── /api/teams → groundops service
The following work is still required:
- Kubernetes manifests for the frontend, auth, flight, and groundops services
- PostgreSQL and RabbitMQ deployment or managed external services
- ConfigMaps and Secrets for environment configuration
- Ingress or Gateway routing rules
- Health checks and readiness probes
- Container images and an image registry
- CI/CD automation for builds and deployments
- TLS and production domain configuration
The public URL should expose one entry point, while service-to-service communication remains internal to the cluster.
Base URL: http://localhost:3005/api/auth
| Method | Endpoint | Description |
|---|---|---|
POST |
/signup |
Create a user account |
POST |
/signin |
Sign in and receive auth tokens |
POST |
/refresh |
Refresh an access token |
GET |
/me |
Get the current authenticated user |
POST |
/verify-account |
Verify an account |
POST |
/forgot-password |
Request a password reset |
POST |
/reset-password |
Reset a password |
POST |
/logout |
Sign out the current user |
Base URL: http://localhost:3000/api
| Method | Endpoint | Description |
|---|---|---|
GET |
/arrivals |
List arrivals |
GET |
/arrivals/:id |
Get one arrival |
POST |
/arrivals |
Create an arrival |
PATCH |
/arrivals/:id |
Edit an arrival |
DELETE |
/arrivals/:id |
Delete an arrival |
POST |
/arrivals/:id/arrive |
Mark an arrival as arrived |
GET |
/departures |
List departures with query filters |
POST |
/departures |
Create a departure |
PATCH |
/departures/:id |
Edit a departure |
DELETE |
/departures/:id |
Delete a departure |
Base URL: http://localhost:3001/api
| Method | Endpoint | Description |
|---|---|---|
GET |
/tasks |
List tasks |
PATCH |
/tasks/:id/start |
Start a task |
GET |
/turnarounds |
List turnarounds |
GET |
/turnarounds/flight/:flightId |
Get turnarounds for a flight |
GET |
/teams |
List teams |
GET |
/teams/:id |
Get one team |
POST |
/teams |
Create a team |
POST |
/teams/:id/members |
Add a team member |
Run the tests for each service from its directory:
cd auth-service && npm test
cd ../flight-service && npm test
cd ../groundops-service && npm testThe Auth service also provides a coverage command:
cd auth-service
npm run test:coverageThe frontend includes a build and lint command:
cd frontend
npm run build
npm run lintThe repository includes a Bruno collection under Bruno/ for exploring the Auth, Flight, and GroundOps services. Import the collection into Bruno and select the FlightOPs environment to run the requests.
Bruno currently uses the local service ports. Once deployed through Kubernetes and the reverse proxy, update host URLs and authentication settings to use the public ingress endpoint.
- TypeScript
- React 19
- Fastify 5
- PostgreSQL
- Drizzle ORM
- RabbitMQ
- Zod
- TanStack Query
- TanStack Router
- Vitest
- Bruno
- Create a feature branch.
- Make focused changes with clear commit messages.
- Update tests for behavior changes.
- Run the relevant service tests and frontend checks.
- Open a pull request with a summary of the change and validation performed.
This project is licensed under the MIT License.