# Backend Node.js Transition Decision Date: 2026-06-28 ## Decision Vignette keeps the current Python/FastAPI backend for the near-term delivery path, but the replacement target for new replaceable backend infrastructure is Node.js. This is not a full rewrite approval. The migration path is contract-first and strangler-style: - Keep the FastAPI core while delivery-critical behavior is still being closed. - Move cross-runtime boundaries into explicit contracts before extracting services. - Prefer Node.js for new replaceable services or gateway implementations once the contract is stable. - Do not weaken existing fail-closed security, persona catalog, DB/RLS, audit, or PII masking behavior to make migration easier. ## Rationale The project proposal and team capability point toward Node.js, but a direct Python-to-Node rewrite during the current schedule would add delivery and staffing risk. The safer path is to make Python replaceable by pinning the wire contracts first. ## First Boundary The first implementation boundary is the engine gateway contract: - `POST /v1/generate` - `POST /v1/stream` - SSE events: `token`, `done`, `error` - request/response models owned by `apps/api/app/contracts/engine_gateway.py` Both the FastAPI engine client and the current Python engine gateway import this same contract. A future Node.js gateway must preserve these shapes. ## Invariants - `/personas` normal state remains `source:"database", degraded:false`; `seed_fallback` is not normal. - Browser credentials and BFF session behavior stay unchanged. - RBAC, RLS, audit logging, and PII masking stay fail-closed. - OpenAPI generated frontend contracts stay current. - Existing ports and local/prod startup paths stay compatible until a service is deliberately replaced. ## Next Refactor Candidates 1. Split persona HTTP DTOs and mappers from `routes/personas.py` while preserving OpenAPI schema names. 2. Split learner/review session read-model assembly from `routes/sessions.py`. 3. Leave `admin.py` mapper cleanup for later because RBAC, audit, and RLS blast radius is larger.