Files
foodster/CONTRIBUTING.md
T
Esa Kataja 2695b8c01b docs: note that the server's compose and env are copied by hand
The variable rename landed in the repository but not on the server, which
keeps its own compose.yaml and .env. Neither is pulled from here, so the
container came up against the old names. A release touching either now has to
say so in its notes.
2026-09-06 00:08:49 +03:00

105 lines
4.0 KiB
Markdown

# 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.
### 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.
## Deploying
The server keeps its own `compose.yaml` and `.env`. Neither is pulled from
here, so a release that renames a variable, adds one, or changes a mount
needs both copied across **in the same deploy** — otherwise the container
comes up against the old names and the app refuses to start.
Anything in this repository that reaches the server by hand belongs in the
release notes, flagged as breaking.
## 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.