Skip to content
Back to top
View this page

# Dtypes Findings Migration (Incremental, Endoreg-Safe)

Last updated: 2026-06-03 Owner: reporting/frontend/backend

## Scope

Migrate findings read/write flows to a dtypes-driven API surface exposed by `lx_dtypes` under `/base_api/**` without breaking existing `endoreg_db` behavior mounted under `/api/**`.

In the current frontend, `dtypesApi()` defaults to `/dtypes-api/**` and `endoregApi()` defaults to `/endoreg-api/**`; those prefixes are reverse-proxy front doors for the underlying `/base_api/**` and `/api/**` services. Some legacy frontend call sites still hard-code `/api/**`.

## Current-State Inventory

### Uses dtypes today

- Frontend `findingsApi` supports backend mode flag `VITE_FINDINGS_BACKEND` (`endoreg`, `dtypes_read`, `dtypes`).

- In `dtypes_read` and `dtypes` modes, frontend findings reads use `/dtypes-api/examinations/{examination_id}/findings/`, `/dtypes-api/findings/{finding_id}/classifications/`, and `/dtypes-api/classifications/{classification_id}/choices/`.

- Those `/dtypes-api/**` routes proxy to `lx_dtypes` `/base_api/**` endpoints.

- In `dtypes` mode, patient finding CRUD uses `/dtypes-api/patient-findings/**` and validates finding/examination compatibility plus classification/choice consistency before persistence.

- The frontend default is now `dtypes` when `VITE_FINDINGS_BACKEND` is unset or invalid, so read and patient-finding write traffic defaults to `/dtypes-api/**`.

### Uses endoreg_db today

- `/api/**` remains the backend endoreg_db route namespace.

- The current frontend helper default for endoreg routes is `/endoreg-api/**`; older stores/components still call `/api/**` directly.

- Explicit `VITE_FINDINGS_BACKEND=endoreg` remains available as a rollback mode.

- In explicit `endoreg` mode, findings reads use: `/api/examinations/{examination_id}/findings/` and `/api/findings/{finding_id}/classifications/`.

- `findingsApi.getClassificationChoices()` still exposes the endoreg `/api/classifications/{classification_id}/choices/` route, but no current frontend source call site invokes it outside the service definition.

- Patient finding persistence is still on endoreg_db tables (`PatientFinding`, `PatientFindingClassification`) for `/base_api/patient-findings/**`.

- Patient finding row CRUD uses `/api/patient-findings/**` only in explicit `VITE_FINDINGS_BACKEND=endoreg` or `VITE_FINDINGS_BACKEND=dtypes_read` modes. In `endoreg` mode, classification replacement still goes through `/dtypes-api/patient-findings/{id}/classifications/`.

- Patient, gender, center, and patient-examination workflows still use endoreg_db routes from `patient.py` and `examination.py`.

- Report save flows still submit to `/api/patient-examination-reports/save-submission/`.

## Route Usage Audit (2026-06-03)

Question checked: are routes from these backend URL modules still used by the frontend?

- `/home/admin/endoreg-db/endoreg_db/urls/examination.py`

- `/home/admin/endoreg-db/endoreg_db/urls/classification.py`

- `/home/admin/endoreg-db/endoreg_db/urls/patient.py`

### `examination.py`

Backend route | Frontend status | Notes
--- | --- | ---
`/api/examinations/{examination_id}/findings/` | Used only in explicit endoreg mode | `findingsApi.getExaminationFindings()` now defaults to `/dtypes-api/examinations/{id}/findings/`; this route remains the `VITE_FINDINGS_BACKEND=endoreg` rollback path.
`/api/findings/{finding_id}/classifications/` | Used only in explicit endoreg mode | `findingsApi.getFindingClassifications()` now defaults to `/dtypes-api/findings/{id}/classifications/`; this route remains the `VITE_FINDINGS_BACKEND=endoreg` rollback path.
`/api/classifications/{classification_id}/choices/` | Exposed, not actively called | Implemented by `findingsApi.getClassificationChoices()`, but no frontend source call site invokes it today.
`/api/examinations/{exam_id}/indications/` | Not found in current frontend source | Reporting currently derives indication options from patient-examination detail and examination detail payloads instead.
`/api/indications/{indication_id}/choices/` | Not found in current frontend source | No current source call site found.
`/api/patient-examinations/create/` | Used | Used by reporting case setup and case resolution flows when creating a patient examination context.
`/api/patient-examinations/{pk}/` | Used | Used by the reporting shell and report editor for patient-examination detail hydration.
`/api/patient-examinations/list/` | Used | Used by reporting shell, case resolution, anonymization validation, and `patientExaminationStore`.
`/api/patient-examinations/{exam_id}/classifications/` | Not actively called | Present in `endpoints.ts`, but no current frontend source call site invokes it.
`/api/patient-examinations/{examination_id}/findings/` | Not actively called | Present in `endpoints.ts`, but current findings reads use `examinations/{id}/findings/` through `findingsApi`.
`/api/examinations/{exam_id}/interventions/` | Not found in current frontend source | No current source call site found.
`/api/examinations/{exam_id}/findings/{finding_id}/interventions/` | Not found in current frontend source | `SimpleExaminationForm.vue` has stale legacy calls under `examination/...`, but that component is not routed and the paths do not match this backend route.

