vignette/docs/decisions/backend-node-transition.md
2026-06-28 12:18:20 +09:00

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.