43 lines
2 KiB
Markdown
43 lines
2 KiB
Markdown
# 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.
|