services: app-dev: build: . container_name: appspace-webex-dev ports: - "1889:3000" # host 1889 → container 3000 (app always listens on 3000 inside) env_file: .env.dev environment: - PORT=3000 # force internal listen port (overrides any PORT in .env.dev for container) volumes: - .:/app - /app/node_modules command: npm run dev user: root # dev bind mounts often require root for host uid/perms; prod image uses non-root restart: unless-stopped profiles: ["dev"] app-prod: build: . container_name: appspace-webex-prod ports: - "1889:3000" # host 1889 → container 3000 (app always listens on 3000 inside) env_file: .env environment: - PORT=3000 # force internal listen port (overrides any PORT in .env for container) restart: unless-stopped # No `profiles:` key on this service, so `docker compose up -d` (or `docker compose up -d app-prod`) starts it by default. # Use `docker compose --profile dev up -d app-dev` for development (only starts the dev service). # Inherits non-root USER node from Dockerfile for security hardening # Dockerfile HEALTHCHECK is automatically used by Docker # Smoke test service: starts the prod image with minimal dummy envs # (required vars are validated at startup). Used by `npm run docker:smoke` # to verify the container builds, starts, and /health responds. smoke-test: build: . container_name: appspace-smoke-test environment: - PORT=3000 - NODE_ENV=production # Dummy values for required env vars (validation happens early) - WEBEX_BOT_TOKEN=smoke-test-bot-token - WEBEX_ROOM_ID=smoke-test-room-id - APPSPACE_INSTANCE_URL=https://smoke.example.com - APPSPACE_SUBJECT_ID=smoke-subject - APPSPACE_REFRESH_TOKEN=smoke-refresh-token - APPSPACE_API_BASE_URL=https://smoke.example.com - SMOKE_TEST=true # No ports published; we use docker inspect for the built-in healthcheck status. profiles: ["smoke"] # Uses the hardened Dockerfile (non-root, healthcheck, etc.)