# ───────────────────────────────────────────────────────────────────────────── # Stage 1: Builder # Installs ALL dependencies and compiles the React frontend inside Docker. # Nothing needs to be installed on the host machine except Docker itself. # ───────────────────────────────────────────────────────────────────────────── FROM node:20-alpine AS builder WORKDIR /build # Install backend deps COPY package.json ./ RUN npm install # Install frontend deps and build React app COPY client/package.json ./client/ RUN cd client && npm install COPY client/ ./client/ RUN cd client && npm run build # ───────────────────────────────────────────────────────────────────────────── # Stage 2: Production image # Copies only what's needed to run — no dev tools, no node_modules for client. # Final image is lean (~180MB) and ready to run with zero host setup. # ───────────────────────────────────────────────────────────────────────────── FROM node:20-alpine AS production # Chromium + deps for Phase 3 Puppeteer PDF generation RUN apk add --no-cache \ chromium \ nss \ freetype \ harfbuzz \ ca-certificates \ ttf-freefont ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true ENV PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium-browser ENV NODE_ENV=production ENV PORT=3001 ENV DB_PATH=/data/cpas.db WORKDIR /app # Copy backend deps from builder COPY --from=builder /build/node_modules ./node_modules COPY --from=builder /build/client/dist ./client/dist # Copy backend source COPY server.js ./ COPY db/ ./db/ COPY package.json ./ # Ensure data directory exists (will be overridden by volume mount) RUN mkdir -p /data EXPOSE 3001 HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \ CMD wget -qO- http://localhost:3001/api/health || exit 1 CMD ["node", "server.js"]