# kaizer-1/hrv-stress-wearable architecture

> Architecture diagram of the GitHub repository kaizer-1/hrv-stress-wearable, generated by GitDiagram from its file tree, README and a sample of source files (last updated 2026-06-27). It is an AI-made overview: check details against the source.

- Interactive diagram: https://gitdiagram.com/kaizer-1/hrv-stress-wearable
- Repository: https://github.com/kaizer-1/hrv-stress-wearable

## Overview

1. **Repository shape**
   This is a split-stack system: a Python package for ML + backend services, a React/Vite frontend, plus scripts, data artifacts, and reports. The main architectural boundary is between the **Python inference service** and the **browser dashboard**.

2. **Primary runtime path**
   The live system is a pipeline from **sensor source → feature streamer → inference engine → WebSocket broadcast + SQLite persistence → React UI**. The backend is the hub; the frontend is a consumer of both REST APIs and a streaming WebSocket.

3. **Hardware / input boundary**
   The backend does not depend on a single physical device. It uses a `SensorSource` abstraction with three implementations: **serial** for the ESP32 wearable, **CSV replay** for offline/demo use, and **TCP** for a future networked sensor feed. This makes hardware a replaceable ingress layer rather than part of the core service.

4. **Signal processing and ML subsystem**
   Under `src/stress_detection/features`, raw 1 Hz multi-sensor samples are cleaned, windowed, and converted into a **22-feature vector** on a 30-second window with 5-second stride. That feature pipeline is shared by training and serving, which is important for train/serve parity. The model layer is a **scikit-learn SVM pipeline** with scaling, probability output, and smoothing in the serving path.

5. **Training / offline data pipeline**
   The `scripts/` directory and `src/stress_detection/io`, `features`, `models` packages form the offline ML workflow: load raw CSVs, clean them, generate features, train SVMs, and export `joblib` models. Model artifacts in `data/models/` and evaluation outputs in `reports/` are the outputs of that pipeline, not runtime dependencies.

6. **Inference and session state**
   `src/stress_detection/service/inference` turns streaming windows into predictions, applies calibration offsets when enabled, and smooths stress probability over time. `src/stress_detection/service/sessions` persists user/session/sample/prediction/calibration data into SQLite. This is where ephemeral stream processing becomes durable session history.

7. **Auth and user scoping**
   The service includes a JWT-based auth subsystem under `service/auth`. Authentication is used to scope REST data and gate the WebSocket stream. That means user identity is a cross-cutting concern for both persistence and live streaming, not just a login screen feature.

8. **WebSocket live delivery**
   Live updates are pushed through `service/ws`: the backend broadcasts sample, feature, and prediction messages to connected clients. This is the real-time boundary between backend computation and frontend visualization. The stream is server-driven; the UI mainly subscribes and renders state.

9. **Frontend application structure**
   The React app is organized by route and domain: live monitoring, history, calibration, breathing, settings, auth, and session detail. State is split between local UI components, Zustand stores, and API hooks. The frontend consumes REST for session/auth/calibration operations and WebSocket for live telemetry.

10. **Demo and hardware-free operation**
   Demo mode is a first-class subsystem, not a mock-only afterthought. The backend can replay canned session data, and the frontend can switch into a visible demo state. This allows the full architecture to run without the ESP32 or sensors, which is important for testing, demos, and development.

11. **Configuration and deployment surface**
   Runtime behavior is driven by YAML config under `config/`, especially input source selection and service settings. `scripts/run_service.py` is the backend entrypoint, and the project is designed around a local host deployment with the API and WebSocket on the Python service and the UI on the Vite dev server.

12. **Evidence and quality subsystem**
   The repo includes substantial test coverage across backend pytest suites, frontend Vitest tests, and Playwright end-to-end flows. `docs/` and `reports/` capture architecture, API contracts, hardware protocol, and model results. These artifacts are part of the project’s architecture because they document and validate the live system boundaries and data contracts.

13. **Key architectural constraint**
   The model is trained on a combined dataset because the project hardware’s GSR values differ from WESAD’s units. That domain-shift issue directly influences the deployed model choice and explains why the system includes both public-dataset artifacts and project-specific recording artifacts in the repository.

