Monorepo Makefile: Go API, React frontend, and Postgres via Docker Compose.
SHELL := /bin/bash .DEFAULT_GOAL := help
API_DIR := api WEB_DIR := frontend DIST_DIR := dist COMPOSE := docker compose GO := go NPM := npm
Use npm ci when a lockfile exists; fall back to npm install for first-time setup.
NPM_INSTALL := $(if $(wildcard $(WEB_DIR)/package-lock.json),$(NPM) ci,$(NPM) install)
.PHONY: help setup dev test lint build clean db-up db-migrate
help: ## Show available targets
@awk 'BEGIN {FS = ":.## "; printf "Usage: make \033[36m<target>\033[0m\n\nTargets:\n"}
/^[a-zA-Z0-9_-]+:.## / {printf " \033[36m%-14s\033[0m %s\n", $$1, $$2}'
$(MAKEFILE_LIST)
setup: ## Install dependencies and start Postgres (safe to run repeatedly) @command -v $(GO) >/dev/null || { echo "Go is required"; exit 1; } @command -v $(NPM) >/dev/null || { echo "Node.js/npm is required"; exit 1; } @command -v docker >/dev/null || { echo "Docker is required"; exit 1; } cd $(API_DIR) && $(GO) mod download cd $(WEB_DIR) && $(NPM_INSTALL) $(COMPOSE) up -d postgres
dev: db-up ## Run the Go API and React development servers
@trap 'kill 0' INT TERM EXIT;
(cd $(API_DIR) && $(GO) run ./cmd/api) &
(cd $(WEB_DIR) && $(NPM) run dev) &
wait
test: ## Run backend and frontend tests cd $(API_DIR) && $(GO) test ./... # --runInBand avoids excess worker processes in constrained CI environments. cd $(WEB_DIR) && $(NPM) test -- --runInBand
lint: ## Lint and format-check backend and frontend code
# gofmt prints only files that need formatting; fail if that list is non-empty.
@test -z "$$(cd $(API_DIR) && gofmt -l .)" || {
echo "Go files need formatting; run: gofmt -w $(API_DIR)";
exit 1;
}
cd $(API_DIR) && $(GO) vet ./...
cd $(WEB_DIR) && $(NPM) run lint
build: ## Build production API and frontend artifacts mkdir -p $(DIST_DIR) cd $(API_DIR) && CGO_ENABLED=0 $(GO) build -o ../$(DIST_DIR)/api ./cmd/api cd $(WEB_DIR) && $(NPM) run build rm -rf $(DIST_DIR)/web