From cae59413749f97cdbef879b32707b0641884848e Mon Sep 17 00:00:00 2001 From: Saravana Achu Mac Date: Tue, 5 May 2026 13:31:10 -0700 Subject: [PATCH] ci(docker): add compose smoke script --- README.md | 3 ++ docker-compose.yml | 15 ++++++---- package.json | 1 + scripts/compose-smoke.sh | 65 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 78 insertions(+), 6 deletions(-) create mode 100755 scripts/compose-smoke.sh diff --git a/README.md b/README.md index 1d72de5..b4b3daa 100644 --- a/README.md +++ b/README.md @@ -47,6 +47,9 @@ pnpm run smoke:local # Use an already-running backend or skip shared service checks when isolating product behavior. SMOKE_START_BACKEND=0 pnpm run smoke:local -- --no-start pnpm run smoke:local -- --skip-platform + +# Docker compose build/start/health smoke +pnpm run smoke:compose ``` ## Architecture diff --git a/docker-compose.yml b/docker-compose.yml index 364a6e1..3ca7d90 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -6,12 +6,12 @@ services: ports: - "4016:4016" environment: - - NODE_ENV=production + - NODE_ENV=${NODE_ENV:-development} - PORT=4016 - HOST=0.0.0.0 - PRODUCT_ID=notelett - SERVICE_NAME=notelett-backend - - JWT_SECRET=${JWT_SECRET:-dev-secret-change-me} + - JWT_SECRET=${JWT_SECRET:-dev-secret-change-me-at-least-32-characters} - COSMOS_ENDPOINT=${COSMOS_ENDPOINT:-} - COSMOS_KEY=${COSMOS_KEY:-} - COSMOS_DATABASE=${COSMOS_DATABASE:-bytelyst} @@ -34,7 +34,7 @@ services: - LLM_EMBEDDING_MODEL=${LLM_EMBEDDING_MODEL:-text-embedding-3-small} restart: unless-stopped healthcheck: - test: ["CMD", "wget", "--spider", "-q", "http://localhost:4016/health"] + test: ["CMD-SHELL", "node -e \"fetch('http://localhost:4016/health').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))\""] interval: 30s timeout: 5s retries: 3 @@ -43,14 +43,17 @@ services: build: context: . dockerfile: web/Dockerfile + args: + NEXT_PUBLIC_NOTES_API_URL: ${NEXT_PUBLIC_NOTES_API_URL:-http://localhost:4016/api} + NEXT_PUBLIC_PLATFORM_SERVICE_URL: ${NEXT_PUBLIC_PLATFORM_SERVICE_URL:-http://localhost:4003/api} ports: - - "3000:3000" + - "3000:3045" environment: - NODE_ENV=production - NEXT_PUBLIC_PRODUCT_NAME=NoteLett - NEXT_PUBLIC_PRODUCT_ID=notelett - - NEXT_PUBLIC_NOTES_API_URL=http://backend:4016/api - - NEXT_PUBLIC_PLATFORM_SERVICE_URL=${PLATFORM_SERVICE_URL:-http://localhost:4003}/api + - NEXT_PUBLIC_NOTES_API_URL=${NEXT_PUBLIC_NOTES_API_URL:-http://localhost:4016/api} + - NEXT_PUBLIC_PLATFORM_SERVICE_URL=${NEXT_PUBLIC_PLATFORM_SERVICE_URL:-http://localhost:4003/api} - NEXT_PUBLIC_EXTRACTION_SERVICE_URL=${EXTRACTION_SERVICE_URL:-http://localhost:4005} - NEXT_PUBLIC_MCP_SERVER_URL=${MCP_SERVER_URL:-http://localhost:4007}/api - NEXT_PUBLIC_DIAGNOSTICS_URL=${DIAGNOSTICS_URL:-http://localhost:3000} diff --git a/package.json b/package.json index d1b8879..ea043ca 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,7 @@ "test": "pnpm --filter @notelett/backend run test && pnpm --filter @notelett/web run test && pnpm --filter @notelett/mobile run test", "build": "pnpm --filter @notelett/backend run build && pnpm --filter @notelett/web run build", "smoke:local": "bash scripts/local-smoke.sh", + "smoke:compose": "bash scripts/compose-smoke.sh", "verify": "pnpm run typecheck && pnpm run test && pnpm run build", "prepare": "husky" }, diff --git a/scripts/compose-smoke.sh b/scripts/compose-smoke.sh new file mode 100755 index 0000000..1e0128c --- /dev/null +++ b/scripts/compose-smoke.sh @@ -0,0 +1,65 @@ +#!/usr/bin/env bash +# Build and smoke-test the local Docker Compose stack. + +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)" +COMPOSE_CMD="${COMPOSE_CMD:-docker compose}" +BACKEND_URL="${BACKEND_URL:-http://localhost:4016}" +WEB_URL="${WEB_URL:-http://localhost:3000}" +JWT_SECRET="${JWT_SECRET:-dev-secret-change-me-at-least-32-characters}" + +cd "$REPO_DIR" + +if ! command -v docker >/dev/null 2>&1; then + echo "docker is required for compose smoke checks." >&2 + exit 127 +fi + +cleanup() { + bash scripts/docker-prep.sh --restore >/dev/null 2>&1 || true + if [[ "${KEEP_COMPOSE:-0}" != "1" ]]; then + $COMPOSE_CMD down --remove-orphans >/dev/null 2>&1 || true + fi +} +trap cleanup EXIT + +wait_for_url() { + local url="$1" + local label="$2" + local attempts="${3:-60}" + + for attempt in $(seq 1 "$attempts"); do + if curl -fsS "$url" >/dev/null; then + echo "ok: $label" + return 0 + fi + sleep 2 + if [[ "$attempt" == "$attempts" ]]; then + echo "failed: $label did not respond at $url" >&2 + return 1 + fi + done +} + +echo "Preparing Docker build dependencies..." +bash scripts/docker-prep.sh + +echo "Building backend and web images..." +$COMPOSE_CMD build backend web + +echo "Starting compose stack..." +NODE_ENV=development \ +DB_PROVIDER=memory \ +JWT_SECRET="$JWT_SECRET" \ +FIELD_ENCRYPT_ENABLED=false \ +FEATURE_FLAGS_ENABLED=false \ +TELEMETRY_ENABLED=false \ +$COMPOSE_CMD up -d backend web + +wait_for_url "$BACKEND_URL/health" "backend health" +wait_for_url "$BACKEND_URL/api/bootstrap" "backend bootstrap" +wait_for_url "$WEB_URL" "web root" + +echo "Compose smoke passed."