๐ŸฅฆNdiro
Chapter 13 of 13

Changing the site: a working method

You wanted three abilities: modify the site, review changes to it, and suggest improvements. This closing chapter is the working method for all three.

The loop for making a change

  1. Read CLAUDE.md first. It's the repo's contract with its contributors (human or AI): the module map, the data model, the security invariants, the gotchas. Most bad diffs violate something already written there.
  2. Find the seam. The codebase marks its intended extension points โ€” e.g. offering another trackable micro-nutrient is one new NUTRIENT_CATALOG entry in config.py; everything downstream is key-generic. A change that fits a seam touches one or two files; needing five is a signal to re-read.
  3. Run the stub tests before and after. All of them โ€” each is its own script, so loop: for t in tests/test_m*.py tests/probe_cross_user.py; do python "$t" || break; done. They need no AWS and no network and run in seconds. They drive the real routes against fake boto3 tables (tests/fakes.py) โ€” a minicluster in miniature. tests/testkit.py must be imported first in any new test; it installs the fakes before the app imports.
  4. Check both themes and a phone width for any UI change โ€” devtools has a device-width toggle, and the CSS chapter showed the one-attribute theme flip.

The review checklist

Chapter by chapter, compressed into one table. A "yes" isn't automatically a rejection โ€” it's where to spend your attention:

AskBecause (chapter)
Does innerHTML or |safe get anything that isn't a source literal?XSS (Jinja, JS, security)
Does any identifier in a URL, query, or form decide whose data is read or written?Tenant isolation (API, security)
Does a new GET change application data? Is a new write route missing its guard decorator or rate limit?CSRF, auth (HTTP, backend, identity)
Does a public page or a log line gain a config value or user content?Invariants #8, #11 (security)
New in-process state (cache, counter, thread) โ€” does it survive the "what if --workers 2?" question, and is the bet commented?Single-worker design (backend)
Numbers crossing the DynamoDB edge: Decimal(str(x)) in, float() out?Decimal discipline (storage)
New fetch call: does it handle 401, non-OK, and network failure โ€” the three-rung ladder?The error contract (API)
New input: validated to canonical form server-side, not just constrained in the HTML?Validation (HTML, API)
Hard-coded color instead of a var(--token)? A button that's a styled div?Theming, a11y (HTML, CSS)
Does the diff update the matching stub test โ€” or need a new one?The tests are the spec

Graded exercises

Each is small, safe, and touches one new layer. Do them in a branch; the tests tell you if you broke a promise.

  1. CSS only: change --gold in both theme blocks of base.html and watch it propagate. Then find one hard-coded color anywhere and tokenize it.
  2. Template only: add your own section to privacy.html. No route change needed โ€” why not?
  3. Template + JS: add a third tile to the log page's today-summary (say, largest meal today). The data is already in the /api/meals payload; you need one element in the HTML and a few lines in renderDays.
  4. Full stack: add a field to the /api/meals response (e.g. a per-day meal count) in _meals_payload, render it, and extend the relevant test. Decimal rules apply.
  5. Backend + test first: write a failing check in a copy of test_m9_status.py asserting /status shows something it doesn't yet โ€” then make it pass. You'll touch a route, a template, and the leak check.
  6. Boss level: add a nutrient to NUTRIENT_CATALOG in config.py, and trace why that one dict entry is enough โ€” through resolve_nutrient, the settings page, the form field name, the AI schema, and the chart. That trace is the architecture of the app.

Suggesting improvements

The strongest improvement proposals here name the trade they're reversing. This codebase declines things on purpose โ€” GSIs, caching layers, multiple workers, frameworks, a real queue โ€” and writes down why. "Add Redis so we can run two workers" is only an improvement once ~100 users isn't the scale anymore; "the meals cache from the old tracker" is explicitly warned against in CLAUDE.md. Meanwhile some gaps are real and acknowledged: the ephemeral spool, memory-only rate-limit state across restarts, no CSP header yet. An improvement pitch that says "this trade was right at PoC scale and here's the trigger that changes it" will land; one that pattern-matches "small app is missing big-app machinery" won't.

Where to go deeper

One last pointer, in the spirit of the whole book: this guide is itself part of the site โ€” a closed chapter registry and two routes in app.py (grep for dzidza), templates extending _dzidza.html, a leak-checked public page like any other, with a stub test of its own. Reading how the book you just finished is served makes a fitting final exercise. Dzidza zvakanaka โ€” happy learning.

๐Ÿ