# ───────────────────────────────────────────────────────────── # Stage 1: build — compile TypeScript to dist/ # ───────────────────────────────────────────────────────────── FROM node:20.11-bookworm-slim AS build 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: final — minimal, non-root runtime image # ───────────────────────────────────────────────────────────── FROM node:20.11-bookworm-slim AS final WORKDIR /app # Install curl for healthcheck probe — then clean up apt cache in same layer RUN apt-get update && \ apt-get install -y --no-install-recommends curl && \ rm -rf /var/lib/apt/lists/* # Create dedicated non-root system user/group — containers must never run as root RUN groupadd --system --gid 1001 nodejs && \ useradd --system --uid 1001 --gid nodejs nodeapp # Copy package files and install production dependencies only COPY package.json package-lock.json ./ RUN npm ci --omit=dev # Copy compiled artifacts and runtime-required files from build stage only COPY --from=build /app/dist ./dist COPY --from=build /app/scripts ./scripts COPY --from=build /app/src/db/migrations ./src/db/migrations # Drop root — all subsequent instructions and the running container use nodeapp USER nodeapp EXPOSE 3000 CMD ["node", "dist/server.js"]