Build the three core feature UIs on top of the now-wired stores + corrected API
client from Phase 3a, turning the runnable shell into a usable app.
Dashboard (pages/Dashboard.tsx): AppBar (Normogen + username + logout) over an
MUI Tabs container (Medications | Health | Interactions), widened to lg. User
loads on mount (needed for profile_id in medication create).
MedicationManager (components/medication/): full CRUD.
* List of medication cards (name, dosage·frequency, active chip, instructions)
with edit/delete actions and an empty state.
* Create dialog: name/dosage/frequency/route(select)/instructions. profile_id
sourced from user.profile_id with a 'default' fallback (TODO: real profiles).
Payload typed to CreateMedicationRequest.
* Edit dialog (UpdateMedicationRequest shape) + delete confirm. Guards the
optional medication_id field.
HealthStats (components/health/): trend cards + chart + add + table.
* Trend summary cards from /health-stats/trends (avg/min/max + trend arrow).
* recharts LineChart of a selected stat type over measured_at, with a type
selector. Timestamp field is measured_at (not timestamp).
* Record dialog (stat_type/value/unit/measured_at/notes) + recent-readings table
(date-fns formatted).
InteractionsChecker (components/interactions/): multi-select medication names
(chips) -> POST /interactions/check. Results rendered as cards with a
SeverityChip, description, and disclaimer. Success/empty states.
Shared SeverityChip (components/common/): maps InteractionSeverity ->
MUI Chip color (severe=error, moderate=warning, mild=success, unknown=default).
Added @mui/icons-material@7 (pinned to match @mui/material 7; npm tried to grab
v9 which needs material ^9).
Verified: npm run build clean (TS5 strict), dev server serves the app + all
component modules transform. Solaria round-trip confirmed every contract the UIs
call: medication create/list (200), interactions warfarin+aspirin -> severe,
health-stat create (201).
The frontend was a Create React App scaffold (deprecated) where App.tsx was
still the stock 'Learn React' boilerplate — the implemented login/register pages
and stores were never mounted (no router). This swaps to Vite/TS5, fixes the
broken API client, wires a real router + dashboard, and lands on a runnable app.
Tooling swap (CRA -> Vite):
* Dropped react-scripts, web-vitals, @types/jest; added vite 6 + @vitejs/plugin-react
+ vitest 3 + jsdom; bumped typescript 4.9 -> 5.6, @types/node 16 -> 22.
* New vite.config.ts (with dev-server /api proxy -> backend, no CORS in dev),
tsconfig.json (target es2022, moduleResolution bundler, vite/client types),
tsconfig.node.json, vite-env.d.ts, root index.html.
* .env / .env.example (VITE_API_URL + VITE_API_TARGET). Renamed index.tsx ->
main.tsx (theme provider + CssBaseline). Deleted all CRA boilerplate
(App.css, logo.svg, App.test.tsx, reportWebVitals.ts, react-app-env.d.ts,
CRA index.html/logos/readme) + the orphaned empty web/src/ and mobile/ trees.
* node_modules 479MB -> 265MB; lockfile 695KB -> 198KB.
API client correctness (services/api.ts):
* Env var process.env.REACT_APP_* -> import.meta.env.VITE_*; dropped the
hardcoded http://solaria:8001/api (now /api via the dev proxy).
* Fixed contract mismatches: getCurrentUser /auth/me -> /users/me;
updateMedication PUT -> POST /:id; deleteMedication DELETE -> POST /:id/delete.
* Added refreshToken() (/auth/refresh) and server-side logout() (/auth/logout).
* Removed the /lab-results block (no backend route).
* 401 interceptor now attempts ONE silent refresh (deduped) before bouncing to
/login, instead of hard-redirecting on every 401.
* CreateMedicationRequest type now matches the backend (required route +
profile_id fields).
Router + dashboard:
* Real App.tsx with BrowserRouter: /login, /register (public), / (protected
Dashboard), catch-all -> /.
* New Dashboard.tsx: MUI AppBar + welcome card, loads the current user on mount,
logout button. The shell feature UIs get built into next.
* LoginPage/RegisterPage navigate to / (was /dashboard); store logout is now
async; AuthTokens type includes refresh_token.
* Minimal MUI theme.ts.
Verified: npm run build clean (TS5 strict + Vite), dev server serves the app +
proxies /api to the backend, vitest runs. Solaria round-trip confirmed all
corrected endpoints (/users/me 200, /auth/refresh 200, /auth/logout 204,
medication create 200).