CurseTechnique/learning/walkthrough.md

3.6 KiB

CurseTechnique Codebase Walkthrough

This document is a practical map of the app, aimed at learning-oriented Rust reading.

1. High-level architecture

The app uses a lightweight 4-layer layout:

  1. src/main.rs - startup and route wiring
  2. src/handlers.rs - HTTP handlers and input validation
  3. src/db.rs - SQLite queries and data structs
  4. src/views.rs - HTML rendering (server-side string rendering)

The goal is to keep each file focused and easy to read without adding extra frameworks.

2. Request flow (end-to-end)

Example: open GET /day/2026-02-07

  1. Route is defined in src/main.rs and points to handlers::show_day_entries.
  2. show_day_entries in src/handlers.rs validates the date path param.
  3. It calls db::fetch_day_entries in src/db.rs to load rows from SQLite.
  4. It passes those rows to views::render_day_page in src/views.rs.
  5. The rendered HTML is returned to the browser.

Example: submit add-entry form POST /day/{date}/add

  1. Route points to handlers::create_entry.
  2. Handler validates date and form fields (name, calories).
  3. Handler calls db::insert_entry.
  4. Handler redirects back to /day/{date}.

3. File-by-file reading guide

src/main.rs

Read this file first. It is intentionally small.

  • Creates data directory and opens SQLite DB.
  • Calls DB init/seed helpers.
  • Builds Axum router.
  • Starts Tokio TCP listener.

If you ever wonder "where is this endpoint connected?", this file is the source of truth.

src/handlers.rs

This is the HTTP boundary.

Core concepts here:

  • AppState holds shared DB connection behind Arc<Mutex<Connection>>.
  • Each handler receives typed route/form data.
  • Handlers do three steps:
    1. Validate input
    2. Call DB function
    3. Return HTML or redirect

Useful helper functions:

  • validate_date ensures YYYY-MM-DD format.
  • parse_entry_form_fields validates name + calories.
  • month_bounds computes first/next month boundaries.

src/db.rs

This file contains all SQL.

Data structs:

  • FoodEntry represents one row.
  • DaySummary represents aggregated values for calendar cards.

Functions are split by intent:

  • Setup: init_db, seed_db_if_empty
  • Reads: fetch_month_summaries, fetch_day_entries
  • Writes: insert_entry, update_entry, delete_entry

If behavior looks wrong (totals, filtering, ordering), start debugging here.

src/views.rs

This file builds HTML strings for SSR.

  • render_calendar_page renders /.
  • render_day_page renders /day/{date}.
  • Small helpers reduce clutter:
    • render_day_card
    • render_entry_rows
    • entry_count_label
    • escape_html

Important: escape_html is used when rendering user-provided food names.

4. Key Rust patterns used

  • Result<T, E> for explicit error handling.
  • ? operator to propagate errors.
  • Arc<Mutex<_>> for shared mutable state across async handlers.
  • Simple structs over tuple-heavy values for readability (DaySummary).
  • Module organization (mod db; mod handlers; mod views;) to keep files focused.

5. How to add a feature safely

Use this checklist:

  1. Add/adjust SQL function in db.rs.
  2. Add or update handler logic in handlers.rs.
  3. Update route wiring in main.rs if endpoint path changes.
  4. Update HTML output/forms in views.rs.
  5. Run:
    • cargo fmt
    • cargo check

6. Suggested beginner exercises

  1. Add a "notes" text column to food entries.
  2. Show count of entries in the day header.
  3. Add confirmation step on delete (simple query param or separate page).
  4. Add a helper in handlers to prevent editing future dates.

These exercises touch all 4 layers and are great practice for understanding the whole flow.