diff --git a/apps/api/docs/agents/dev-environment.md b/apps/api/docs/agents/dev-environment.md index a030719f..37157aac 100644 --- a/apps/api/docs/agents/dev-environment.md +++ b/apps/api/docs/agents/dev-environment.md @@ -25,7 +25,7 @@ error message to switch sides cleanly. - **Container:** `./dev.sh up --build` rebuilds the image; the named `api_dev_node_modules` volume persists across rebuilds, so refresh it once with - `docker volume rm ai-starter-infra_api_dev_node_modules` before the + `docker volume rm boringstack-infra_api_dev_node_modules` before the next `up`. `node_modules` is baked into the image at build time, so the container diff --git a/apps/api/scripts/ci/pre-push.sh b/apps/api/scripts/ci/pre-push.sh index bf74cab2..78e1fe8a 100755 --- a/apps/api/scripts/ci/pre-push.sh +++ b/apps/api/scripts/ci/pre-push.sh @@ -59,8 +59,9 @@ osv-scanner --config="$ROOT/osv-scanner.toml" --lockfile="$ROOT/bun.lock" ok "osv-scanner clean" RAN=$((RAN + 1)) -step "3/${TOTAL} Ensure Postgres + Valkey are running" +step "3/${TOTAL} Ensure Postgres + Valkey are running and migrated" probe_tcp() { nc -z "$1" "$2" 2>/dev/null; } +export DATABASE_URL="${DATABASE_URL:-postgresql://app:app_dev_password@localhost:5432/app}" if probe_tcp localhost 5432 && probe_tcp localhost 6379; then ok "Postgres + Valkey already up" @@ -83,12 +84,21 @@ else probe_tcp localhost 6379 || fail "Valkey did not become reachable on :6379" ok "dev stack ready" fi + +# Always migrate — a reachable :5432 does NOT guarantee a migrated schema. A +# sibling stack's `down -v` (e.g. the smoke gate) can drop the volume out from +# under a still-listening Postgres, leaving tests to hit "relation +# audit.audit_log does not exist". The api-migrate-dev one-shot is idempotent +# and runs inside the compose network against the real `postgres` service, so +# it targets the dev DB regardless of what holds the host's :5432. +c_blue " applying migrations (idempotent)…" +(cd "$COMPOSE_DIR" && ./dev.sh up -d api-migrate-dev >/dev/null 2>&1) +ok "schema migrated" RAN=$((RAN + 1)) step "4/${TOTAL} Test suite (integration)" export REQUIRE_INTEGRATION_DB=true export RUN_VALKEY_NETWORK_TESTS=true -export DATABASE_URL="${DATABASE_URL:-postgresql://app:app_dev_password@localhost:5432/app}" bun run test ok "tests passed" RAN=$((RAN + 1)) diff --git a/apps/api/scripts/dev/preflight-host-dev.sh b/apps/api/scripts/dev/preflight-host-dev.sh index bf6b6725..684e3ee2 100755 --- a/apps/api/scripts/dev/preflight-host-dev.sh +++ b/apps/api/scripts/dev/preflight-host-dev.sh @@ -13,7 +13,7 @@ fi # Compose project name (from `name:` in docker-compose.yml) prefixes the # service container name with a numeric suffix per replica. if docker ps --format '{{.Names}}' 2>/dev/null \ - | grep -qE '^ai-starter-infra-api-dev-[0-9]+$'; then + | grep -qE '^boringstack-infra-api-dev-[0-9]+$'; then cat >&2 <<'MSG' ────────────────────────────────────────────────────────────────────── diff --git a/apps/docs/src/content/docs/topics/deployment.mdx b/apps/docs/src/content/docs/topics/deployment.mdx index e913c5b5..3ce0870f 100644 --- a/apps/docs/src/content/docs/topics/deployment.mdx +++ b/apps/docs/src/content/docs/topics/deployment.mdx @@ -329,8 +329,8 @@ it rejects boot, and Traefik's ACME loop logs every retry. ```bash docker compose -f /opt/boringstack/infra/compose/compose/docker-compose.yml ps -docker logs ai-starter-infra-api-1 2>&1 | tail -50 -docker logs ai-starter-infra-traefik-1 2>&1 | grep -i acme +docker logs boringstack-infra-api-1 2>&1 | tail -50 +docker logs boringstack-infra-traefik-1 2>&1 | grep -i acme ``` If check 2 fails (the cert says Cloudflare instead of Let's Encrypt), diff --git a/apps/docs/src/data/scripts-catalog.json b/apps/docs/src/data/scripts-catalog.json index dc8e34de..3be9b139 100644 --- a/apps/docs/src/data/scripts-catalog.json +++ b/apps/docs/src/data/scripts-catalog.json @@ -273,7 +273,7 @@ "prePushStages": [ "1/${TOTAL} Fast checks (typecheck, lint, lint:meta, knip)", "2/${TOTAL} Dependency vulnerability scan", - "3/${TOTAL} Ensure Postgres + Valkey are running", + "3/${TOTAL} Ensure Postgres + Valkey are running and migrated", "4/${TOTAL} Test suite (integration)", "5/${TOTAL} Test coverage", "6/${TOTAL} Production build", diff --git a/apps/ui/docs/agents/dev-environment.md b/apps/ui/docs/agents/dev-environment.md index 1fcdb39d..2a44cbd1 100644 --- a/apps/ui/docs/agents/dev-environment.md +++ b/apps/ui/docs/agents/dev-environment.md @@ -7,7 +7,7 @@ container dev, or chasing stale-module / blank-page boots. ```bash rm -rf apps/ui/node_modules -cd infra/compose/compose && docker volume rm ai-starter-infra_ui_dev_node_modules 2>/dev/null; ./dev.sh up -d --build ui-dev +cd infra/compose/compose && docker volume rm boringstack-infra_ui_dev_node_modules 2>/dev/null; ./dev.sh up -d --build ui-dev ``` ## Pick one runner @@ -30,7 +30,7 @@ error message to switch sides cleanly. - **Container:** `./dev.sh up --build` rebuilds the image; the named `ui_dev_node_modules` volume persists across rebuilds, so refresh it once with - `docker volume rm ai-starter-infra_ui_dev_node_modules` before the + `docker volume rm boringstack-infra_ui_dev_node_modules` before the next `up`. `node_modules` is baked into the image at build time, so the container diff --git a/apps/ui/scripts/dev/preflight-host-dev.sh b/apps/ui/scripts/dev/preflight-host-dev.sh index fd832f17..016f88ad 100755 --- a/apps/ui/scripts/dev/preflight-host-dev.sh +++ b/apps/ui/scripts/dev/preflight-host-dev.sh @@ -10,7 +10,7 @@ if ! command -v docker >/dev/null 2>&1; then fi if docker ps --format '{{.Names}}' 2>/dev/null \ - | grep -qE '^ai-starter-infra-ui-dev-[0-9]+$'; then + | grep -qE '^boringstack-infra-ui-dev-[0-9]+$'; then cat >&2 <<'MSG' ────────────────────────────────────────────────────────────────────── diff --git a/infra/compose/compose/dev.sh b/infra/compose/compose/dev.sh index 131a87c9..a13037de 100755 --- a/infra/compose/compose/dev.sh +++ b/infra/compose/compose/dev.sh @@ -24,6 +24,17 @@ STACK="${STACK:-dev}" COMPOSE_FILES=(-f "$ROOT/docker-compose.yml") PROFILE_ARGS=() +# Isolate the smoke stack under its own compose project. The pre-push smoke +# gate tears its stack down with `down -v`; without isolation that removes the +# shared Postgres/Valkey volumes the api test gate then depends on, so tests +# hit an empty schema ("audit.audit_log does not exist"). A dedicated project +# means `down -v` can only ever drop smoke's own volumes. dev/prod keep the +# docker-compose.yml `name:` (boringstack-infra). +PROJECT_ARGS=() +if [[ "$STACK" == "smoke" ]]; then + PROJECT_ARGS=(-p boringstack-smoke) +fi + # Observability + GlitchTip default to ON for dev and prod — you can't build # muscle memory for a dashboard you've never seen until prod day-one. They # stay OFF for `smoke` (full-stack-smoke CI doesn't need them and the extra @@ -164,7 +175,7 @@ if [[ "$STACK" == "dev" && "${1:-}" == "up" ]]; then fi if [[ "$WIRE_GLITCHTIP" == "1" || "$WIRE_VAPID" == "1" ]]; then - docker compose "${COMPOSE_FILES[@]}" "${PROFILE_ARGS[@]}" "$@" + docker compose "${COMPOSE_FILES[@]}" "${PROJECT_ARGS[@]}" "${PROFILE_ARGS[@]}" "$@" # Background — both scripts are idempotent and silent when wiring is # already done. Foregrounding them would hold the dev loop on every # `up` for first-boot bootstraps that only matter once. @@ -175,5 +186,5 @@ if [[ "$WIRE_GLITCHTIP" == "1" || "$WIRE_VAPID" == "1" ]]; then ( "$ROOT/../scripts/dev-vapid-init.sh" --quiet & ) >/dev/null 2>&1 fi else - exec docker compose "${COMPOSE_FILES[@]}" "${PROFILE_ARGS[@]}" "$@" + exec docker compose "${COMPOSE_FILES[@]}" "${PROJECT_ARGS[@]}" "${PROFILE_ARGS[@]}" "$@" fi diff --git a/infra/compose/compose/docker-compose.yml b/infra/compose/compose/docker-compose.yml index 17cb9e6d..438f7a87 100644 --- a/infra/compose/compose/docker-compose.yml +++ b/infra/compose/compose/docker-compose.yml @@ -1,4 +1,4 @@ -name: ai-starter-infra +name: boringstack-infra x-default-logging: &default-logging driver: json-file @@ -67,7 +67,7 @@ services: traefik: image: traefik:v3.7@sha256:6b9cbca6fac42ab0075f5437d8dc1685cfd188626d8d515839ea94f8b6271c42 - container_name: ai-starter-traefik + container_name: boringstack-traefik profiles: [prod] user: root restart: unless-stopped diff --git a/infra/compose/compose/promtail/promtail-config.yml b/infra/compose/compose/promtail/promtail-config.yml index 333e5cd6..48aba114 100644 --- a/infra/compose/compose/promtail/promtail-config.yml +++ b/infra/compose/compose/promtail/promtail-config.yml @@ -28,7 +28,7 @@ scrape_configs: refresh_interval: 5s filters: - name: label - values: ["com.docker.compose.project=ai-starter-infra"] + values: ["com.docker.compose.project=boringstack-infra"] relabel_configs: # Skip Pino-speaking containers (handled by the next job with JSON parsing). - source_labels: ["__meta_docker_container_label_com_docker_compose_service"] @@ -50,7 +50,7 @@ scrape_configs: refresh_interval: 5s filters: - name: label - values: ["com.docker.compose.project=ai-starter-infra"] + values: ["com.docker.compose.project=boringstack-infra"] relabel_configs: - source_labels: ["__meta_docker_container_label_com_docker_compose_service"] regex: "^(api-dev|api|api-migrate|api-migrate-dev)$" diff --git a/infra/compose/docs/logql-cheatsheet.md b/infra/compose/docs/logql-cheatsheet.md index 1a6be16c..98361b1b 100644 --- a/infra/compose/docs/logql-cheatsheet.md +++ b/infra/compose/docs/logql-cheatsheet.md @@ -2,9 +2,9 @@ Quick reference for querying Loki from Grafana's Explore tab. The Promtail config ships every container log to Loki with these labels: -- `compose_project` — always `ai-starter-infra` +- `compose_project` — always `boringstack-infra` - `compose_service` — the service name (`api-dev`, `ui-dev`, `postgres`, `traefik`, `glitchtip-web`, `glitchtip-worker`, etc.) -- `container` — the container name (`ai-starter-infra-api-dev-1`) +- `container` — the container name (`boringstack-infra-api-dev-1`) ## Basics @@ -29,12 +29,12 @@ Quick reference for querying Loki from Grafana's Explore tab. The Promtail confi **"All errors across all services, last 1h":** ```logql -{compose_project="ai-starter-infra"} |~ "(?i)error" +{compose_project="boringstack-infra"} |~ "(?i)error" ``` **"Errors as a numeric series for graphing":** ```logql -sum by (compose_service) (rate({compose_project="ai-starter-infra"} |~ "(?i)error" [5m])) +sum by (compose_service) (rate({compose_project="boringstack-infra"} |~ "(?i)error" [5m])) ``` **"Filter API logs by Pino JSON `level`":** @@ -68,7 +68,7 @@ sum by (router) ( ```logql # Combined with Grafana's time-range picker, scope to the 30s before the # restart event in Prometheus (changes(container_start_time_seconds[5m]) > 0). -{container="ai-starter-infra-api-dev-1"} +{container="boringstack-infra-api-dev-1"} ``` ## Useful operators diff --git a/infra/compose/docs/observability.md b/infra/compose/docs/observability.md index 11beb39b..56bde224 100644 --- a/infra/compose/docs/observability.md +++ b/infra/compose/docs/observability.md @@ -46,7 +46,7 @@ Set `GRAFANA_ADMIN_USER` / `GRAFANA_ADMIN_PASSWORD` in `compose/.env` before exp **Promtail** (`compose/promtail/promtail-config.yml`): -- Discovers all containers in the `ai-starter-infra` Compose project via the docker socket. +- Discovers all containers in the `boringstack-infra` Compose project via the docker socket. - Labels every line with `compose_service` (e.g. `api-dev`, `traefik`), `compose_project`, and `container`. - Ships to Loki. diff --git a/scripts/rename-project.sh b/scripts/rename-project.sh index 5589955f..88688f1e 100755 --- a/scripts/rename-project.sh +++ b/scripts/rename-project.sh @@ -10,7 +10,9 @@ # - "API Template" (Swagger title) → # - noreply@example.com → noreply@ # - demo@example.com (seeded demo user) → demo@ -# - ai-starter-infra (compose stack name) → -infra +# +# The compose stack name (boringstack-infra) and all container/volume +# names rename via the bare boringstack → rule below. # # Excluded from rewrite: # - apps/api/src/lib/email/providers/cloudflare.ts and similar prose that @@ -106,7 +108,6 @@ printf ' %-26s → %s\n' "boringstack-api" "$PROJECT-api" printf ' %-26s → %s\n' "boringstack-ui" "$PROJECT-ui" printf ' %-26s → %s\n' "boringstack-xyz" "$GHCR_OWNER" printf ' %-26s → %s\n' "API Template" "$PROJECT_TITLE" -printf ' %-26s → %s\n' "ai-starter-infra" "$PROJECT-infra" printf ' %-26s → %s\n' "noreply@example.com" "noreply@$DOMAIN" printf ' %-26s → %s\n' "demo@example.com" "demo@$DOMAIN" echo @@ -162,7 +163,7 @@ apply_to_file() { [[ -f "$file" ]] || return 0 if [[ "$DRY_RUN" == "1" ]]; then - if grep -qE 'boringstack|BoringStack|ai-starter-infra|API Template|@example\.com' "$file" 2>/dev/null; then + if grep -qE 'boringstack|BoringStack|API Template|@example\.com' "$file" 2>/dev/null; then echo " would edit: $file" fi return 0 @@ -179,7 +180,6 @@ apply_to_file() { -e "s/boringstack-xyz/${GHCR_OWNER}/g" \ -e "s/boringstack-api/${PROJECT}-api/g" \ -e "s/boringstack-ui/${PROJECT}-ui/g" \ - -e "s/ai-starter-infra/${PROJECT}-infra/g" \ -e "s/BoringStack API/${PROJECT_TITLE} API/g" \ -e "s/BoringStack UI/${PROJECT_TITLE} UI/g" \ -e "s/BoringStack/${PROJECT_TITLE}/g" \