# ============================================================ # STAGE 1: Build Frontend + Backend # ============================================================ FROM node:22-alpine AS builder # Install system dependencies for sharp and pdf processing RUN apk add --no-cache \ python3 \ py3-pip \ make \ g++ \ gcc \ libc-dev \ vips-dev \ poppler-utils \ pkgconfig WORKDIR /app # Install pnpm and node-gyp globally RUN npm install -g pnpm@10.4.1 node-gyp # Copy package files COPY package.json pnpm-lock.yaml ./ COPY patches/ ./patches/ # Install ALL dependencies (including devDeps for build) RUN pnpm install --frozen-lockfile # Copy source code COPY . . # Build frontend + backend RUN pnpm build # ============================================================ # STAGE 2: Production image # ============================================================ FROM node:22-alpine AS production # Install runtime dependencies only (vips for sharp, poppler for PDF) RUN apk add --no-cache \ poppler-utils \ vips \ curl WORKDIR /app # Copy node_modules from builder (already compiled, including sharp native binaries) COPY --from=builder /app/node_modules ./node_modules # Copy built assets from builder COPY --from=builder /app/dist ./dist COPY --from=builder /app/client/dist ./client/dist # Copy package.json (needed for module resolution) COPY package.json ./ # Copy drizzle migrations COPY drizzle/ ./drizzle/ COPY drizzle.config.ts ./ # Create uploads directory RUN mkdir -p /app/uploads EXPOSE 3000 CMD ["node", "dist/index.js"]