# Local development only. Runs watch-mode servers against bind-mounted sources. # For a deployment use compose.prod.yaml. # # The project name must stay distinct from the production project so that # `docker compose down` in this directory can never tear down a running # production stack. name: leistungsbilanz-dev x-service-defaults: &service-defaults init: true restart: unless-stopped stop_grace_period: 20s logging: driver: json-file options: max-size: "20m" max-file: "10" services: api: <<: *service-defaults build: context: . target: dev command: - sh - -c - npm run db:migrate && npm run db:verify:circuit-schema && npm run dev:api environment: PORT: "3000" LOG_LEVEL: "${LOG_LEVEL:-info}" # Development ports stay on the loopback interface; nothing here is # authenticated and the API must not be reachable from the LAN. ports: - "127.0.0.1:3000:3000" mem_limit: 1g volumes: - ./src:/app/src - ./scripts:/app/scripts - ./data:/app/data - ./drizzle.config.ts:/app/drizzle.config.ts:ro - ./tsconfig.json:/app/tsconfig.json:ro healthcheck: test: - CMD - node - -e - fetch('http://127.0.0.1:3000/health').then(response=>process.exit(response.ok?0:1)).catch(()=>process.exit(1)) interval: 30s timeout: 5s retries: 5 start_period: 30s web: <<: *service-defaults build: context: . target: dev command: - npm - run - dev:web - -- - --hostname - 0.0.0.0 environment: API_INTERNAL_URL: http://api:3000 NEXT_TELEMETRY_DISABLED: "1" LOG_LEVEL: "${LOG_LEVEL:-info}" depends_on: api: condition: service_healthy ports: - "127.0.0.1:3001:3001" # next dev grows steadily under long-running use; the limit turns that into # a container restart instead of host-wide swapping. mem_limit: 2g volumes: - ./src:/app/src - ./next.config.mjs:/app/next.config.mjs:ro - ./tsconfig.json:/app/tsconfig.json:ro - ./tsconfig.next.json:/app/tsconfig.next.json:ro healthcheck: # Must stay on /health: "/" redirects to /projects and Node's fetch # follows redirects, which turned every probe into a full page render. test: - CMD - node - -e - fetch('http://127.0.0.1:3001/health').then(response=>process.exit(response.ok?0:1)).catch(()=>process.exit(1)) interval: 30s timeout: 5s retries: 5 start_period: 30s