Skip to content

api-server — CONTEXT.md

NestJS 11 backend with Prisma 6 ORM, PostgreSQL + PostGIS, Redis, JWT/OTP auth, and Socket.IO real-time. For global conventions (branding, Angular patterns, GIS overview), see /CLAUDE.md.


1. Module Structure Pattern

Each feature module lives in src/<feature>/ and contains:

<feature>/
├── <feature>.module.ts
├── <feature>.controller.ts
├── <feature>.service.ts
├── dto/
│   ├── create-<feature>.dto.ts
│   └── update-<feature>.dto.ts
└── guards/ (if feature-specific)

Feature Modules (16 total)

Module Controllers Services Notes
analytics analytics analytics Dashboard summary stats
auth auth auth JWT + OTP login (admin, driver, passenger)
boardings boardings boardings QR check-in/out, earnings, trip boardings
common twilio Shared Twilio SMS/WhatsApp service
config Config files only (CORS, etc.)
drivers drivers drivers CRUD + bank accounts + assignment history
lines lines, passenger-stops lines Line/route CRUD + public stops + GTFS
location location location GPS logging, proximity checks, monitoring
passenger gtfs GTFS data import/query
payments otp, recharge, withdraw otp, recharge, withdraw, libelula Full payment stack (Libelula gateway)
prisma prisma Database client wrapper
schedules schedules schedules, dispatcher Trip scheduling + auto-dispatch
tenant tenant tenant Multi-tenant CRUD
trips trips, passenger-trips trips Trip lifecycle + driver/passenger views
users users users Admin user creation + passenger listing
vehicles vehicles vehicles Vehicle CRUD + assignment history

2. Auth Flow

  • JWT strategy: JwtStrategy.validate() returns { userId, email, role, tenantId }
  • OTP login: requestOtp → saves to DB; skips Twilio when TWILIO_FORCE_REAL_SEND=false
  • Dev bypass: OTP_MASTER_KEY=000000 fires before driver status guard
  • Token payload: includes driverId via generateTokenResponse()
  • Downstream services: look up driver by userId (JWT sub), not email
  • Passenger auth: separate POST /auth/passenger/request-otp and verify-otp endpoints; auto-creates Passenger record

Role Enum

enum Role {
  SUPER_ADMIN
  ADMIN
  DRIVER
  PASSENGER
}

3. Environment Loading

ConfigModule.forRoot({
  envFilePath: [`.env.${process.env.NODE_ENV}`, '.env'],
  isGlobal: true,
})

.env.development takes priority in dev; .env is the fallback.

Key Environment Variables

Variable Purpose
DATABASE_URL PostgreSQL connection string
JWT_SECRET Token signing secret
OTP_MASTER_KEY Dev bypass OTP (set 000000 in dev only)
TWILIO_FORCE_REAL_SEND false in dev to skip SMS
TWILIO_ACCOUNT_SID / TWILIO_AUTH_TOKEN Twilio credentials
TWILIO_SMS_FROM / TWILIO_WHATSAPP_FROM Send-from numbers
TWILIO_OTP_TEMPLATE_ID WhatsApp template for login OTP
LIBELULA_API_URL / LIBELULA_APPKEY Libelula payment gateway
LIBELULA_CALLBACK_ALLOWED_IPS IP allowlist for payment callbacks
API_URL Backend URL injected into frontend builds
NODE_ENV development or production
ADDITIONAL_ORIGINS Extra CORS origins (comma-separated)
ANALYTICS_KEY Shared secret for POST /analytics/events (x-analytics-key header). If unset, the endpoint accepts all keys (dev). Must match analyticsKey in each client app's environment.ts.

Never commit .env files — only .env.example is allowed in version control.


4. Database Schema (Prisma)

Database name: transit_flow Provider: postgresql with PostGIS extension

Core Models

