Production-style TypeScript/Express API for managing Gundam combat operations:
- pilots
- mobile suits
- weapons
- missions
- admin claim management
The API uses Firebase Admin (Auth + Firestore), request validation with Joi, centralized error handling, route-level authorization, Prometheus metrics, and OpenAPI documentation.
- Node.js + TypeScript
- Express 5
- Firebase Admin SDK (Authentication + Firestore)
- Joi validation
- Helmet security headers
- CORS middleware
- Swagger/OpenAPI (
swagger-jsdoc,swagger-ui-express) - Jest + Supertest
- Prometheus client metrics
This project is functionally complete for the capstone scope and includes:
- CRUD APIs for pilots, mobile suits, weapons, and missions
- Firebase bearer token authentication
- role-based authorization middleware
- admin endpoint for custom claims management
- generated OpenAPI docs and static docs output
- metrics and health endpoints
- Base URL (local):
http://localhost:3010 - Swagger UI:
http://localhost:3010/api-docs - Health check:
GET /api/v1/health - Metrics:
GET /metrics
Create a .env file based on .env.example.
cp .env.example .envThe following variables are required (from .env.example):
| Variable | Description |
|---|---|
NODE_ENV |
Runtime environment (development or production) |
PORT |
API server port |
FIREBASE_PROJECT_ID |
Firebase project ID |
FIREBASE_PRIVATE_KEY |
Firebase service account private key |
FIREBASE_CLIENT_EMAIL |
Firebase service account client email |
SWAGGER_SERVER_URL |
URL used for generated docs context |
CLOUDFLARE_TUNNEL_TOKEN |
Token if exposing API through Cloudflare tunnel |
npm installDevelopment:
npm startBuild:
npm run buildProduction run (after build):
npm run start:prodThis repository includes a docker-compose.yml with:
api(Node/TypeScript API)cloudflared(Cloudflare Tunnel agent)prometheusgrafana
- Docker + Docker Compose installed
- A Cloudflare account
- A domain managed in Cloudflare
- A Cloudflare Tunnel token
Copy and edit the environment file:
cp .env.example .envSet all required Firebase values and set:
NODE_ENV=productionPORT=3010SWAGGER_SERVER_URLto your public API URL (for examplehttps://api.yourdomain.com)CLOUDFLARE_TUNNEL_TOKENto your Cloudflare tunnel token
In Cloudflare Zero Trust:
- Create a tunnel (Cloudflared connector).
- Add a Public Hostname (for example
api.yourdomain.com). - Set the service target to
http://api:3010(the API service name and port from Docker Compose). - Copy the generated tunnel token into
.envasCLOUDFLARE_TUNNEL_TOKEN.
docker compose up -d --buildCheck running services:
docker compose psView logs if needed:
docker compose logs -f api cloudflared- Local API:
http://localhost:3010/api/v1/health - Public API (through tunnel):
https://api.yourdomain.com/api/v1/health - Local Swagger UI:
http://localhost:3010/api-docs - Metrics:
http://localhost:3010/metrics - Prometheus:
http://localhost:9090 - Grafana:
http://localhost:3001
Stop:
docker compose downRestart:
docker compose restart| Script | Purpose |
|---|---|
npm start |
Run API with ts-node |
npm run build |
Compile TypeScript to dist/ |
npm run start:prod |
Run compiled output |
npm test |
Run Jest tests |
npm run test:watch |
Run tests in watch mode |
npm run test:coverage |
Run tests with coverage |
npm run generate-docs |
Generate openapi.json and static docs at docs/index.html |
All domain routes are protected by Firebase bearer token auth and role checks.
Implemented roles used by middleware:
admincommanderpilot
Role access by resource:
| Route Group | Read | Create/Update/Delete |
|---|---|---|
/api/v1/mobile-suits |
admin, commander, pilot |
admin, commander |
/api/v1/weapons |
list: admin, commander, pilot; by-id: admin, commander |
admin, commander |
/api/v1/missions |
admin, commander, pilot |
admin, commander |
/api/v1/pilots |
admin, commander |
create/delete: admin; update: admin, commander |
/api/v1/admin/setCustomClaims |
admin |
admin |
POST /api/v1/admin/setCustomClaims
POST /api/v1/pilotsGET /api/v1/pilotsGET /api/v1/pilots/:idPUT /api/v1/pilots/:idDELETE /api/v1/pilots/:id
POST /api/v1/mobile-suitsGET /api/v1/mobile-suitsGET /api/v1/mobile-suits/:idPUT /api/v1/mobile-suits/:idDELETE /api/v1/mobile-suits/:id
POST /api/v1/weaponsGET /api/v1/weaponsGET /api/v1/weapons/:idPUT /api/v1/weapons/:idDELETE /api/v1/weapons/:id
POST /api/v1/missionsGET /api/v1/missionsGET /api/v1/missions/:idPUT /api/v1/missions/:idDELETE /api/v1/missions/:id
Regenerate OpenAPI and static docs:
npm run generate-docsGenerated outputs:
openapi.jsondocs/index.html
Run all tests:
npm testCoverage:
npm run test:coverage