# syntax=docker/dockerfile:1 FROM node:22-alpine AS builder WORKDIR /app COPY package.json package-lock.json ./ RUN npm ci COPY . . RUN npx prisma generate # Qualitaets-Gate: ein Image entsteht nur, wenn Lint, Typecheck und # Unit-Tests gruen sind. eslint laeuft hier ohne --fix (anders als # `npm run lint`), damit ein Verstoss den Build abbricht statt still # korrigiert zu werden. Die e2e-Tests brauchen eine Datenbank und laufen # deshalb nicht im Image-Build. RUN npx eslint "{src,test}/**/*.ts" && npm run typecheck && npm test -- --ci RUN npm run build FROM node:22-alpine AS runtime ENV NODE_ENV=production WORKDIR /app COPY package.json package-lock.json ./ RUN npm ci --omit=dev COPY --from=builder /app/dist ./dist COPY --from=builder /app/generated ./generated # schema.prisma, migrations/ und prisma.config.ts: noetig fuer # `npm run migrate:deploy`, das der Container beim Start selbst ausfuehrt # (siehe CMD unten). seed.ts selbst wird NICHT zur Laufzeit ausgefuehrt - # `npm run build` kompiliert es vorab zu dist/seed.js (siehe # tsconfig.seed.json), das schon in ./dist enthalten ist. Frueher lief # `ts-node prisma/seed.ts` direkt im Container: der TypeScript-Compiler # braucht dafuer deutlich mehr Heap als das 512Mi-Pod-Limit hergibt und # fuehrte zu sporadischen OOM-Crashes beim Start. COPY --from=builder /app/prisma ./prisma COPY --from=builder /app/prisma.config.ts ./prisma.config.ts EXPOSE 3001 USER node # migrate deploy ist idempotent und nutzt einen DB-seitigen Advisory-Lock, # seed ist idempotent per Unique-Constraint auf User.email (siehe seed.ts) - # beides unproblematisch bei mehreren gleichzeitig startenden Pod-Replicas. CMD ["sh", "-c", "npm run migrate:deploy && npm run seed && node dist/main.js"]