Scaffold the Go app: auth, migrations, bundle import
Bring up the stage 1 skeleton described in the PRD, enough that the app builds, serves, and can be populated with dishes. - net/http server with shared-password Basic auth, /healthz outside it, graceful shutdown, and TZ-aware calendar days - SQLite via modernc (pure Go, static binary), opened with WAL and a single connection - migration runner: numbered SQL files embedded and applied once each inside a transaction, recorded in schema_migrations - bundle import (PRD §7.3) as a live feature on the Ruoat tab: paste JSON or upload a file, get a per-row Finnish report. The same importer is reachable as `foodster -import` for repopulating a scratch database - templ views and hand-written CSS with light-dark() theming; the Datastar v1.0.3 client is vendored, since the Go SDK ships no browser asset and a CDN would break an offline LAN Names are normalized to sentence case rather than title case: Finnish capitalizes only the first word of a phrase, so "Keitetyt perunat" is right and "Keitetyt Perunat" is not. PRD §6 and §7.3 are amended to match. Testing is behind make targets rather than ad-hoc commands: `make check` runs lint, unit tests and scripts/smoke.sh, which exercises auth, static assets and every import path against a scratch database on a spare port.
This commit is contained in:
@@ -46,12 +46,57 @@ make fix gofmt, templ fmt, go mod tidy
|
||||
make lint go vet, gofmt check, golangci-lint when installed
|
||||
make test go test ./...
|
||||
make build ./foodster
|
||||
make seed import a dish bundle (SEED=seeds/testi.json)
|
||||
make vendor re-download the Datastar client
|
||||
make image build and tag vYYYYMMDD-N (creates a git tag)
|
||||
make push push the newest tag and :latest
|
||||
make release image + push
|
||||
make up/down/logs compose
|
||||
```
|
||||
|
||||
## Importing dishes
|
||||
|
||||
The **Ruoat** 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
|
||||
{
|
||||
"mains": [{"name": "Kanacurry", "categories": ["chicken"], "has_sides": true}],
|
||||
"sides": [{"name": "Riisi"}]
|
||||
}
|
||||
```
|
||||
|
||||
Categories are `meat`, `chicken`, `fish` and `vegetarian` — stored in English
|
||||
even though the UI is Finnish. A dish may list several, which is how
|
||||
build-your-own meals like tortillas cover every category at once. `has_sides`
|
||||
defaults to `true` when omitted.
|
||||
|
||||
Import is best-effort, never atomic. Valid rows land; invalid ones are skipped
|
||||
and named (`tuntematon kategoria`, `ei kategorioita`, `jo listalla`).
|
||||
|
||||
Names are normalized to sentence case on the way in — whitespace collapses and
|
||||
the first letter is capitalized, the rest is left as typed, because Finnish
|
||||
capitalizes only the first word of a phrase. `keitetyt perunat` is stored as
|
||||
`Keitetyt perunat`, while `BBQ-kylkeä` and `Kotipizza` keep their capitals.
|
||||
Duplicates are caught case-insensitively, so re-importing a bundle is safe.
|
||||
|
||||
The same importer runs from the command line when you just want to repopulate
|
||||
a scratch database:
|
||||
|
||||
```sh
|
||||
make seed # or: SEED=seeds/other.json make seed
|
||||
```
|
||||
|
||||
## Migrations
|
||||
|
||||
Numbered SQL files in `cmd/foodster/migrations`, embedded in the binary and
|
||||
applied in filename order at startup. Each runs in a transaction and is
|
||||
recorded in `schema_migrations`, so it applies exactly once.
|
||||
|
||||
Adding one means dropping a new `NNNN_what_it_does.sql` into that directory.
|
||||
Never edit a migration that has already shipped — a released file has run on
|
||||
a live database and will not run again.
|
||||
|
||||
## Configuration
|
||||
|
||||
Everything is environment variables. `.env` is gitignored; start from
|
||||
|
||||
Reference in New Issue
Block a user