# Build the SPA. adapter-static writes /app/build (pages == assets). FROM node:24-alpine AS build WORKDIR /app # Lockfile first: this layer is reused until the dependencies actually change. # Every build tool lives in devDependencies, so no --omit=dev here. # # --legacy-peer-deps works around a conflict that predates this Dockerfile: # openapi-typescript@7.13.0 peer-requires typescript@^5.x while the project is on ^6.0.3, # so plain `npm ci` fails ERESOLVE on every npm version tested (10.8, 10.9, 11.17). # The flag only skips peer *validation* — the tree installed is still exactly # package-lock.json (verified: typescript 6.0.3, lockfile unmodified). # Drop the flag once package.json resolves that conflict. COPY package.json package-lock.json ./ RUN npm ci --legacy-peer-deps COPY . . # Optional baked-in default. Precedence at runtime is # /config.js > VITE_API_BASE_URL > the 'http://localhost:5000' in src/lib/api/client.ts. # Declared after `npm ci` so passing it does not invalidate the dependency layer. # client.ts uses `??`, so an empty string would beat its default: unset instead of exporting "". ARG VITE_API_BASE_URL # Same gate as the README's documented `npm run check`: a type regression fails the image. RUN npm run check RUN if [ -z "${VITE_API_BASE_URL:-}" ]; then unset VITE_API_BASE_URL; fi; npm run build # Serve it. openapi.json / schema.d.ts are committed, so nothing here touches the live API. FROM nginx:1.27-alpine WORKDIR /usr/share/nginx/html COPY nginx.conf /etc/nginx/conf.d/default.conf COPY docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh RUN chmod +x /usr/local/bin/docker-entrypoint.sh COPY --from=build /app/build/ ./ EXPOSE 80 ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"] CMD ["nginx", "-g", "daemon off;"]