Stage 1's point is collecting eating history, so the logging path is the one that has to be frictionless: pick a dish, tick sides, done. Kirjaa: - dishes ordered and sized by how often they have been eaten, so the likely answer is the biggest target on the screen - picking a dish opens the sides step; a dish with has_sides false says so instead of offering an empty list - saving redirects, so a refresh cannot double-post - a day already logged shows the entry with edit and delete. Editing reopens the sides step with the existing sides ticked, which makes editing and creating the same screen - day switcher and a server-side search over the catalog Historia walks back day by day to the oldest entry, so a day nobody wrote down appears as an explicit gap rather than quietly missing. No JavaScript is involved: every interaction is a link or a form, and the checked-chip styling is :has(input:checked). Datastar stays loaded but unused until an interaction genuinely needs to avoid a page load. Also fix a Makefile ordering bug: lint did not depend on generate, so `go vet` could run against templ output that was being rewritten. check now runs its phases as sub-makes so `make -j` cannot interleave them. Records two features that are specified but not built: dish CRUD in the UI (§7.3, only import exists today) and a per-device light/dark switch (§7.4). The switch must show the state that is active, not the one clicking produces.
102 lines
3.4 KiB
Makefile
102 lines
3.4 KiB
Makefile
# Foodster. Run `make` for the target list.
|
|
|
|
COMPOSE ?= podman compose
|
|
BIN := foodster
|
|
PKG := ./cmd/foodster
|
|
|
|
# Vendored Datastar client. Bump, run `make vendor`, commit the result.
|
|
DATASTAR_VERSION ?= v1.0.3
|
|
SEED ?= seeds/testi.json
|
|
|
|
# Registry coordinates, shared password and TZ live here. Gitignored.
|
|
ifneq (,$(wildcard .env))
|
|
include .env
|
|
export
|
|
endif
|
|
|
|
# Generated templ output is excluded — it is not ours to format.
|
|
GOFILES = $(shell find . -name '*.go' -not -name '*_templ.go' 2>/dev/null)
|
|
|
|
.DEFAULT_GOAL := help
|
|
.PHONY: help generate build run seed test smoke check lint fix vendor image push release up down logs clean
|
|
|
|
help: ## Show this help
|
|
@grep -hE '^[a-zA-Z_-]+:.*## ' $(MAKEFILE_LIST) \
|
|
| awk -F':.*## ' '{printf " \033[1m%-9s\033[0m %s\n", $$1, $$2}'
|
|
|
|
generate: ## Generate Go from .templ files
|
|
go tool templ generate
|
|
|
|
build: generate ## Build ./foodster
|
|
CGO_ENABLED=0 go build -trimpath \
|
|
-ldflags="-s -w -X main.version=dev" -o $(BIN) $(PKG)
|
|
|
|
run: generate ## Run locally on :8080 (database in ./data)
|
|
FOODSTER_PASSWORD=$${FOODSTER_PASSWORD:-dev} go run $(PKG)
|
|
|
|
seed: ## Import a dish bundle (SEED=seeds/testi.json)
|
|
go run $(PKG) -import $(SEED)
|
|
|
|
test: generate ## Run unit tests
|
|
go test ./...
|
|
|
|
smoke: generate ## End-to-end check: auth, static assets, bundle import
|
|
./scripts/smoke.sh
|
|
|
|
# Sub-makes rather than prerequisites: these must run in order even under
|
|
# `make -j`, and a parallel run vets generated code that is being rewritten.
|
|
check: ## Everything that must pass before a commit
|
|
@$(MAKE) --no-print-directory lint
|
|
@$(MAKE) --no-print-directory test
|
|
@$(MAKE) --no-print-directory smoke
|
|
@echo "check: all passed"
|
|
|
|
vendor: ## Re-download the Datastar client (DATASTAR_VERSION=v1.0.3)
|
|
curl -sSfL -o cmd/foodster/static/datastar.js \
|
|
"https://cdn.jsdelivr.net/gh/starfederation/datastar@$(DATASTAR_VERSION)/bundles/datastar.js"
|
|
@head -1 cmd/foodster/static/datastar.js
|
|
|
|
lint: generate ## go vet, gofmt check, golangci-lint when installed
|
|
go vet ./...
|
|
@bad=$$(gofmt -l $(GOFILES) 2>/dev/null); \
|
|
if [ -n "$$bad" ]; then echo "gofmt needed:"; echo "$$bad"; exit 1; fi
|
|
@if command -v golangci-lint >/dev/null 2>&1; then golangci-lint run; \
|
|
else echo "golangci-lint not installed - skipped"; fi
|
|
|
|
fix: ## Format Go and templ sources, tidy go.mod
|
|
@if [ -n "$(GOFILES)" ]; then gofmt -w $(GOFILES); fi
|
|
go tool templ fmt .
|
|
go mod tidy
|
|
|
|
image: ## Build and tag an image as vYYYYMMDD-N. Creates a git tag.
|
|
@test -n "$(FOODSTER_REPO)" || { echo "set FOODSTER_REPO in .env"; exit 1; }
|
|
@day=$$(date +%Y%m%d); \
|
|
tag="v$$day-$$(( $$(git tag -l "v$$day-*" | wc -l) + 1 ))"; \
|
|
echo "==> $$tag"; \
|
|
git tag "$$tag"; \
|
|
podman build --platform linux/amd64 --build-arg VERSION="$$tag" \
|
|
-t "$(FOODSTER_REPO):$$tag" -t "$(FOODSTER_REPO):latest" .
|
|
|
|
push: ## Push the newest tag and :latest
|
|
@test -n "$(FOODSTER_REPO)" || { echo "set FOODSTER_REPO in .env"; exit 1; }
|
|
@tag=$$(git tag -l 'v*' --sort=-creatordate | head -n1); \
|
|
test -n "$$tag" || { echo "no tags yet - run make image"; exit 1; }; \
|
|
podman push "$(FOODSTER_REPO):$$tag"; \
|
|
podman push "$(FOODSTER_REPO):latest"
|
|
|
|
release: image push ## Build, tag and push in one go
|
|
|
|
up: ## Start the stack
|
|
@mkdir -p data # or the engine creates it root-owned and the app cannot write
|
|
$(COMPOSE) up -d
|
|
|
|
down: ## Stop the stack
|
|
$(COMPOSE) down
|
|
|
|
logs: ## Follow app logs
|
|
$(COMPOSE) logs -f app
|
|
|
|
clean: ## Remove the binary and generated templates
|
|
rm -f $(BIN)
|
|
find . -name '*_templ.go' -delete
|