### `classification.py`

`classification.py` currently contributes an empty `url_patterns` list; the NICE, PARIS, batch, and status paths are commented out. No frontend source call sites for `/api/classifications/nice/`, `/api/classifications/paris/`, `/api/classifications/batch/`, or `/api/classifications/status/{video_id}/` were found.

### `patient.py`

Backend route family | Frontend status | Notes
--- | --- | ---
`/api/patients/`, `/api/patients/{id}/` | Used | Used by `patientService`, `patientStore`, `PatientDashboard`, patient create/edit/detail components, and case-resolution patient creation.
`/api/patients/{id}/pseudonym/` | Used | Router-generated `PatientViewSet` action used by `patientService.generatePatientPseudonym()` and patient detail UI.
`/api/patients/{id}/check_deletion_safety/` | Used | Router-generated `PatientViewSet` action used by patient edit/detail deletion checks.
`/api/centers/` | Used | Used by patient lookup loading in `patientService`, `patientStore`, and patient forms.
`/api/genders/` | Used | Used by patient lookup loading in `patientService`, `patientStore`, and patient forms.
`/api/patient-findings/`, `/api/patient-findings/{id}/` | Used only in explicit endoreg or dtypes-read modes | Default row CRUD now uses `/dtypes-api/patient-findings/**`; these routes remain available for `VITE_FINDINGS_BACKEND=endoreg` and `VITE_FINDINGS_BACKEND=dtypes_read`.
`/api/check_pe_exist/{pk}/` | Used | Called by `patientExaminationStore.doesPatientExaminationExist()`.

### Legacy/Residual Notes

- `frontend/src/components/Examination/SimpleExaminationForm.vue` remains in source but is not registered in the current router. Its legacy `examination/...` endpoint strings do not match the active `examination.py` routes.

- `frontend/src/components/CaseGenerator/FindingGenerator*.vue` are legacy/demo components and are not reachable from the current router.

- `frontend/src/views/PatientAdder.vue` exists but is not currently routed.

- The current routed reporting flow is under `/reporting/**`; the legacy `/untersuchung` and `/report-generator` routes redirect to `/reporting/case-setup`.

## Phased Checklist

### Phase 0: Stabilize current findings flow (no behavior break)

- [x] Remove duplicate findings reactive reload triggers in `FindingsDetail` and `AddableFindingsDetail`.

- [x] Normalize findings network calls through a single service layer (`findingsApi`) for edited components/stores.

- [x] Keep endoreg-safe create contract: create finding first, then dedicated classifications update route.

- [x] Add structured error parsing (`required-finding`, `duplicate-finding`, `invalid-choice`, `invalid-finding`).

- Acceptance criteria:

  - No repeated watcher-trigger loops for single finding render.

  - 400 errors surface actionable code/message.

### Phase 1: Frontend findings API abstraction

- [x] Add `frontend/src/api/findingsApi.ts` + `.js`.

- [x] Add `VITE_FINDINGS_BACKEND` env typing.

- [x] Route `patientFindingStore` and `examinationStore` through `findingsApi`.

- [x] Route findings reads in the current reporting flow and stores through `findingsApi`.

- Acceptance criteria:

  - Component/store layer remains camelCase-compatible.

  - Backend switching does not require component-level endpoint changes.

### Phase 2: dtypes read endpoints (parallel, non-breaking)

- [x] `GET /base_api/examinations/{examination_id}/findings/`

- [x] `GET /base_api/findings/{finding_id}/classifications/`

- [x] `GET /base_api/classifications/{classification_id}/choices/`

- [x] Compatibility-oriented payload shape preserved (`id`, `name`, `required`, `choices`, legacy fields where needed).

- Acceptance criteria:

  - Frontend can run in `dtypes_read` mode without `/api` findings reads.

### Phase 3: dtypes write endpoints (endoreg-safe persistence)

- [x] `GET /base_api/patient-findings/?patient_examination=...`

- [x] `POST /base_api/patient-findings/`

- [x] `PATCH /base_api/patient-findings/{id}/`

- [x] `DELETE /base_api/patient-findings/{id}/`

- [x] `POST /base_api/patient-findings/{id}/classifications/`

- [x] Validation rules enforced before persistence.

- [x] Persistence remains endoreg_db tables for compatibility.

- Acceptance criteria:

  - `/api/**` remains fully operational with no contract regression.

### Phase 4: Cutover governance

- [x] Track migration in this document.

- [ ] Parity test suite green in CI for all findings endpoints/modes.