Model Key Fields Notes
Tenant name, domain, email, phoneNumber, status, isActive Top-level org (municipality/syndicate)
Line name, colorHex, polyline (String?), tenantId polyline = Google Encoded Polyline for visual track
Route name, lineId, status Operational path; has ordered Checkpoints
Checkpoint name, latitude, longitude, location (PostGIS), radiusMeters, orderIndex, routeId location = geography(Point,4326)
Stop name, latitude, longitude, lineId, orderIndex Passenger-visible stops
User email, password, role, phoneNumber, otpCode, roles[] Auth entity; roles[] for multi-role
Driver firstName, lastName, ci, licenseNumber, status, balance, tenantId, userId balance = Decimal(10,2) earnings
Vehicle plate, model, year, capacity, status, tenantId M:N with Line; M:N with Driver via VehicleAssignment
VehicleAssignment driverId, vehicleId, isCurrent Joins drivers to vehicles
Trip vehicleId, driverId, lineId, routeId, status, actualCheckpoints (Json) actualCheckpoints = historical log, never remove
TripSchedule lineId, driverId, vehicleId, startTime (HH:MM), daysOfWeek (bitmask) Recurring schedule
VehicleLocationLog vehicleId, lat, lng Raw GPS log

Payment/Boarding Models

Model Key Fields Notes
Passenger userId, qrToken, balance balance = Decimal(10,2) wallet
Boarding tripId, passengerId, scanFlow, scannedAt, checkedOutAt Unique per trip+passenger
BalanceTransfer boardingId, passengerId, driverId, amount One per boarding
OtpRecord userId, otpHash, operationType, expiresAt, used Payment OTP (separate from auth)
Transaction passengerId, type, amount, status, libelulaTransactionId Libelula top-ups
BankAccount driverId, accountNumber, bankName, isDefault Driver saved accounts
Withdrawal driverId, amount, bankAccount, status Pending/processed/rejected

Critical GIS Rules

  • Line.polyline (String?) = Google Encoded Polyline — visual geometry only
  • Checkpoint.location = PostGIS geography(Point,4326) — proximity queries via ST_DWithin
  • Route.points was removed (2026-04-12) — geometry lives on Line.polyline only
  • OSRM road snapping is called from the browser, not the backend

5. Key Endpoints (Quick Reference)

Prefix Controller Key Endpoints
/auth auth POST login, POST request-otp, POST verify-otp, POST passenger/*, GET me
/tenants tenant CRUD + GET :id/lines, POST :id/lines
/lines lines CRUD + PATCH :id/polyline, route CRUD, vehicle assignment
/trips trips POST self-dispatch, POST :id/start, POST :id/finish, GET my-trips
/drivers drivers CRUD + GET me, bank account CRUD
/vehicles vehicles CRUD + GET available
/boardings boardings GET my-qr, POST :tripId/checkin, POST :tripId/scan-passenger, earnings
/location location POST (log GPS), GET monitoring
/payments/* otp, recharge, withdraw OTP flow, Libelula recharge, driver withdrawal
/passenger/* passenger-stops GET stops/search, GET stops/nearby, GTFS routes/stops
/analytics analytics GET summary
/schedules schedules CRUD + deactivate

6. Dev Workflow

cd apps/api-server
npm install
npm run start:dev          # NestJS watch mode
npx prisma studio          # DB GUI at :5555
npx prisma migrate dev     # Run migrations
npx prisma db push         # Push schema without migration history
npx prisma generate        # Regenerate Prisma client after schema changes

7. Key File Paths

What Path
Prisma schema prisma/schema.prisma
App module src/app.module.ts
Auth module src/auth/
Lines module src/lines/
Trips module src/trips/
Location service src/location/location.service.ts
Boardings module src/boardings/
Payments module src/payments/
GTFS service src/passenger/gtfs.service.ts
Twilio service src/common/twilio.service.ts
CORS config src/config/cors.config.ts
JWT strategy src/auth/jwt.strategy.ts

Last updated: 2026-06-05.