omnidiag / docs /code_cleanup_report.md
yahyoha's picture
docs: add v2.0 roadmap, API docs, and .env.example
3e4503d
|
Raw
History Blame Contribute Delete
6.85 kB
# Code Cleanup Report
**Branch:** `feature/omni-platform-final`
**Date:** 2026-06-28
**Scope:** Full codebase — frontend (React/JSX) + backend (Python/FastAPI)
---
## Summary
Two analysis agents scanned the frontend and backend in parallel. All confirmed findings were then applied. A total of **19 files** were modified across both layers.
---
## Frontend Changes
### 1. Extracted shared `ValueBadge` component and `SLIDER_CLASS` constant
**File:** `frontend/src/components/SchemaFieldFactory.jsx`
The live-value badge (blue pill showing the current slider value) and the range `<input type="range">` Tailwind class string were each copy-pasted verbatim between `SliderField` and `NumberField`.
**Fix:** Extracted a local `ValueBadge({ value })` component and a `SLIDER_CLASS` string constant at the top of the file. Both field types now reference them.
---
### 2. Merged duplicate patient-reset `useEffect`s
**File:** `frontend/src/components/ClinicalEmrMode.jsx`
Two `useEffect`s both fired on `selectedDisease` change:
- The first reset result/SHAP/error state and set `selectedPatient` from `patients.length`.
- The second also called `getPatientsForDisease` and set `selectedPatient`, silently overwriting the first.
**Fix:** Merged into one `useEffect` on `[selectedDisease]` that calls `getPatientsForDisease`, sets the patient, and clears result state.
---
### 3. Removed redundant schema cache from `DiseaseContext`
**File:** `frontend/src/context/DiseaseContext.jsx`
The context maintained its own `schemaCache` state, a `preFetchSchemas` function (called eagerly on app load for all diseases), and a `getSchemaForDisease` method. None of these were consumed anywhere outside the context itself — `useDiseaseSchema.js` already handles schema fetching and caching independently via its own module-level `Map`.
**Fix:** Removed `schemaCache` state, `preFetchSchemas`, and `getSchemaForDisease` (~40 lines). The context now only manages disease selection and the available diseases list.
---
### 4. Moved `@keyframes` animations out of JSX
**Files:** `frontend/src/components/FormSkeleton.jsx`, `frontend/src/components/VariableScalesModal.jsx`
**Target:** `frontend/src/index.css`
Both components injected `<style>` tags with `@keyframes` blocks directly into the render output, re-injecting them into the document on every mount.
**Fix:** Moved `shimmer` and `slideInRight` animations to `index.css`. Components reference the class names only.
---
### 5. Removed dead exports
All of the following were exported but never imported anywhere in the codebase:
| File | Removed export |
|---|---|
| `components/ErrorBoundary.jsx` | `PredictionErrorBoundary` |
| `utils/schemaToZod.js` | `validateFormData` |
| `utils/medicalDictionary.js` | `isKnownMedicalTerm`, `getFullDictionary` |
| `mockPatients.js` | `getAvailablePatientDiseases` |
| `hooks/useDiseaseSchema.js` | `clearSchemaCache` |
| `components/SchemaFieldFactory.jsx` | `componentIcons` (defined, never referenced) |
---
## Backend Changes
### 6. Removed unused imports
| File | Removed |
|---|---|
| `backend/model_loader.py` | `import sys` |
| `backend/ensemble_loader.py` | `import sys`, `Tuple` and `Callable` from `typing` |
| `backend/ensemble_loader.py` | `import joblib as _joblib` inside a `for` loop body (top-level `joblib` already imported) |
---
### 7. Promoted deferred imports and loggers to module level
**File:** `backend/main.py`
Two route handlers (`explain_disease`, `counterfactuals_disease`) each executed `import traceback as _tb` and `_log = logging.getLogger(...)` on **every request**, deferring what should be module-level setup.
**Fix:**
- Added `import traceback` at the top of the file.
- Added `_explain_log` and `_cf_log` as module-level loggers alongside the existing `log`.
- Removed the per-request imports and local `_log` assignments from both handlers.
---
### 8. Extracted `_validate_patient_input` helper
**File:** `backend/main.py`
The schema-validation block appeared identically in all three clinical route handlers (`predict_disease`, `explain_disease`, `counterfactuals_disease`):
```python
schema = get_schema_for_disease(disease)
if schema:
validated = schema(**patient)
patient_data = validated.model_dump()
else:
patient_data = patient
```
**Fix:** Extracted into `_validate_patient_input(disease, patient) -> dict` placed above the route definitions. All three handlers now call it with one line.
---
### 9. Extracted `extract_token_from_request` utility
**File:** `backend/auth/jwt.py` (new function)
**Callers updated:** `backend/rate_limit.py`, `backend/middleware/audit.py`
The cookie-then-header token extraction pattern was duplicated in both files (and had diverged slightly — different variable names, one used `str | None`, the other `Optional[str]`):
```python
token = request.cookies.get("access_token")
if not token:
auth = request.headers.get("Authorization", "")
if auth.startswith("Bearer "):
token = auth[7:]
```
**Fix:** Added `extract_token_from_request(request: Request) -> Optional[str]` to `auth/jwt.py`. Both callers import and use it.
---
### 10. Replaced `print()` with structured logging in `router.py`
**File:** `backend/router.py`
`_load_all_configs()` and `_create_loader()` used raw `print()` with emoji characters for status messages while the rest of the backend uses structured `logging`. This meant disease registration events were invisible to the configured log handler.
**Fix:** Added `log = logging.getLogger("omnidiag.router")` and replaced all 7 `print()` calls with `log.info()`, `log.warning()`, and `log.error()`.
---
### 11. Upgraded Pydantic v1 `class Config` to v2 `model_config`
**File:** `backend/schemas.py`
`HeartDiseaseInput` and `DiabetesInput` both used the Pydantic v1 inner-class style:
```python
class Config:
json_schema_extra = { ... }
```
The rest of the backend (auth schemas, patient schemas) correctly uses Pydantic v2 style. Added `ConfigDict` to the import and replaced both with:
```python
model_config = ConfigDict(json_schema_extra={ ... })
```
---
## What Was Not Changed
The following duplication exists in `backend/model_loader.py` and `backend/ensemble_loader.py` and was identified but intentionally left alone:
| Duplication | Reason deferred |
|---|---|
| `_apply_preprocessors` — identical in both loaders | Extracting a `BaseModelLoader` carries regression risk without tests |
| `_get_feature_engineer` / `_engineer_features` — copy-pasted | Same as above |
| `preprocessors` property directory-scan loop | Same as above |
| XGBoost `base_score` monkey-patch | The two implementations have already diverged in detail; merging requires careful testing |
These should be addressed as a dedicated refactor with integration tests in place.