# Halo Bestie — Backend Fastify.js REST API serving both mobile apps and the internal control center. > See root `CLAUDE.md` for full project context and architectural decisions. ## Stack - **Runtime:** Node.js + Fastify.js - **Database:** PostgreSQL via GCP Cloud SQL - **Auth:** Firebase Auth JWT verification (no session, stateless) - **Payment:** Xendit - **Infra:** GCP Cloud Run ## Two Listeners ``` Public (0.0.0.0:3000) → client_app + mitra_app routes Internal (private IP:3001) → control_center routes only ``` Internal listener must never be exposed to the public internet. ## Route Namespacing ``` /api/client/... → client app routes /api/mitra/... → mitra app routes /api/shared/... → shared routes (e.g. auth, lookup) /internal/... → control center routes (internal listener only) ``` ## Auth Flow 1. Firebase Auth issues JWT token on mobile/web 2. Client sends JWT in `Authorization: Bearer ` header 3. Fastify verifies token using Firebase Admin SDK on every request 4. User record fetched from PostgreSQL by Firebase UID ## Key Conventions - All routes must be authenticated unless explicitly marked public - Internal routes have an additional role check (`role: admin`) - Use Fastify plugins for shared middleware (auth, error handling, logging) - Business logic lives in `services/` — never directly in route handlers