build(r0.13): Dockerfiles api/web + compose Dokploy + runbook — R0 prêt à déployer

- image api : multi-stage (pnpm deploy --legacy --prod), client Prisma
  régénéré dans l'arborescence déployée, binaryTargets explicites
  (debian/arm64 openssl-3), entrypoint migrate deploy → seed optionnel
  (SEED_ON_START, compilé dist/seed) → API ; non-root, healthcheck /health
- image web : nginx alpine, statique Vite, proxy /api résolu À LA REQUÊTE
  (resolver Docker + variable — nginx démarre sans l'API), fallback SPA,
  cache immuable /assets, healthcheck IPv4 (127.0.0.1)
- infra/docker-compose.dokploy.yml : 5 services préfixés siop2-, secrets
  exigés, seul siop2-web rejoint dokploy-network (API jamais exposée)
- runbook docs/06-production/runbook-dokploy.md : topologie, profils
  d'environnement, checklist première prod, rollback, répétition locale
- répétition locale validée de bout en bout : migrate+seed au boot,
  parcours demo-login → /users/me à travers nginx conteneurisé, conteneurs
  healthy ; le double verrou ADR-002 (DEMO_MODE sans I_KNOW en production)
  a refusé de démarrer — observé en situation réelle
- prisma passe en dépendance de production (migrations au boot)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
pr-daaif
2026-07-15 22:58:42 +01:00
parent 36de93bb7e
commit ce24d9c32b
13 changed files with 381 additions and 6 deletions

39
apps/api/Dockerfile Normal file
View File

@@ -0,0 +1,39 @@
# SIOP V2 — image API (NestJS + Prisma).
# Contexte de build : RACINE du monorepo (docker build -f apps/api/Dockerfile .)
# Étage 1 : dépendances + builds ; étage 2 : runtime minimal (node:24-slim).
FROM node:24-slim AS builder
RUN corepack enable
WORKDIR /repo
# Manifestes d'abord (cache de couche pour pnpm install)
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./
COPY packages/shared/package.json packages/shared/package.json
COPY apps/api/package.json apps/api/package.json
RUN pnpm install --frozen-lockfile --filter @siop/api --filter @siop/shared
COPY packages/shared packages/shared
COPY apps/api apps/api
RUN pnpm --filter @siop/shared build \
&& pnpm --filter @siop/api prisma:generate \
&& pnpm --filter @siop/api build \
&& pnpm --filter @siop/api deploy --legacy --prod /out
# Client Prisma regénéré DANS l'arborescence déployée (node_modules à plat)
RUN cd /out && ./node_modules/.bin/prisma generate \
&& cp -r /repo/apps/api/dist /out/dist
FROM node:24-slim
# openssl : requis par les moteurs Prisma
RUN apt-get update \
&& apt-get install -y --no-install-recommends openssl ca-certificates \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /app
ENV NODE_ENV=production
COPY --from=builder --chown=node:node /out /app
COPY --chown=node:node apps/api/docker-entrypoint.sh ./docker-entrypoint.sh
RUN chmod +x docker-entrypoint.sh
USER node
EXPOSE 3000
HEALTHCHECK --interval=30s --timeout=3s --start-period=20s --retries=3 \
CMD node -e "fetch('http://localhost:3000/health').then((r)=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))"
ENTRYPOINT ["./docker-entrypoint.sh"]