Port of Feature 04 task 3 (7629cab) onto Feature 04 + Feature 03.
On first boot create the single household_settings row with the zone from
MEALQUEST_DEFAULT_TZ and the seed times and days (dinner 17:30, reminder
16:30, rotation check 09:00, plan draft Fri 09:00, suggestions Sun 08:00,
chat autosend Sat 08:00). An existing row is never overwritten.
Add household.SettingsService with Get, a validating Update (IANA zone,
zero-padded 24-hour HH:MM, day of week 0-6) that records updated_by, and
in-process Subscribe for the scheduler. Serve it as GET and PATCH
/api/v1/settings/household; invalid input is a 400 in the standard error
body. Migration 0002 adds household_settings.updated_by. Link time/tzdata
from internal/household so zones load in the minimal image.
Review fixes:
- F1: the settings routes are mounted on the protected /api/v1 subrouter,
so they need a session (RequireSession) and, for PATCH, the CSRF token.
updated_by is the session actor's subject from auth.ActorFrom; the
duplicate internal/actor package is dropped, and Update refuses an empty
member instead of storing NULL. A test drives PATCH through the
production router with a real SessionManager session.
- F2: config no longer validates MEALQUEST_DEFAULT_TZ. Seeding requires a
valid zone only when it creates the row (ErrNoDefaultZone,
ErrInvalidDefaultZone, both naming the variable at boot), so a reboot
over existing settings ignores a missing or invalid default.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
81 lines
4.2 KiB
Markdown
81 lines
4.2 KiB
Markdown
# MealQuest
|
||
|
||
MealQuest is a mobile-first Progressive Web App for weekly dinner planning for
|
||
one household. The household lists the dinners it makes regularly, an AI
|
||
assistant suggests new dinners to try (swipe "Try it" or "Pass"), and the app
|
||
builds a weekly plan, pushes it to Google Calendar, and generates a shopping
|
||
list grouped by dinner, kept as a browsable weekly history. It ships as a
|
||
single Go service with the React PWA embedded in the binary.
|
||
|
||
> Status: this repository is the Feature 01 scaffold (Go service with
|
||
> `/health`, embedded PWA skeleton, Makefile, Dockerfile, CI). The planned
|
||
> application is described in [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md).
|
||
|
||
## Quick start
|
||
|
||
Requirements: Go 1.25 and Node.js `^22.22.2 || ^24.15.0 || >=26.0.0` — that
|
||
is, 22.22.2 or later on the 22 line, 24.15.0 or later on the 24 line, or 26.0.0
|
||
or later. Node.js 23, 24.0–24.14 and 25 are not supported: this is the
|
||
`engines` range of jsdom in the committed lockfile, the strictest of all the
|
||
web dependencies.
|
||
|
||
```sh
|
||
(cd web && npm ci)
|
||
mkdir -p ~/.mealquest-dev # outside the repository: it holds a secret
|
||
chmod 700 ~/.mealquest-dev
|
||
head -c 32 /dev/urandom | base64 > ~/.mealquest-dev/secret_key
|
||
chmod 600 ~/.mealquest-dev/secret_key
|
||
export MEALQUEST_HTTP_ADDR=:8080
|
||
export MEALQUEST_PUBLIC_URL=http://localhost:5173
|
||
export MEALQUEST_DATA_DIR="$HOME/.mealquest-dev"
|
||
export MEALQUEST_SHUTDOWN_TIMEOUT=10s
|
||
export MEALQUEST_SECRET_KEY_FILE="$HOME/.mealquest-dev/secret_key"
|
||
# Authentik OAuth2/OpenID provider for MealQuest (redirect URI:
|
||
# $MEALQUEST_PUBLIC_URL/auth/callback). Save its client secret to the file.
|
||
export MEALQUEST_OIDC_ISSUER=https://auth.example.com/application/o/mealquest/
|
||
export MEALQUEST_OIDC_CLIENT_ID=mealquest
|
||
export MEALQUEST_OIDC_CLIENT_SECRET_FILE="$HOME/.mealquest-dev/oidc_client_secret"
|
||
export MEALQUEST_OIDC_ALLOWED_GROUPS=mealquest-admin
|
||
# Optional: sessions end after MEALQUEST_SESSION_IDLE unused (default 720h)
|
||
# and always MEALQUEST_SESSION_MAX after sign-in (default 4320h).
|
||
# export MEALQUEST_SESSION_IDLE=720h
|
||
# export MEALQUEST_SESSION_MAX=4320h
|
||
# Optional: comma-separated IPs/CIDRs of reverse proxies whose
|
||
# X-Forwarded-For/-Proto headers are honoured (production: Traefik). Unset
|
||
# trusts no peer, which is right for local development.
|
||
# export MEALQUEST_TRUSTED_PROXY=10.60.1.33
|
||
export MEALQUEST_DEFAULT_TZ=America/New_York
|
||
make dev
|
||
```
|
||
|
||
`make dev` runs the Go server on `:8080` and the Vite dev server on `:5173`
|
||
(which proxies `/api`, `/auth` and `/media` to `:8080`). Open
|
||
http://localhost:5173. Configuration is environment-only and fails fast:
|
||
every variable above is required except the commented-out session
|
||
lifetimes (when set they must be positive, with MAX at least IDLE),
|
||
trusted proxy list (every entry must be an IP or CIDR) and
|
||
`MEALQUEST_DEFAULT_TZ`, and
|
||
secrets are read only from files named by `*_FILE` variables. `MEALQUEST_PUBLIC_URL`, `MEALQUEST_OIDC_ISSUER` and the
|
||
endpoints the issuer advertises must be `https://`; plain `http://` is
|
||
accepted only for `localhost`, `127.0.0.1` and `[::1]`.
|
||
`MEALQUEST_DEFAULT_TZ` is the IANA zone the household settings are created
|
||
with on first boot: until those settings exist, boot fails unless it is a
|
||
valid IANA zone. Later boots ignore it, set or not (change the zone in
|
||
household settings instead).
|
||
|
||
## Common commands
|
||
|
||
| Command | What it does |
|
||
| -------------- | --------------------------------------------------------------- |
|
||
| `make dev` | Go server plus Vite dev server. |
|
||
| `make test` | `gofmt` check, `go vet`, `go test -race`, web typecheck and tests. |
|
||
| `make build` | Build the PWA, embed it, build the static binary `bin/mealquest`. |
|
||
| `make docker` | Build the container image from the root `Dockerfile`. |
|
||
|
||
## Where to read next
|
||
|
||
- [AGENTS.md](AGENTS.md) — house rules, approved dependencies, conventions.
|
||
- [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) — architecture of record.
|
||
- [design/MealQuest Requirements.md](design/MealQuest%20Requirements.md) — product requirements.
|
||
- [design/MealQuest UI Designs/design_handoff_mealquest/README.md](design/MealQuest%20UI%20Designs/design_handoff_mealquest/README.md) — UI handoff.
|