# ───────────────────────────────────────────────────────────── # Stage 1: builder — compile TypeScript to dist/ # ───────────────────────────────────────────────────────────── FROM node:18-alpine AS builder WORKDIR /app # Copy package files and install all dependencies (including dev) COPY package.json package-lock.json ./ RUN npm ci # Copy source and compile COPY tsconfig.json ./ COPY src/ ./src/ COPY scripts/ ./scripts/ RUN npm run build # ───────────────────────────────────────────────────────────── # Stage 2: production — minimal runtime image # ───────────────────────────────────────────────────────────── FROM node:18-alpine AS production WORKDIR /app # Copy package files and install production dependencies only COPY package.json package-lock.json ./ RUN npm ci --omit=dev # Copy compiled output from builder stage COPY --from=builder /app/dist ./dist # Copy migration scripts (needed for db:migrate at deploy time) COPY --from=builder /app/scripts ./scripts COPY src/db/migrations ./src/db/migrations # Run as non-root user (built into node:alpine) USER node EXPOSE 3000 CMD ["node", "dist/server.js"]