FROM node:20-alpine AS builder WORKDIR /app # Copy package files first for better caching COPY package.json package-lock.json ./ RUN npm ci --ignore-scripts # Cache-bust: change CACHEBUST value in docker-compose.yml to force rebuild ARG CACHEBUST=1 # Copy source and build COPY . . RUN npm run build RUN npm prune --production # ── Production image ────────────────────────────────────────── FROM node:20-alpine AS production WORKDIR /app # wget is needed for Docker/Portainer health checks RUN apk add --no-cache wget COPY --from=builder /app/package.json ./package.json COPY --from=builder /app/package-lock.json ./package-lock.json COPY --from=builder /app/dist ./dist COPY --from=builder /app/node_modules ./node_modules EXPOSE 4000 ENV NODE_OPTIONS="--max-old-space-size=1024" # Run TypeORM migrations on startup, then start the API. # Migration errors are logged (not suppressed) so failed deploys are visible. CMD ["sh", "-c", "echo 'Running database migrations...' && npx typeorm migration:run -d dist/database/ormconfig.js && echo 'Migrations complete.' && npm run start:prod"]