# Laptop-local entry point: build the two service images, run the dev stack. # # No fleet host uses this file. dev, beta and prod all deploy through # infra/deploy/deploy.sh, which pulls registry images by their sha-<12hex> tag. # A laptop has no registry login, so `install` BUILDS both images under the # `:local` tag that infra/docker-compose.yml already falls back to # (BACKEND_IMAGE_TAG / FRONTEND_IMAGE_TAG default to `local`). Without that # build step `up` would try to PULL `:local`, which is published nowhere and # fails with a 403 -- so `up` checks for the images first and says what to run. # # This wraps infra's own compose targets; `make -C infra dev-up` remains # equivalent to `make up` here, same project name, same overlay, same stack. SHELL := /bin/bash # Keeps this stack's volumes off the prod-shaped `thermograph` project that # infra/docker-compose.yml pins by default (the env var always wins over the # file's `name:` key). COMPOSE_PROJECT_NAME ?= thermograph-dev POSTGRES_PASSWORD ?= thermograph-dev # The daemon refuses to start without this, and the backend answers 404 on the # whole /internal/* surface while it is unset -- both fail closed. A throwaway # value is all a laptop needs; nothing outside this stack accepts it. THERMOGRAPH_INTERNAL_TOKEN ?= dev-token export COMPOSE_PROJECT_NAME POSTGRES_PASSWORD THERMOGRAPH_INTERNAL_TOKEN # The dev overlay publishes backend on $DEV_BIND_ADDR, default loopback. Set # DEV_BIND_ADDR=0.0.0.0 to reach it from phones on your own Wi-Fi -- safe on a # laptop LAN, never on a fleet host (see infra/docker-compose.dev.yml). COMPOSE := docker compose -f infra/docker-compose.yml -f infra/docker-compose.dev.yml # Ask compose what it will run rather than restating the image names here -- # REGISTRY_HOST / *_IMAGE_PATH / *_IMAGE_TAG all have defaults in # infra/docker-compose.yml, and a second copy of them in this file is a rename # away from silently building a tag nothing runs. `--images ` also # lists that service's dependencies, hence the per-service filter. Override by # passing BACKEND_IMAGE=... / FRONTEND_IMAGE=... if you need a one-off tag. # POSTGRES_PASSWORD is inlined because `config` refuses to interpolate without # it, and $(shell) does not see make's `export` directives. CONFIG_ENV := POSTGRES_PASSWORD=$(POSTGRES_PASSWORD) ifndef BACKEND_IMAGE BACKEND_IMAGE := $(shell $(CONFIG_ENV) $(COMPOSE) config --images backend 2>/dev/null | grep -m1 '/backend:') endif ifndef FRONTEND_IMAGE FRONTEND_IMAGE := $(shell $(CONFIG_ENV) $(COMPOSE) config --images frontend 2>/dev/null | grep -m1 '/frontend:') endif .DEFAULT_GOAL := help .PHONY: help install up down logs ps check-images-resolved help: ## List targets @grep -hE '^[a-z-]+:.*?## ' $(MAKEFILE_LIST) \ | awk -F':.*?## ' '{printf " \033[36m%-8s\033[0m %s\n", $$1, $$2}' # Empty means `docker compose config` itself failed -- a broken compose file or # no docker at all. Fail here rather than running `docker build -t ""`. check-images-resolved: @[[ -n "$(BACKEND_IMAGE)" && -n "$(FRONTEND_IMAGE)" ]] || { \ echo "could not resolve image names from infra/docker-compose.yml;" >&2; \ echo "check 'docker compose -f infra/docker-compose.yml config'" >&2; exit 1; } install: check-images-resolved ## Build backend + frontend images as :local (run once before `up`) docker build -t $(BACKEND_IMAGE) backend docker build -t $(FRONTEND_IMAGE) frontend up: check-images-resolved ## Start the local dev stack, uncapped, backend on 127.0.0.1:8137 @for img in $(BACKEND_IMAGE) $(FRONTEND_IMAGE); do \ docker image inspect "$$img" >/dev/null 2>&1 || { \ echo "missing image $$img -- run 'make install' first" >&2; exit 1; }; \ done $(COMPOSE) up -d @echo "backend: http://$${DEV_BIND_ADDR:-127.0.0.1}:8137" down: ## Stop the stack (named volumes persist) $(COMPOSE) down logs: ## Follow the stack's logs (SERVICE=backend to narrow) $(COMPOSE) logs -f $(SERVICE) ps: ## Show the stack's containers $(COMPOSE) ps