Repository navigation
Expand file tree
/
Copy pathMakefile
More file actions
160 lines (129 loc) · 6.93 KB
/
Copy pathMakefile
File metadata and controls
160 lines (129 loc) · 6.93 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
# ELMS — developer entry points.
#
# Codegen tool versions are pinned here (TDD §14) and fetched on demand via
# `go run pkg@version` / `npx pkg@version`, so nothing has to be installed
# globally beyond Go, Node and Docker.
#
# ELMS is built one task at a time (docs/tasks.md). Targets whose inputs do not
# exist yet print a "skip" line naming the task that creates them, rather than
# failing with a confusing error.
SHELL := /bin/bash
.SHELLFLAGS := -euo pipefail -c
.DEFAULT_GOAL := help
SERVER_DIR := server
WEB_DIR := web
# Connection to the compose Postgres as seen from the host. The api container
# gets its own DATABASE_URL from docker-compose.yml; these defaults mirror it so
# host-run commands (dev, seed) need no setup.
#
# Override in the environment, not in .env — this Makefile never sources it, and
# docker-compose.yml builds the api container's DATABASE_URL from the POSTGRES_*
# parts rather than reading one. To point a host-run command at another database
# (e.g. Neon, before deploying — docs/demo.md):
#
# DATABASE_URL='postgresql://…?sslmode=require' make seed
POSTGRES_USER ?= elms
POSTGRES_PASSWORD ?= elms
POSTGRES_DB ?= elms
POSTGRES_PORT ?= 5432
DATABASE_URL ?= postgres://$(POSTGRES_USER):$(POSTGRES_PASSWORD)@localhost:$(POSTGRES_PORT)/$(POSTGRES_DB)?sslmode=disable
export DATABASE_URL
# Pinned codegen toolchain.
SQLC := go run github.com/sqlc-dev/sqlc/cmd/sqlc@v1.31.1
OAPI_CODEGEN := go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen@v2.8.0
OPENAPI_TS := npx --yes openapi-typescript@7.13.0
OPENAPI_SPEC := $(SERVER_DIR)/api/openapi.yaml
SQLC_CONFIG := $(SERVER_DIR)/sqlc.yaml
OAPI_CONFIG := $(SERVER_DIR)/api/oapi-codegen.yaml
TS_CLIENT := $(WEB_DIR)/src/api/schema.d.ts
COMPOSE_FILE := docker-compose.yml
WEB_PKG := $(WEB_DIR)/package.json
PW_CONFIG := $(WEB_DIR)/playwright.config.ts
.PHONY: help dev up down db-up build gen gen-sql gen-server gen-client \
test test-web test-int e2e lint lint-go lint-web seed clean tools
help: ## Show this help
@echo "ELMS — make targets:"
@grep -hE '^[a-zA-Z0-9_-]+:.*?## .*$$' $(MAKEFILE_LIST) \
| awk 'BEGIN {FS = ":.*?## "}; {printf " \033[36m%-10s\033[0m %s\n", $$1, $$2}'
## ---------------------------------------------------------------- run
dev: db-up ## Run the dev stack (Go API + Vite proxying /api); Ctrl-C stops all
@if [ ! -f "$(WEB_PKG)" ]; then \
echo "→ web not scaffolded yet (T-60); running the API alone"; \
cd $(SERVER_DIR) && go run ./cmd/api; \
else \
trap 'kill 0' EXIT INT TERM; \
( cd $(SERVER_DIR) && go run ./cmd/api ) & \
( cd $(WEB_DIR) && npm run dev ) & \
wait; \
fi
up: ## Full stack via docker compose (postgres + api + web)
@if [ ! -f "$(COMPOSE_FILE)" ]; then echo "→ skip: $(COMPOSE_FILE) not present yet (T-04)"; \
else docker compose up --build; fi
down: ## Stop the compose stack and drop its volumes
@if [ ! -f "$(COMPOSE_FILE)" ]; then echo "→ skip: $(COMPOSE_FILE) not present yet (T-04)"; \
else docker compose down -v; fi
db-up: ## Start only Postgres, in the background
@if [ ! -f "$(COMPOSE_FILE)" ]; then echo "→ skip: $(COMPOSE_FILE) not present yet (T-04)"; \
else docker compose up -d postgres; fi
seed: ## Load idempotent demo data (admin/agent users, station, locker grid)
@if [ ! -d "$(SERVER_DIR)/cmd/seed" ]; then echo "→ skip: seed command not present yet (T-13)"; \
else cd $(SERVER_DIR) && go run ./cmd/seed; fi
## ---------------------------------------------------------------- build
# `go build ./...` cannot run from server/: the cmd/api binary name collides
# with the api/ spec directory. Both paths are fixed by TDD §2, so build into
# bin/ (gitignored) instead.
build: ## Compile the server into server/bin/
cd $(SERVER_DIR) && go build -o bin/ ./...
## ---------------------------------------------------------------- codegen
gen: gen-sql gen-server gen-client ## Regenerate sqlc queries, Go server and TS client
gen-sql:
@if [ ! -f "$(SQLC_CONFIG)" ]; then echo "→ skip sqlc: $(SQLC_CONFIG) not present yet (T-12)"; \
else cd $(SERVER_DIR) && $(SQLC) generate; fi
gen-server:
@if [ ! -f "$(OAPI_CONFIG)" ]; then echo "→ skip oapi-codegen: $(OAPI_CONFIG) not present yet (T-41)"; \
else cd $(SERVER_DIR) && $(OAPI_CODEGEN) -config api/oapi-codegen.yaml api/openapi.yaml; fi
gen-client:
@if [ ! -f "$(OPENAPI_SPEC)" ]; then echo "→ skip TS client: $(OPENAPI_SPEC) not present yet (T-40)"; \
elif [ ! -f "$(WEB_PKG)" ]; then echo "→ skip TS client: $(WEB_DIR) not scaffolded yet (T-60)"; \
else $(OPENAPI_TS) $(OPENAPI_SPEC) -o $(TS_CLIENT); fi
## ---------------------------------------------------------------- verify
test: ## Go unit tests
cd $(SERVER_DIR) && go test ./...
test-web: ## Frontend unit tests (Vitest)
@if [ ! -f "$(WEB_PKG)" ]; then echo "→ skip web tests: $(WEB_DIR) not scaffolded yet (T-60)"; \
else cd $(WEB_DIR) && npx vitest run; fi
# The tag adds the integration files to their packages rather than replacing
# what is already there, so this runs the whole server suite — unit tests
# included — under the race detector. That is what CI runs, and what makes the
# Level 4 proof (README) meaningful.
test-int: ## Whole server suite under -race, integration included (needs Docker)
@docker info >/dev/null 2>&1 || { echo "Docker must be running for testcontainers-go"; exit 1; }
cd $(SERVER_DIR) && go test -race -count=1 -tags=integration ./...
# The guard is on the Playwright config, not on package.json: the web package
# has existed since T-60, so guarding on it fell through to `npx playwright
# test` and made an advertised target fail on a missing suite. T-70 creates the
# config; until then this says so and exits clean.
e2e: ## Playwright suite against the compose stack
@if [ ! -f "$(PW_CONFIG)" ]; then \
echo "→ skip e2e: no Playwright suite yet (T-70/T-71, docs/tasks.md M7)"; \
echo " Until it lands, the equivalent coverage is: make test-int (server, -race)"; \
echo " and make test-web (SPA, Vitest)."; \
else cd $(WEB_DIR) && npx playwright test; fi
lint: lint-go lint-web ## Lint everything (Go + web)
lint-go:
@command -v golangci-lint >/dev/null || { echo "golangci-lint not found — brew install golangci-lint"; exit 1; }
cd $(SERVER_DIR) && go vet ./...
cd $(SERVER_DIR) && golangci-lint run ./...
lint-web:
@if [ ! -f "$(WEB_PKG)" ]; then echo "→ skip web lint: $(WEB_DIR) not scaffolded yet (T-60)"; \
else cd $(WEB_DIR) && npx tsc --noEmit && npm run lint; fi
## ---------------------------------------------------------------- misc
clean: ## Remove build and coverage artifacts
rm -rf $(SERVER_DIR)/bin $(SERVER_DIR)/coverage.out \
$(WEB_DIR)/dist $(WEB_DIR)/coverage \
$(WEB_DIR)/playwright-report $(WEB_DIR)/test-results
tools: ## Report versions of the toolchain this repo expects
@go version
@node --version | sed 's/^/node /'
@docker --version 2>/dev/null || echo "docker: not installed"
@golangci-lint --version 2>/dev/null || echo "golangci-lint: not installed"