services: app: build: context: /docker/linumiq-invoice/git/ dockerfile: Dockerfile image: linumiq-invoice:dev container_name: linumiq-invoice-dev restart: unless-stopped # --- Container hardening (DEV) --------------------------------------- # Prevent privilege escalation and drop all Linux capabilities (the app # is a plain Node HTTP server — it needs none). security_opt: - "no-new-privileges:true" cap_drop: - ALL # Read-only root filesystem: the app never writes to the image at runtime # (Prisma client is baked at build; the SQLite DB lives on the /data bind # mount; logo/image caches live in the DB or in-memory). npm/Prisma # incidental writes are redirected to the tmpfs /tmp (see Dockerfile env). read_only: true tmpfs: - /tmp # Resource limits (Compose v2 / docker compose, non-swarm). mem_limit: 512m pids_limit: 256 cpus: 1.5 env_file: - .env.dev environment: # SQLite file lives on a bind mount so it survives image rebuilds. DATABASE_URL: "file:/data/prod.sqlite" NODE_ENV: production PORT: "3000" volumes: - /docker/linumiq-invoice/dev/data:/data healthcheck: test: ["CMD", "wget", "-qO-", "http://127.0.0.1:3000/healthz"] interval: 30s timeout: 5s retries: 3 networks: - caddy_net networks: caddy_net: name: caddy_net external: true