Files
foodster/CONTRIBUTING.md
T
KessinenandEsa Kataja d8810d288e release: repair the catalog 404 and stop the page jumping (#3)
Showstopper. Adding, editing or deleting a dish redirected to /ruoat, which stopped existing when the tab was renamed to Ruuat — every one of those actions ended on a 404. Live in v20260905-4. The tests missed it because they asserted only a 303; a redirect to a dead URL is still a 303. They now assert the target.

The page no longer jumps. Deleting a dish partway down the catalog, or opening a day in Kirjaa, sent the browser to the top. Both now patch in place via Datastar — bin, pencil, day rows, dish pills, save, delete, cancel and Näytä lisää. Links stay links and forms stay forms, so it works without JavaScript.

Non-production tabs are labelled. ENV=dev gives dev · Foodster.

Contributing guide added, and commits now take Conventional Commit types.

⚠️ Breaking: rewrite the server's .env in this deploy. Environment variables lost the FOODSTER_ prefix; the app refuses to start on an unset PASSWORD.

REPO=…  TAG=latest  PASSWORD=…  HOST=foodster.kessinen.com
ENV=prod  PUID=1000  PGID=1000  TZ=Europe/Helsinki

PUID/PGID rather than UID/GID — UID is read-only in bash and would be silently overwritten.

Co-authored-by: Esa Kataja <[email protected]>
Reviewed-on: #3
2026-09-05 21:03:04 +00:00

3.6 KiB

Contributing

A household project, so this is less a set of rules than a note to whoever picks it up next — including me in six months.

Getting set up

cp .env.example .env      # then edit it
make run                  # http://localhost:8080, tab titled "dev · Foodster"
make                      # every target, with a one-line description

make check is the gate: go vet, gofmt, unit tests, and scripts/smoke.sh, which drives a real server over HTTP. Run it before every commit.

Branches

dev is where work happens. main holds released versions only — it is protected on the remote and takes no direct pushes, so a release arrives as a pull request from dev, squash-merged.

After a squash merge, reset dev onto it or the next pull request will offer the same commits again:

git switch main && git pull --ff-only
git switch dev && git reset --hard main
git push --force-with-lease origin dev

make image refuses to run outside main. That check has to be local: the tag and the image are made before anything reaches the remote, so branch protection cannot catch a release built from the wrong branch.

Commit messages

Conventional Commits — a type, an optional scope, then a short subject in the imperative.

feat(kirjaa): expand the selected day in place
fix: redirect the catalog to /ruuat, not /ruoat
chore(deps): bump the vendored Datastar client
Type For
feat new behaviour someone will notice
fix a bug, ideally naming what broke
refactor same behaviour, different shape
test tests only
docs documentation only
build Makefile, Containerfile, compose, CI
chore anything else: dependencies, seeds, tidying

The body matters more than the type. Explain why, and what the alternative was — the diff already says what changed. If a fix was subtle, say what made it subtle; if a test caught something, say what. Commits here are the only design record this project has.

Release pull requests

Because main is squash-merged, a pull request title becomes a commit message on main. A release spans a fix, a feature and some chores at once, so none of the types above fits it honestly. Use release: instead:

release: repair the catalog 404 and stop the page jumping

main's log is then one line per deployment, which is what that branch is for, and the pull request body serves as the release notes. No version in the title — the CalVer tag is not created until make image runs after the merge.

The types above are for dev, where a commit really does do one thing.

Things that are easy to get wrong

  • The interface is Finnish. Code, comments, this file and the PRD are English. There is no i18n layer and no language switcher.
  • No infrastructure detail is committed — no hostnames, registry paths or ports. They live in .env, which is gitignored, because the PRD leaves the door open to publishing this repository.
  • Migrations are immutable once shipped. A released migration has run on a live database and will not run again. Add a new numbered file instead.
  • Interactions patch, they do not navigate. Anything that reloads the page loses the scroll position, which on a long list is maddening. Links stay links and forms stay forms so it works without JavaScript; Datastar layers over them with data-on:click__prevent and data-on:submit__prevent.
  • A ponytail: comment marks a deliberate shortcut and names its ceiling, so the next reader can tell a decision from an oversight.
  • Assert what a response does, not just that it responded. A redirect to a dead URL is still a 303; that one shipped.