# 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 ```sh 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: ```sh 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. Because `main` is squash-merged, a pull request title becomes a commit message on `main`. Give it the same treatment. ## 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.