Files
beer_data/RUNBOOK.md
T
hermes 24cdd452c5
Build and Push Image / Build and push image (push) Canceled after 0s
Build and Push Image / Unit tests (push) Canceled after 17m41s
feat(ui): rebuild the interface with a proper design system
The old UI was two pages of raw pandas tables with no navigation, no styling
and no way to see a run's comments. This replaces it with a small,
testable application and a beer-themed design.

What changed
------------

Restructure
- The domain logic now lives in `brewing.py` as pure functions over plain
  data, with no Flask or Mongo dependency. The gravity maths, the ABV
  formula and the run-aggregation rules are unit-testable on their own.
- `app_factory.py` replaces the module-level app, and the routes move into
  blueprints under `views/`. A request-scoped Mongo repository is created per
  request and closed at teardown.
- `mongo/repository.py` replaces `build_db.py` / `query_db.py` / `get_conn.py`.
  Reading a document no longer requires a second query to fetch the fields.

Interface
- A dark, beer-themed design system: warm amber `#be7f39` on near-black, a
  condensed display face (Anton) for headings and Inter for body text. Both
  fonts and the chart library are vendored into `static/`, so the container
  needs no outbound network at runtime — the old templates pulled Bootstrap
  from a CDN.
- A real navigation bar, a login page, a brew-process page with a proper
  form, and a run-detail page listing every reading with its comment.
- The run summary tables now show the beer name and the latest comment, which
  the old pandas tables did not.
- Native form controls (checkbox, number spinners, date icon, scrollbars)
  are restyled for the dark theme.

Correctness
- The alcohol calculation now uses the standard homebrew formula,
  `(OG - FG) x 131.25`. The old code used `(max - min) / 7.36 + 0.5`, which is
  not a recognised brewing formula and overstated every result.
- Gravity points and decimal readings now convert correctly in both
  directions (`1039` <-> `1.039`).
- A run's display name resolves to the most-used label across its readings,
  because `beer_type` is stored per-reading and drifts across a run.
- Re-submitting a reading for the same run and day updates it in place
  rather than creating a duplicate.

Security / production
- The container ran the Werkzeug debugger with `FLASK_DEBUG=1`, exposing an
  interactive console on any unhandled error. It now runs waitress with
  debugging off.
- `SECRET_KEY` comes from the environment.
- The app secret is no longer a hard-coded string in source.

Housekeeping
- Removes the bokeh/duckdb/pandas dependency chain and the static file it
  generated at import time; removes the dead `add_user.py` and `test.py`.
- Splits `requirements.txt` (runtime) from `requirements-dev.txt` (tests).
- Adds a pytest suite (64 tests) and a `test` job to the CI workflow so the
  image is only built when the tests pass.
- Adds a README describing the data model and a RUNBOOK for the cluster side.

Data compatibility
------------------
The existing `beer_db.beer_data` documents are read as they are and are not
migrated or rewritten. No collection is dropped, and no document is modified
by this change other than through the explicit "record a reading" form, which
keeps the original `(date, beer_run_id)` uniqueness rule.
2026-11-09 10:21:44 +10:00

3.9 KiB
Raw Blame History

RUNBOOK — Brew Log (beer_data)

Operational notes for the beer namespace deployment.

What runs where

Namespace beer
Deployment beer-deployment (3 replicas)
Image git.aridgwayweb.com/armistace/beer-data:latest
Service beer-service, NodePort 30015 → container port 5000
Database MongoDB at 192.168.178.229, database beer_db
Secret beercred (registry pull credentials)

Access: http://<any-cluster-node>:30015/

The pods are pinned to archlinux-k3s-3 (.161) via nodeSelector.

Environment variables

Variable Value Source
MONGO_HOST 192.168.178.229 Deployment manifest
MONGO_USER root Deployment manifest
MONGO_PASS (see below) Deployment manifest
SECRET_KEY (see below) Deployment manifest — Flask session signing key
FLASK_ENV production Dockerfile
FLASK_DEBUG 0 Dockerfile

SECRET_KEY and MONGO_PASS must be set in the live Deployment. They are not committed to this repo — read them from the running cluster:

kubectl -n beer get deploy beer-deployment -o jsonpath='{.spec.template.spec.containers[0].env}'

The app refuses to start a usable session without a SECRET_KEY; the Dockerfile ships a placeholder so the container still boots if the variable is missing. Treat the placeholder as a misconfiguration.

Deploying

Pushing to master triggers .gitea/workflows/build_push.yml, which runs the test suite and then builds and pushes the image. The workflow does not currently deploy to the cluster — apply the manifests yourself:

kubectl -n beer rollout restart deployment/beer-deployment
kubectl -n beer rollout status deployment/beer-deployment --timeout=180s

Verify the deploy actually took

CI green and pods Ready do not prove the new code is running. Check the running digest against the registry:

# what the pod is running
kubectl -n beer get pod -l app=beer-data \
  -o jsonpath='{.items[0].status.containerStatuses[0].imageID}'

# what the registry has as :latest
curl -s -u "armistace:$REG_PASSWORD" -I \
  "https://git.aridgwayweb.com/v2/armistace/beer-data/manifests/latest" \
  -H "Accept: application/vnd.docker.distribution.manifest.v2+json" \
  | grep -i docker-content-digest

If they differ, the registry :latest is stale — re-run the build rather than re-applying the manifest.

Check the app is alive

kubectl -n beer get pods
kubectl -n beer logs deploy/beer-deployment --tail=50
curl -s http://<node>:30015/healthz     # -> {"status":"ok"}

/healthz never touches Mongo, so it proves the process is up but not that the database is reachable.

Data safety

The beer_db.beer_data collection holds the actual brewing records. There is no migration step and no schema version — documents are read as they are written, and every field is treated as optional.

To take a backup before any risky change:

mongodump --uri="mongodb://root:$MONGO_PASS@192.168.178.229:27017/beer_db" \
  --out=/tmp/beer_db_backup_$(date +%Y%m%d)

Common problems

The login page loads but nothing else does

The Mongo connection failed. Check the app logs for an auth error and confirm the credentials:

kubectl -n beer logs deploy/beer-deployment --tail=100 | grep -i mongo

A run shows a negative alcohol figure

That was the old formula ((max - min) / 7.36 + 0.5) applied to a run whose current gravity is above the assumed original gravity of 1012. Fixed in the current version: the standard (OG - FG) × 131.25 formula is used, and a run with no known OG shows a dash instead of a figure.

The chart on the run page is blank

The chart library is served from /static/js/chart.umd.js — it is vendored in the repo, not loaded from a CDN, so the container works with no outbound network. Check the browser console for a 404 on that path.