- [ ] Soak window complete (no regressions in configured period).

- [x] Flip default `VITE_FINDINGS_BACKEND` from `endoreg` to `dtypes` when the env var is unset or invalid.

## Compatibility Matrix

Endpoint / Area | Read/Write Source | Persistence | Rollout Status
--- | --- | --- | ---
`/api/examinations/*/findings/` or `/endoreg-api/examinations/*/findings/` | endoreg_db | endoreg_db | Explicit `endoreg` fallback read path
`/api/findings/*/classifications/` or `/endoreg-api/findings/*/classifications/` | endoreg_db | endoreg_db | Explicit `endoreg` fallback read path
`/api/classifications/*/choices/` or `/endoreg-api/classifications/*/choices/` | endoreg_db | endoreg_db | Exposed by service, no active frontend caller found
`/api/patient-findings/**` or `/endoreg-api/patient-findings/**` | endoreg_db | endoreg_db | Explicit `endoreg`/`dtypes_read` fallback row CRUD path
`/base_api/examinations/*/findings/` via `/dtypes-api/examinations/*/findings/` | dtypes KB | n/a | Implemented; default active path
`/base_api/findings/*/classifications/` via `/dtypes-api/findings/*/classifications/` | dtypes KB + db mapping | n/a | Implemented; default active path
`/base_api/classifications/*/choices/` via `/dtypes-api/classifications/*/choices/` | dtypes KB + db mapping | n/a | Implemented; no active frontend caller found
`/base_api/patient-findings/**` via `/dtypes-api/patient-findings/**` | dtypes-validated API | endoreg_db tables | Implemented; default active CRUD path
Frontend findings integration | `findingsApi` mode switch | n/a | Implemented (default `dtypes`)

## Decision Log

Date | Decision | Rationale | Owner
--- | --- | --- | ---
2026-03-09 | Keep `/api/**` as default while introducing `/base_api/**` in parallel. | Avoid production regressions during migration. | reporting/backend
2026-03-09 | Use `VITE_FINDINGS_BACKEND` feature mode (`endoreg`, `dtypes_read`, `dtypes`). | Enables incremental rollout and targeted testing. | frontend
2026-03-09 | Validate with dtypes but persist patient findings in existing endoreg tables for now. | Reduces schema/data migration risk while gaining validation parity. | backend
2026-03-09 | Keep explicit create-then-classification flow for endoreg-safe mode. | Matches existing behavior and prevents nested-write ambiguity. | frontend/backend
2026-03-09 | Pin pytest CI settings to a deterministic findings module (`report_template_examples`) when env var is unset. | Avoids environment-dependent `lx_knowledge_base` lookup failures in contract tests. | backend
2026-06-03 | Document frontend route usage against `examination.py`, `classification.py`, and `patient.py`. | Clarifies which endoreg routes remain part of the active frontend contract during dtypes migration. | frontend/backend
2026-06-03 | Default unset/invalid `VITE_FINDINGS_BACKEND` to `dtypes`. | Moves active findings read/write traffic to the dtypes API while preserving explicit `endoreg` rollback. | frontend

## Progress Log

Date | Reference | Status | Notes
--- | --- | --- | ---
2026-03-09 | Working tree changes in `lx_dtypes/django/api/main.py` and `test_findings_api.py` | Completed | Added `/base_api` findings read/write endpoints + validation + tests.
2026-03-09 | Working tree changes in `lx_dtypes/django_settings_ci_test.py`, `pyproject.toml`, and API error/deactivation handling | Completed | Fixed pytest execution path for backend contract tests; `pytest lx-data-models/lx_dtypes/django/api/tests/test_findings_api.py -q` passes locally from repo root.
2026-03-09 | Working tree changes in `frontend/src/api/findingsApi.*` | Completed | Added unified service layer and backend mode switch.
2026-03-09 | Working tree changes in findings components/stores/reporting views | Completed | Removed duplicate reload triggers and migrated key calls to `findingsApi`.
2026-03-09 | Frontend validation (`vue-tsc`) + targeted vitest (`findingsApi`, requirement crash guard) | Completed | Type-check and targeted migration tests pass locally.
2026-06-03 | Frontend route audit against endoreg URL modules | Completed | Confirmed active use of selected `examination.py` and `patient.py` routes; `classification.py` has no active routes.
2026-06-03 | `frontend/src/api/findingsApi.ts` default backend mode | Completed | Missing or invalid `VITE_FINDINGS_BACKEND` now resolves to `dtypes`; focused routing tests updated.

## Post-Cutover Follow-Up

Keep the `dtypes` default and consider retiring the explicit `endoreg` fallback only when all are true:

- Contract tests pass for `/base_api` read/write findings endpoints.

- Frontend mode tests pass for `endoreg`, `dtypes_read`, and `dtypes`.

- End-to-end create/update/delete/classification flows pass in staging.

- No agreed regression during soak period.