diff --git a/docs/decisions/backend-node-transition.md b/docs/decisions/backend-node-transition.md index 55251c3..38173db 100644 --- a/docs/decisions/backend-node-transition.md +++ b/docs/decisions/backend-node-transition.md @@ -46,6 +46,7 @@ Provider pass-through sentinels such as `data: [DONE]` are ignored compatibility - Browser credentials and BFF session behavior stay unchanged. - Browser-facing `/sessions/{id}/stream` SSE stays a separate app contract; the engine gateway stream uses JSON token payloads. - Browser-facing session list/dashboard/detail/review/share response DTOs stay stable across the Python route and any future Node read API. +- Browser-facing persona catalog/review/draft/source/evidence response DTOs stay stable across the Python route and any future Node read API. - 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. @@ -58,6 +59,14 @@ The second internal boundary is the browser-facing session read model. This preserves the current FastAPI delivery path while making a future Node.js read API mirror one module's browser contract instead of re-deriving response shapes from mixed route code. Hidden/evaluator-only turn filtering, saved worksheet precedence, teacher read-only review status, and public share sanitization remain invariants. +## Third Boundary + +The third internal boundary is the browser-facing persona read model. + +`apps/api/app/persona_read_model.py` now owns persona catalog, review queue, draft payload/detail, source document, generation evidence, and draft generation response DTOs plus deterministic mappers. `apps/api/app/routes/personas.py` keeps route decorators, auth and teacher/admin gates, repository calls, RAG source registration, LLM draft generation, and HTTP error mapping. + +This keeps `/personas` fail-closed semantics stable: normal catalog entries remain `source:"database", degraded:false`, seed fallback remains degraded, and OpenAPI schema names such as `PersonaSummary`, `PersonaReviewSummary`, `PersonaDraftPayload`, and `PersonaDraftDetail` stay unchanged. + ## Evidence - `python -B -m py_compile app/contracts/engine_gateway.py app/engine_client.py app/services/orchestrator.py engine_gateway/gateway.py engine_gateway/test_gateway_model.py app/test_orchestrator_masking.py app/test_session_turn_persistence.py` @@ -67,11 +76,12 @@ This preserves the current FastAPI delivery path while making a future Node.js r - `apps/api/engine_gateway/golden/engine_gateway_contract.v1.json` and `apps/api/engine_gateway/golden/engine_gateway_schema.v1.json` validated by `engine_gateway/test_gateway_model.py` - `python -B -m py_compile app/session_read_model.py app/routes/sessions.py` - `python -B -m pytest -p no:cacheprovider app/test_session_turn_persistence.py app/test_evaluation_persistence.py app/test_session_share.py app/test_learner_dashboard.py app/test_rbac_idor.py app/test_teacher_dashboard.py -q` — 48 passed +- `python -B -m py_compile app/persona_read_model.py app/routes/personas.py` +- `python -B -m pytest -p no:cacheprovider app/test_persona_review.py -q` — 33 passed - `npm run check:api-types` - `npm run typecheck` ## Next Refactor Candidates 1. Add live Node.js gateway endpoint conformance once a Node gateway implementation exists; the artifact runner is now in place. -2. Split persona HTTP DTOs and mappers from `routes/personas.py` while preserving OpenAPI schema names. -3. Leave `admin.py` mapper cleanup for later because RBAC, audit, and RLS blast radius is larger. +2. Leave `admin.py` mapper cleanup for later because RBAC, audit, and RLS blast radius is larger.