# Xtablo backend — task runner # # Portability: compose.yaml works under both `podman compose` and `docker compose` (CONTEXT D-11). # This justfile uses `podman compose` by default; substitute `docker compose` if needed — # the service definition is identical. # # Dev workflow (two terminals, per RESEARCH Open Question 2): # Terminal 1: just dev # brings up postgres, generates assets, runs air for Go live-reload # Terminal 2: just styles-watch # runs the Tailwind standalone CLI in --watch mode # # Tailwind is intentionally NOT chained into air's pre_cmd: piping CSS rebuilds through # every .go save is wasteful, and the two concerns are independent (CONTEXT D-14). set shell := ["bash", "-cu"] set dotenv-load := true # --- Pinned versions ------------------------------------------------------------------------ # Runtime Go modules are pinned in go.mod (chi v5.2.5, templ v0.3.1020, pgx/v5 v5.9.2, # goose v3.27.1, uuid v1.6.0). Below: CLI tools installed by `just bootstrap`. goose_version := "v3.27.1" templ_version := "v0.3.1020" sqlc_version := "v1.31.1" air_version := "v1.65.1" # Tailwind standalone CLI version pinned for reproducible bootstrap. Update by bumping # this string after verifying the release at https://github.com/tailwindlabs/tailwindcss/releases tailwind_version := "v4.0.0" # HTMX version pinned at bootstrap time. This is the SINGLE authoritative source for the # HTMX version — no runtime CDN reference appears anywhere else (CONTEXT D-10). htmx_version := "2" sortable_version := "1.15.7" # --- Local config --------------------------------------------------------------------------- database_url := "postgres://xtablo:xtablo@localhost:5432/xtablo?sslmode=disable" s3_endpoint := "http://localhost:9000" s3_bucket := "xtablo-dev" s3_region := "us-east-1" s3_access_key := "minioadmin" s3_secret_key := "minioadmin" s3_use_path_style := "true" tailwind := "./bin/tailwindcss" compose_config_dir := ".podman-compose" default: @just --list # Install all CLI tools and bootstrap-download Tailwind + HTMX into local paths. # Network access required. All downloaded artifacts are gitignored — `just bootstrap` is the # canonical reproduction step. bootstrap: mkdir -p bin static # 1. Go-based CLI tools (versions pinned above) go install github.com/pressly/goose/v3/cmd/goose@{{ goose_version }} go install github.com/a-h/templ/cmd/templ@{{ templ_version }} go install github.com/sqlc-dev/sqlc/cmd/sqlc@{{ sqlc_version }} go install github.com/air-verse/air@{{ air_version }} # 2. Tailwind standalone CLI — explicit OS/arch mapping. The Tailwind release artifacts # use 'macos'/'linux' and 'x64'/'arm64', which do NOT match raw `uname -s` / `uname -m` # output (darwin vs macos, x86_64 vs x64). Resolve via case (Codex review concern #2). # Resolves to one of: tailwindcss-macos-x64, tailwindcss-macos-arm64, # tailwindcss-linux-x64, tailwindcss-linux-arm64 os_name=$(uname -s); \ arch_name=$(uname -m); \ case "$os_name" in \ Darwin) tw_os=macos ;; \ Linux) tw_os=linux ;; \ *) echo "Unsupported OS: $os_name (Tailwind standalone supports macos/linux)"; exit 1 ;; \ esac; \ case "$arch_name" in \ x86_64|amd64) tw_arch=x64 ;; \ arm64|aarch64) tw_arch=arm64 ;; \ *) echo "Unsupported arch: $arch_name"; exit 1 ;; \ esac; \ asset="tailwindcss-${tw_os}-${tw_arch}"; \ echo "Downloading $asset @ {{ tailwind_version }}"; \ curl -sSL -o bin/tailwindcss \ "https://github.com/tailwindlabs/tailwindcss/releases/download/{{ tailwind_version }}/${asset}"; \ chmod +x bin/tailwindcss # 3. HTMX — bootstrap-time download. This unpkg URL is the explicit allowed exception to # the runtime no-CDN rule (CONTEXT D-10); served HTML references only /static/htmx.min.js. curl -sSL -o static/htmx.min.js "https://unpkg.com/htmx.org@{{ htmx_version }}/dist/htmx.min.js" # 4. Sortable.js — drag-and-drop library for kanban column reordering. curl -sSL -o static/sortable.min.js "https://cdn.jsdelivr.net/npm/sortablejs@{{ sortable_version }}/Sortable.min.js" compose-config: mkdir -p {{ compose_config_dir }} printf '%s\n' '{"auths":{}}' > {{ compose_config_dir }}/config.json db-up: compose-config DOCKER_CONFIG="$PWD/{{ compose_config_dir }}" podman compose up -d postgres minio minio-init db-down: podman compose down # `just migrate up`, `just migrate down`, `just migrate status`, etc. migrate cmd="status": GOOSE_DRIVER=postgres GOOSE_DBSTRING='{{ database_url }}' GOOSE_MIGRATION_DIR=migrations \ goose {{ cmd }} # templ → Go, sqlc → Go, tailwind → static/tailwind.css. Consumers (templ files, queries, # ui CSS) land in Plans 01-02 / 01-03; until then this recipe will fail when invoked but # its declaration is the contract. generate: templ generate @if ls internal/db/queries/*.sql >/dev/null 2>&1; then sqlc generate; else echo "(no SQL queries yet — skipping sqlc generate)"; fi {{ tailwind }} -i tailwind.input.css -o static/tailwind.css styles-watch: {{ tailwind }} -i tailwind.input.css -o static/tailwind.css --watch dev: db-up just generate DATABASE_URL='{{ database_url }}' \ S3_ENDPOINT='{{ s3_endpoint }}' \ S3_BUCKET='{{ s3_bucket }}' \ S3_REGION='{{ s3_region }}' \ S3_ACCESS_KEY='{{ s3_access_key }}' \ S3_SECRET_KEY='{{ s3_secret_key }}' \ S3_USE_PATH_STYLE='{{ s3_use_path_style }}' \ air -c .air.toml # Start the worker binary (development — requires db-up and MinIO running). worker: db-up DATABASE_URL='{{ database_url }}' \ S3_ENDPOINT='{{ s3_endpoint }}' \ S3_BUCKET='{{ s3_bucket }}' \ S3_REGION='{{ s3_region }}' \ S3_ACCESS_KEY='{{ s3_access_key }}' \ S3_SECRET_KEY='{{ s3_secret_key }}' \ S3_USE_PATH_STYLE='{{ s3_use_path_style }}' \ go run ./cmd/worker # Run the component catalog with live-reload on localhost:8080/ui-catalog (dev-only). # Watches .go, .templ, and .css — rebuilds Tailwind + Go on any change. # Visit http://localhost:8080/ui-catalog to review all 11 component sections. catalog: DATABASE_URL='{{ database_url }}' \ S3_ENDPOINT='{{ s3_endpoint }}' \ S3_BUCKET='{{ s3_bucket }}' \ S3_REGION='{{ s3_region }}' \ S3_ACCESS_KEY='{{ s3_access_key }}' \ S3_SECRET_KEY='{{ s3_secret_key }}' \ S3_USE_PATH_STYLE='{{ s3_use_path_style }}' \ air -c .air-catalog.toml test: just generate go test ./... lint: go vet ./... gofmt -l . | (grep . && exit 1 || exit 0) build: just generate go build -o bin/web ./cmd/web go build -o bin/worker ./cmd/worker # Remove all bootstrap-downloaded and generated artifacts. Does NOT touch the Postgres # volume — run `just db-down` first if a full reset is needed. clean: rm -rf bin/ tmp/ static/htmx.min.js static/sortable.min.js static/tailwind.css find . -name '*_templ.go' -delete