Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Architecture

Health Tracker uses a single-crate workspace with feature-gated compilation for SSR + hydration.

System overview

┌─────────────────────────────────────────────────────────┐
│                    Health Tracker                       │
├─────────────────────────────────────────────────────────┤
│                                                         │
│  ┌─────────────┐    ┌──────────────┐    ┌────────────┐ │
│  │   Browser   │◀──▶│  Axum Server │◀──▶│   SQLite   │ │
│  │  (Leptos)   │    │  (SSR + API) │    │  (Storage) │ │
│  └─────────────┘    └──────────────┘    └────────────┘ │
│                                                         │
│  Feature gates:                                         │
│  - `hydrate` → WASM client bundle                       │
│  - `ssr`     → Server binary                            │
│  - `cli`     → Admin CLI binary (stub)                  │
│  - `gen`     → Code generator binary (stub)             │
└─────────────────────────────────────────────────────────┘

Crate structure

src/
├── main.rs              # Axum server entry (ssr feature only)
├── lib.rs               # WASM hydration entry (hydrate feature only)
├── app.rs               # Shared root component + router (both features)
├── api/                 # Leptos #[server] functions (client-server RPC)
│   └── mod.rs           # upsert_daily_log, get_daily_log, get_daily_logs_for_month
├── routes/              # Page components
│   ├── index.rs         # Landing page (/)
│   ├── dashboard.rs     # Dashboard placeholder (/dashboard)
│   ├── track.rs         # Daily log form (/track?date=YYYY-MM-DD)
│   ├── login.rs         # Auth stub (/login)
│   ├── register.rs      # Auth stub (/register)
│   └── docs.rs          # Docs page (/docs)
├── components/          # Reusable UI
│   ├── header.rs        # Navigation bar
│   ├── footer.rs        # Footer with external links
│   ├── daily_log_form.rs # Full daily log form (4 sections)
│   └── layouts/
│       └── main_layout.rs # Header + Outlet + Footer wrapper
├── server/              # SSR-only (#[cfg(feature = "ssr")])
│   ├── db.rs            # AppState with SqlitePool
│   ├── api/
│   │   └── daily_logs.rs # REST CRUD handlers + OpenAPI
│   └── queries/
│       └── daily_logs.rs # sqlx queries + 7 unit tests
├── shared/              # Framework-agnostic domain types
│   ├── models.rs        # DailyLog, DailyLogSummary, ExerciseIntensity
│   └── validation.rs    # DailyLogForm with #[derive(Validate)]
├── styles/
│   └── main.scss        # SCSS styles
└── bin/
    ├── ht-cli.rs        # Admin CLI (cli feature) — stub
    └── ht-gen.rs        # Code generator (gen feature) — stub

Feature gating

FeatureTargetPurposeStatus
hydratecdylib (WASM)Client-side hydrationComplete
ssrbin (native)Server-side rendering + APIComplete
clibin (native)Admin CLI binaryStub
genbin (native)Code generator binaryStub

Both hydrate and ssr share app.rs, routes/, components/, and shared/ for consistency.

SSR + Hydration flow

  1. Server renders the initial HTML via shell() in main.rs
  2. Browser receives HTML + WASM bundle
  3. Hydration takes over in lib.rs, attaching reactivity to existing DOM
  4. Client-side navigation via leptos_router for subsequent pages

Data flow

The app has two parallel data paths:

Path 1: Leptos #[server] functions (UI-driven)

User Action → Form Signal → #[server] function → sqlx query → Database → Response → UI Update

Used by the DailyLogForm component for interactive form submission and loading existing data. Defined in src/api/mod.rs:

  • upsert_daily_log(form) — create or update a log
  • get_daily_log(date) — fetch a single log
  • get_daily_logs_for_month(year, month) — calendar summaries

Path 2: REST API (external/CLI-driven)

HTTP Request → Axum handler → sqlx query → Database → JSON Response

Standard HTTP endpoints for CLI tools and external consumers. Swagger UI at /api/docs. Defined in src/server/api/:

  • GET /api/daily_logs — list all logs (optional ?start_date= and ?end_date=)
  • POST /api/daily_logs — create or update a log
  • GET /api/daily_logs/{date} — get single log by date
  • DELETE /api/daily_logs/{date} — delete log by date

Module dependency rules

routes      → components, api (#[server] functions), shared
components  → shared (never server, never routes, never api)
server      → shared (never components, never routes)
api         → shared, server (queries)
shared      → (nothing)

This ensures clean separation: domain types have no framework dependencies, server code knows nothing about UI, and components are framework-agnostic where possible.

Database

Single SQLite table daily_logs with columns for body metrics (weight, waist), nutrition (protein, calories), wellness (meditation, exercise + intensity), and sleep. Migrations run automatically on server startup via sqlx.

Dependencies

CratePurpose
leptosReactive UI framework
leptos_routerClient-side routing
leptos_metaDocument head management
leptos_axumSSR integration
axumHTTP server
sqlx (sqlite, chrono, runtime-tokio-rustls)Database queries
validator (derive)Input validation
utoipa + utoipa-swagger-uiOpenAPI spec + Swagger UI
tokioAsync runtime
tracingObservability