14. **What to draw in a diagram**
   The most accurate diagram should show: ESP32/sensor inputs or CSV replay feeding the Python service; internal stages for cleaning/windowing/features/inference/smoothing; SQLite as persistence; JWT auth as a gate on REST and WebSocket; and the React dashboard as the live/history/calibration UI consuming those APIs. The offline training scripts and model/report artifacts should appear as a separate build-time pipeline, not part of the runtime request path.

Main entry points: [`frontend/src/api/client.ts`](https://github.com/kaizer-1/hrv-stress-wearable/blob/main/frontend/src/api/client.ts) (API client), [`scripts/train_combined.py`](https://github.com/kaizer-1/hrv-stress-wearable/blob/main/scripts/train_combined.py) (Training scripts), [`src/stress_detection/service/inference/engine.py`](https://github.com/kaizer-1/hrv-stress-wearable/blob/main/src/stress_detection/service/inference/engine.py) (Inference engine), [`src/stress_detection/service/sessions/manager.py`](https://github.com/kaizer-1/hrv-stress-wearable/blob/main/src/stress_detection/service/sessions/manager.py) (Session store)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_runtime_backend["Python service"]
  node_service_app["Service app<br/>FastAPI runtime<br/>[app.py]"]
  node_runtime_config["Runtime config<br/>config loader<br/>[config.py]"]
  node_sensor_sources["Sensor sources<br/>ingress adapters"]
  node_feature_streamer["Feature stream<br/>windowing pipeline<br/>[streamer.py]"]
  node_inference_engine["Inference engine<br/>ml runtime<br/>[engine.py]"]
  node_session_manager[("Session store<br/>sqlite persistence<br/>[manager.py]")]
  node_auth_subsystem["JWT auth<br/>auth boundary"]
  node_ws_broadcaster["WebSocket hub<br/>live delivery<br/>[broadcaster.py]"]
  node_demo_routes["Demo API<br/>demo mode<br/>[routes.py]"]
end

subgraph group_runtime_frontend["React UI"]
  node_frontend_app["Dashboard app<br/>Vite React<br/>[App.tsx]"]
  node_api_layer["API client<br/>REST client<br/>[client.ts]"]
  node_live_stream_hooks["Live hooks<br/>state + ws<br/>[useLiveStream.ts]"]
  node_route_views["Route views<br/>screens<br/>[Live.tsx]"]
end

subgraph group_offline_ml["Offline ML"]
  node_feature_pipeline["Feature pipeline<br/>shared features<br/>[pipeline.py]"]
  node_feature_extractors["Extractors<br/>feature calc<br/>[extractors.py]"]
  node_svm_model["SVM model<br/>scikit-learn pipeline<br/>[svm.py]"]
  node_training_scripts["Training scripts<br/>offline pipeline<br/>[train_combined.py]"]
end

subgraph group_artifacts["Data artifacts"]
  node_raw_data["Raw data<br/>csv inputs"]
  node_model_artifacts["Model files<br/>joblib outputs"]
  node_session_db[("Session DB<br/>sqlite file<br/>[sessions.sqlite]")]
  node_report_outputs["Reports<br/>evaluation outputs"]
end

node_runtime_config -->|"configures"| node_service_app
node_service_app -->|"opens"| node_sensor_sources
node_sensor_sources -->|"streams samples"| node_feature_streamer
node_feature_streamer -->|"uses"| node_feature_pipeline
node_feature_pipeline -->|"computes"| node_feature_extractors
node_feature_streamer -->|"emits windows"| node_inference_engine
node_inference_engine -->|"scores with"| node_svm_model
node_inference_engine -->|"persists"| node_session_manager
node_session_manager -->|"stores in"| node_session_db
node_inference_engine -->|"publishes"| node_ws_broadcaster
node_auth_subsystem -->|"scopes data"| node_session_manager
node_auth_subsystem -->|"gates"| node_ws_broadcaster
node_demo_routes -.->|"replays"| node_sensor_sources
node_training_scripts -->|"loads"| node_raw_data
node_training_scripts -->|"trains on"| node_feature_pipeline
node_training_scripts -->|"exports"| node_svm_model
node_training_scripts -->|"evaluates to"| node_report_outputs
node_svm_model -->|"saved as"| node_model_artifacts
node_frontend_app -->|"calls"| node_api_layer
node_frontend_app -->|"subscribes via"| node_live_stream_hooks
node_live_stream_hooks -->|"connects to"| node_ws_broadcaster
node_route_views -->|"renders"| node_frontend_app
node_route_views -->|"fetches"| node_api_layer
node_route_views -->|"shows live data"| node_live_stream_hooks
node_api_layer -->|"authenticates against"| node_auth_subsystem
node_api_layer -->|"reads history"| node_session_manager
node_api_layer -->|"controls demo"| node_demo_routes

click node_service_app "https://github.com/kaizer-1/hrv-stress-wearable/blob/main/src/stress_detection/service/app.py"
click node_runtime_config "https://github.com/kaizer-1/hrv-stress-wearable/blob/main/src/stress_detection/service/config.py"
click node_sensor_sources "https://github.com/kaizer-1/hrv-stress-wearable/tree/main/src/stress_detection/service/sources"
click node_feature_streamer "https://github.com/kaizer-1/hrv-stress-wearable/blob/main/src/stress_detection/service/features/streamer.py"
click node_inference_engine "https://github.com/kaizer-1/hrv-stress-wearable/blob/main/src/stress_detection/service/inference/engine.py"
click node_session_manager "https://github.com/kaizer-1/hrv-stress-wearable/blob/main/src/stress_detection/service/sessions/manager.py"
click node_auth_subsystem "https://github.com/kaizer-1/hrv-stress-wearable/tree/main/src/stress_detection/service/auth"
click node_ws_broadcaster "https://github.com/kaizer-1/hrv-stress-wearable/blob/main/src/stress_detection/service/ws/broadcaster.py"
click node_demo_routes "https://github.com/kaizer-1/hrv-stress-wearable/blob/main/src/stress_detection/service/demo/routes.py"
click node_feature_pipeline "https://github.com/kaizer-1/hrv-stress-wearable/blob/main/src/stress_detection/features/pipeline.py"
click node_feature_extractors "https://github.com/kaizer-1/hrv-stress-wearable/blob/main/src/stress_detection/features/extractors.py"
click node_svm_model "https://github.com/kaizer-1/hrv-stress-wearable/blob/main/src/stress_detection/models/svm.py"
click node_training_scripts "https://github.com/kaizer-1/hrv-stress-wearable/blob/main/scripts/train_combined.py"
click node_raw_data "https://github.com/kaizer-1/hrv-stress-wearable/tree/main/data/raw"
click node_model_artifacts "https://github.com/kaizer-1/hrv-stress-wearable/tree/main/data/models"
click node_session_db "https://github.com/kaizer-1/hrv-stress-wearable/blob/main/data/sessions.sqlite"
click node_report_outputs "https://github.com/kaizer-1/hrv-stress-wearable/tree/main/reports"
click node_frontend_app "https://github.com/kaizer-1/hrv-stress-wearable/blob/main/frontend/src/App.tsx"
click node_api_layer "https://github.com/kaizer-1/hrv-stress-wearable/blob/main/frontend/src/api/client.ts"
click node_live_stream_hooks "https://github.com/kaizer-1/hrv-stress-wearable/blob/main/frontend/src/hooks/useLiveStream.ts"
click node_route_views "https://github.com/kaizer-1/hrv-stress-wearable/blob/main/frontend/src/routes/Live.tsx"

classDef toneNeutral fill:#f8fafc,stroke:#334155,stroke-width:1.5px,color:#0f172a
classDef toneBlue fill:#dbeafe,stroke:#2563eb,stroke-width:1.5px,color:#172554
classDef toneAmber fill:#fef3c7,stroke:#d97706,stroke-width:1.5px,color:#78350f
classDef toneMint fill:#dcfce7,stroke:#16a34a,stroke-width:1.5px,color:#14532d
classDef toneRose fill:#ffe4e6,stroke:#e11d48,stroke-width:1.5px,color:#881337
classDef toneIndigo fill:#e0e7ff,stroke:#4f46e5,stroke-width:1.5px,color:#312e81
classDef toneTeal fill:#ccfbf1,stroke:#0f766e,stroke-width:1.5px,color:#134e4a
class node_service_app,node_runtime_config,node_sensor_sources,node_feature_streamer,node_inference_engine,node_session_manager,node_auth_subsystem,node_ws_broadcaster,node_demo_routes toneBlue
class node_frontend_app,node_api_layer,node_live_stream_hooks,node_route_views toneAmber
class node_feature_pipeline,node_feature_extractors,node_svm_model,node_training_scripts toneMint
class node_raw_data,node_model_artifacts,node_session_db,node_report_outputs toneRose
```

## Components

### Python service

Online backend runtime, streaming inference, persistence, and auth.

- [Service app](https://github.com/kaizer-1/hrv-stress-wearable/blob/main/src/stress_detection/service/app.py): FastAPI runtime · Assembles the backend runtime, routes, and lifecycle wiring. · `src/stress_detection/service/app.py`
- [Runtime config](https://github.com/kaizer-1/hrv-stress-wearable/blob/main/src/stress_detection/service/config.py): config loader · Loads YAML/runtime settings for source selection, service options, and deployment behavior. · `src/stress_detection/service/config.py`
- [Sensor sources](https://github.com/kaizer-1/hrv-stress-wearable/tree/main/src/stress_detection/service/sources): ingress adapters · Replaceable input boundary for serial, CSV replay, and TCP sensor feeds. · `src/stress_detection/service/sources`
- [Feature stream](https://github.com/kaizer-1/hrv-stress-wearable/blob/main/src/stress_detection/service/features/streamer.py): windowing pipeline · Buffers raw samples, windows them, and emits feature-ready records. · `src/stress_detection/service/features/streamer.py`
- [Inference engine](https://github.com/kaizer-1/hrv-stress-wearable/blob/main/src/stress_detection/service/inference/engine.py): ml runtime · Scores streamed windows, applies calibration, and smooths stress probabilities. · `src/stress_detection/service/inference/engine.py`
- [Session store](https://github.com/kaizer-1/hrv-stress-wearable/blob/main/src/stress_detection/service/sessions/manager.py): sqlite persistence · Persists users, sessions, samples, predictions, and calibration history into SQLite. · `src/stress_detection/service/sessions/manager.py`
- [JWT auth](https://github.com/kaizer-1/hrv-stress-wearable/tree/main/src/stress_detection/service/auth): auth boundary · Authenticates users and scopes REST and live-stream access. · `src/stress_detection/service/auth`
- [WebSocket hub](https://github.com/kaizer-1/hrv-stress-wearable/blob/main/src/stress_detection/service/ws/broadcaster.py): live delivery · Broadcasts sample, feature, and prediction messages to connected clients. · `src/stress_detection/service/ws/broadcaster.py`
- [Demo API](https://github.com/kaizer-1/hrv-stress-wearable/blob/main/src/stress_detection/service/demo/routes.py): demo mode · Serves canned-session and demo-state behavior for hardware-free operation. · `src/stress_detection/service/demo/routes.py`

### React UI

Browser dashboard consuming REST and WebSocket data.

- [Dashboard app](https://github.com/kaizer-1/hrv-stress-wearable/blob/main/frontend/src/App.tsx): Vite React · Browser UI shell and route composition for monitoring and control. · `frontend/src/App.tsx`
- [API client](https://github.com/kaizer-1/hrv-stress-wearable/blob/main/frontend/src/api/client.ts): REST client · Typed REST helpers for auth, sessions, calibration, and demo control. · `frontend/src/api/client.ts`
- [Live hooks](https://github.com/kaizer-1/hrv-stress-wearable/blob/main/frontend/src/hooks/useLiveStream.ts): state + ws · Hooks and stores that subscribe to live telemetry and connection state. · `frontend/src/hooks/useLiveStream.ts`
- [Route views](https://github.com/kaizer-1/hrv-stress-wearable/blob/main/frontend/src/routes/Live.tsx): screens · Live, history, calibration, breathing, settings, and auth pages. · `frontend/src/routes/Live.tsx`

### Offline ML

Training, feature generation, evaluation, and exported model artifacts.

- [Feature pipeline](https://github.com/kaizer-1/hrv-stress-wearable/blob/main/src/stress_detection/features/pipeline.py): shared features · Shared cleaning, windowing, and feature extraction used by training and serving. · `src/stress_detection/features/pipeline.py`
- [Extractors](https://github.com/kaizer-1/hrv-stress-wearable/blob/main/src/stress_detection/features/extractors.py): feature calc · Computes the 22-feature vector from cleaned sensor windows. · `src/stress_detection/features/extractors.py`
- [SVM model](https://github.com/kaizer-1/hrv-stress-wearable/blob/main/src/stress_detection/models/svm.py): scikit-learn pipeline · Scaled probabilistic SVM used for stress classification. · `src/stress_detection/models/svm.py`
- [Training scripts](https://github.com/kaizer-1/hrv-stress-wearable/blob/main/scripts/train_combined.py): offline pipeline · Builds interim datasets, trains models, checks transfer, and exports artifacts. · `scripts/train_combined.py`

### Data artifacts

Sample recordings, canned demo sessions, trained models, and stored session data.

- [Raw data](https://github.com/kaizer-1/hrv-stress-wearable/tree/main/data/raw): csv inputs · Project recordings and WESAD-derived CSV sources used for cleaning and feature generation. · `data/raw`
- [Model files](https://github.com/kaizer-1/hrv-stress-wearable/tree/main/data/models): joblib outputs · Exported trained models consumed by the backend inference path. · `data/models`
- [Session DB](https://github.com/kaizer-1/hrv-stress-wearable/blob/main/data/sessions.sqlite): sqlite file · On-disk SQLite database holding durable session history. · `data/sessions.sqlite`
- [Reports](https://github.com/kaizer-1/hrv-stress-wearable/tree/main/reports): evaluation outputs · Metrics, figures, and narrative outputs from training and validation runs. · `reports`

## Connections

- Runtime config → Service app: configures · Runtime settings feed service startup and source selection.
- Service app → Sensor sources: opens · Backend instantiates the selected sensor ingress adapter.
- Sensor sources → Feature stream: streams samples · Raw 1 Hz sensor samples are forwarded into feature buffering.
- Feature stream → Feature pipeline: uses · Serving reuses the shared cleaning/windowing/feature logic.
- Feature pipeline → Extractors: computes · Extractors produce the window-level feature vector.
- Feature stream → Inference engine: emits windows · Feature windows become inference-ready inputs.
- Inference engine → SVM model: scores with · The serving path loads and evaluates the trained SVM pipeline.
- Inference engine → Session store: persists · Predictions and calibration state are written to session storage.
- Session store → Session DB: stores in · SQLite is the durable backing store for session history.
- Inference engine → WebSocket hub: publishes · Live predictions and telemetry are sent to the WebSocket layer.
- JWT auth → Session store: scopes data · Identity determines which sessions and records are accessible.
- JWT auth → WebSocket hub: gates · Authenticated users are allowed into the live stream.
- Demo API → Sensor sources: replays · Demo mode can substitute canned or replayed sensor input.
- Training scripts → Raw data: loads · Offline build scripts ingest project and public-dataset CSVs.
- Training scripts → Feature pipeline: trains on · Training uses the same feature pipeline as serving for parity.
- Training scripts → SVM model: exports · Scripts produce versioned joblib SVM artifacts.
- Training scripts → Reports: evaluates to · Metrics and figures are written as validation outputs.
- SVM model → Model files: saved as · Trained classifiers are stored under the model artifact directory.
- Dashboard app → API client: calls · UI screens use REST helpers for auth, sessions, calibration, and demo control.
- Dashboard app → Live hooks: subscribes via · The dashboard consumes live telemetry and connection state through hooks.
- Live hooks → WebSocket hub: connects to · Frontend listens to the backend WebSocket broadcast stream.
- Route views → Dashboard app: renders · Route-level screens are mounted inside the app shell.
- Route views → API client: fetches · Screens request session, auth, calibration, and demo data via REST.
- Route views → Live hooks: shows live data · Live and history-oriented views render telemetry state from stream hooks.
- API client → JWT auth: authenticates against · Login, register, and token usage flow through the backend auth routes.
- API client → Session store: reads history · Session and calibration endpoints are backed by the SQLite store.
- API client → Demo API: controls demo · Frontend toggles canned demo behavior through the demo API.
