diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..c171b29 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,81 @@ +# 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. diff --git a/README.md b/README.md index 696f88b..886700a 100644 --- a/README.md +++ b/README.md @@ -58,6 +58,9 @@ One static Go binary. No Node.js, no bundler, no separate database server. | Auth | HTTP Basic, one shared household password | | Runtime image | `FROM scratch` | +Working on it: [CONTRIBUTING.md](CONTRIBUTING.md) — branches, commit messages, +and the conventions that are easy to miss. + ## Branches `main` holds released versions only. Every release tag points at a commit on