Files
template_001/Dockerfile
SAAC Daemon 5b37f88477 Harden template for production: add comments, fix bugs, add lock file
- Add inline comments to docker-compose.yml explaining the 5 key rules
  (expose vs ports, DB host, DB name persistence, no Traefik labels)
- Add comments to Dockerfile explaining multi-stage build, layer caching,
  and why .dockerignore excludes client/dist
- Add comments to .dockerignore explaining each exclusion
- Fix dev script: use nodemon (auto-restart) instead of node for server.js
- Add postinstall script to auto-install client deps (cd client && npm install)
- Fix SPA fallback: bare return → next() to prevent hanging requests
- Add root package-lock.json for deterministic server dependency installs
- Remove committed tsconfig.tsbuildinfo build artifact, add *.tsbuildinfo to .gitignore
- Update README: simpler install (npm install handles everything), reference SAAC_DEPLOYMENT.md,
  use npx instead of pnpm dlx for shadcn components
2026-02-18 16:36:33 +01:00

58 lines
1.9 KiB
Docker

# Multi-stage Dockerfile for React + Express application
# See SAAC_DEPLOYMENT.md for deployment rules and common mistakes.
#
# Stage 1 (builder): Installs client deps and builds the React app with Vite.
# Stage 2 (production): Installs server deps only, copies built React output.
#
# The .dockerignore excludes client/dist from the build context — this is
# intentional. The builder stage creates a fresh dist/ inside the container,
# and COPY --from=builder copies it between stages (bypasses .dockerignore).
# --- Stage 1: Build React frontend ---
FROM node:20-alpine AS builder
WORKDIR /app/client
# Install client dependencies first (layer caching — only re-runs if package*.json change)
COPY client/package*.json ./
RUN npm install
# Copy client source and build
COPY client/ ./
RUN npm run build
# --- Stage 2: Production server ---
FROM node:20-alpine
ARG SOURCE_COMMIT=unknown
ARG APP_VERSION=1.0.0
WORKDIR /app
# curl is required for the Docker healthcheck below
RUN apk add --no-cache curl
# Install server dependencies only (not devDependencies — they're not needed in production).
# If your app needs devDependencies for a build step (e.g. TypeScript), install ALL deps
# first, run the build, then prune: RUN npm install && npm run build && npm prune --production
COPY package*.json ./
RUN npm install --production
# Copy server code
COPY server.js ./
# Copy built React app from the builder stage (not from host — .dockerignore doesn't apply)
COPY --from=builder /app/client/dist ./client/dist
ENV GIT_COMMIT=${SOURCE_COMMIT} \
APP_VERSION=${APP_VERSION}
# Use "expose" in docker-compose.yml, not "ports". This EXPOSE is just documentation.
EXPOSE 3000
# Healthcheck — must match the healthcheck in docker-compose.yml
HEALTHCHECK --interval=10s --timeout=3s --start-period=5s --retries=2 \
CMD curl -f http://localhost:3000/health || exit 1
CMD ["node", "server.js"]