Release: one log page, grouped dishes, live search (#1)
Structure - Kirjaa and Historia are one page. They were two views of the same thing — every history row already linked into the logger, and the logger had a day switcher. Two tabs instead of three. Also closed a gap: on an already-logged day there was no way to swap to a different dish, only to re-pick its sides. - Ruoat → Ruuat, label and route. - The catalog has a structure. It had no top-level headings at all — the mains simply began with "Liha". Both halves now carry a heading and a count, categories are visibly subordinate, and the add/edit forms collapse instead of filling the screen before any content. Finding things - Dishes grouped by category on both screens, Sekalaiset for multi-category ones. Derived from the stored set, not a fifth category, so one Tortillat still covers all four for the §8.1 suggester later. - Live search on both lists, 250 ms after typing stops. Both remain plain GET forms, so they still filter with JavaScript off. - History is paged 30 days at a time — it previously rendered every day back to the first entry, forever. Correctness - Future meals refused. The picker offered them and ?pvm= accepted them. - today() wasn't midnight, so it never equalled a date parsed from ?pvm= — after saving, the card read "la 5.9. kirjattu" instead of "Tänään kirjattu". - Deletes ask first, for dishes and logged meals. The meal is the more destructive: a dish is only soft-deleted. - DB open failures name the path and uid, instead of unable to open database file (14). Visual - Category icons replace colour dots — steak, drumstick, fish, leaf, quartered circle. - Row actions are a pencil and a bin; the header has a surface. Housekeeping - Datastar SDK dropped — one JSON decode was pulling in four modules including an HTTP compression stack. Five lines replace it. - Release policy documented: main protected, releases arrive as PRs. Co-authored-by: Esa Kataja <[email protected]> Reviewed-on: #1
This commit was merged in pull request #1.
This commit is contained in:
@@ -17,18 +17,29 @@ weeks of real history to weight against.
|
||||
|
||||
Working:
|
||||
|
||||
- **Kirjaa** — log a dinner: pick a dish, tick sides, save. Dishes are sized
|
||||
by how often they are eaten. Edit or delete the day's entry.
|
||||
- **Historia** — every day back to the first entry, with unlogged days shown
|
||||
as explicit gaps.
|
||||
- **Ruoat** — add, edit and delete mains and sides, or import a whole bundle
|
||||
by paste or file upload. Deletes are soft, so old log entries keep showing
|
||||
the dish they used.
|
||||
- **Kirjaa** — log a dinner: pick a dish, tick sides, save. Dishes are ordered
|
||||
and sized by how often they are eaten, so the likely answer is the biggest
|
||||
target. The history sits on the same page underneath: every day back to the
|
||||
first entry, unlogged days shown as explicit gaps, and every row a link that
|
||||
loads that day into the logger above it.
|
||||
- **Ruuat** — add, edit and delete mains and sides, or import a whole bundle
|
||||
by paste or file upload. Grouped by category and alphabetical inside, since
|
||||
this is a list you manage rather than one you pick from. Deletes are soft,
|
||||
so old log entries keep showing the dish they used.
|
||||
- **Light / dark**, remembered per device, dark by default. The button shows
|
||||
the theme that is on — moon while dark, sun while light — not the one a
|
||||
click would bring.
|
||||
|
||||
Still to build:
|
||||
|
||||
- Live search as you type, and paging for the history and catalog lists once
|
||||
years of entries make them long. Both via Datastar.
|
||||
- Category icons instead of plain colour dots — colour and shape together, so
|
||||
a red blob and a yellow blob are told apart by more than hue.
|
||||
- Edit and delete as icons in the catalog rows, and a confirmation step before
|
||||
a delete actually happens.
|
||||
- A background for the header. Something subtle; the palette gets overhauled
|
||||
later.
|
||||
- Stage 2: the seven-meal suggester, which starts once there is history to
|
||||
weight against.
|
||||
|
||||
@@ -50,16 +61,31 @@ One static Go binary. No Node.js, no bundler, no separate database server.
|
||||
## Branches
|
||||
|
||||
`main` holds released versions only. Every release tag points at a commit on
|
||||
`main`, so its history is the deployment history.
|
||||
`main`, so its history is the deployment history. **Nothing is committed to
|
||||
`main` directly** — it moves only by fast-forwarding `dev` into it.
|
||||
|
||||
All development happens on `dev`. Merge into `main` when cutting a release,
|
||||
then build and push the image from there.
|
||||
All development happens on `dev`. `main` is protected on the remote: it takes
|
||||
no direct pushes, so a release arrives through a pull request.
|
||||
|
||||
```sh
|
||||
git switch dev # where the work happens
|
||||
git switch main && git merge dev && make release
|
||||
git switch dev # where the work happens
|
||||
# ... commits ...
|
||||
make check # lint, unit tests, smoke
|
||||
git push origin dev
|
||||
|
||||
tea pr create --base main --head dev # or open it in the forge
|
||||
# merge the pull request, then:
|
||||
|
||||
git switch main && git pull --ff-only
|
||||
make release # builds, tags vYYYYMMDD-N, pushes the image
|
||||
git push origin --tags
|
||||
```
|
||||
|
||||
`make image` additionally refuses to run from any branch but `main`, so a
|
||||
release tag can never point at a commit that was not released. That check
|
||||
lives locally because it has to: tags and images are built before anything
|
||||
reaches the remote, so protection there cannot catch it.
|
||||
|
||||
## Quick start
|
||||
|
||||
```sh
|
||||
@@ -84,7 +110,7 @@ make up/down/logs compose
|
||||
|
||||
## Importing dishes
|
||||
|
||||
The **Ruoat** tab takes a bundle of mains and sides: paste the JSON or upload
|
||||
The **Ruuat** tab takes a bundle of mains and sides: paste the JSON or upload
|
||||
a file, and the app reports row by row what it did.
|
||||
|
||||
```json
|
||||
@@ -181,6 +207,16 @@ That directory must exist and be owned by the user compose runs as — `make up`
|
||||
creates it, and `FOODSTER_UID`/`FOODSTER_GID` in `.env` tell the container who
|
||||
that is. Get them from `id -u` and `id -g`.
|
||||
|
||||
If the app exits with `cannot open /data/foodster.db ... unable to open
|
||||
database file (14)`, the ownership does not match. Docker creates a missing
|
||||
bind-mount directory as root, and the container is not root:
|
||||
|
||||
```sh
|
||||
ls -ldn data # whose is it?
|
||||
sudo chown -R 1000:1000 data # match FOODSTER_UID / FOODSTER_GID
|
||||
docker compose restart
|
||||
```
|
||||
|
||||
## Security
|
||||
|
||||
Access is a single shared password over HTTP Basic — no accounts, no
|
||||
|
||||
Reference in New Issue
Block a user