# Versionsstempel (quick-260914-ku1): die Werte setzt .gitea/scripts/publish-images.sh # per --build-arg; lokal greifen die Vorgaben (dev). Ein globales ARG liefert nur die # Vorgabe -- jede nutzende Stufe wiederholt deshalb `ARG NAME` ohne Wert. ARG APP_VERSION=dev ARG APP_CHANNEL=dev ARG APP_COMMIT= ARG APP_BUILD_TIME= FROM node:24-alpine AS base RUN corepack enable && corepack prepare pnpm@9 --activate FROM base AS deps WORKDIR /app COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./ COPY apps/api/package.json ./apps/api/ COPY packages/shared/package.json ./packages/shared/ RUN pnpm install --frozen-lockfile --filter=@tessera/api... FROM base AS builder WORKDIR /app COPY --from=deps /app/ ./ COPY apps/api/ ./apps/api/ COPY packages/shared/ ./packages/shared/ COPY tsconfig.base.json ./ RUN pnpm --filter=@tessera/api exec prisma generate RUN pnpm --filter=@tessera/api build # quick-261009-p0m: Laufzeit-Abhaengigkeiten ohne Entwicklungswerkzeuge. Eigene Stufe, # weil der Ordnername von @prisma/client im pnpm-Speicher von den aufgeloesten # Peer-Paketen abhaengt: der Prisma-Client wird deshalb HIER erzeugt (postinstall von # apps/api, braucht das Schema vor der Installation) und samt Ordner uebernommen, # statt einen Pfad aus der Builder-Stufe fest einzutragen. FROM base AS prod-deps WORKDIR /app COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./ COPY apps/api/package.json ./apps/api/ COPY packages/shared/package.json ./packages/shared/ COPY apps/api/prisma ./apps/api/prisma/ RUN pnpm install --frozen-lockfile --prod --filter=@tessera/api... # Der Prisma-Client entsteht im postinstall von apps/api, der Fehler verschluckt # (`prisma generate || true`). Deshalb hier noch einmal ausdruecklich erzeugen und pruefen: # fehlt der Client, scheitert der Bau -- statt eines Abbilds, das erst beim Start stirbt. RUN apps/api/node_modules/.bin/prisma generate --schema apps/api/prisma/schema.prisma \ && find node_modules/.pnpm -path '*/.prisma/client/index.js' | grep -q . # quick-261009-p0m: Laufzeitstufe direkt vom Node-Abbild (ohne das vorbereitete pnpm # der Stufe base). Die Paketverwaltungen des Node-Abbilds (npm, npx, corepack, yarn) # werden gleich als Erstes entfernt -- im Betrieb installiert nichts nach. FROM node:24-alpine AS runner WORKDIR /app ENV NODE_ENV=production ARG APP_VERSION ARG APP_CHANNEL ARG APP_COMMIT ARG APP_BUILD_TIME ENV APP_VERSION=$APP_VERSION APP_CHANNEL=$APP_CHANNEL APP_COMMIT=$APP_COMMIT APP_BUILD_TIME=$APP_BUILD_TIME # Die Ordner-/Dateinamen werden mit Platzhaltern gesucht (yarn-v1.22.22 wechselt mit dem # Node-Abbild); die letzte Zeile laesst den Bau scheitern, falls eines der Werkzeuge # bleibt -- sonst verpufft die Absicherung still bei einem neuen Basisabbild. RUN rm -rf /usr/local/lib/node_modules/npm /usr/local/lib/node_modules/corepack /opt/yarn* \ /usr/local/bin/npm /usr/local/bin/npx /usr/local/bin/corepack /usr/local/bin/yarn* \ && for c in npm npx corepack yarn yarnpkg; do \ if command -v "$c" >/dev/null 2>&1; then echo "FEHLER: $c ist noch im Abbild" >&2; exit 1; fi; \ done \ && [ -z "$(ls -d /opt/yarn* /usr/local/lib/node_modules/npm /usr/local/lib/node_modules/corepack 2>/dev/null)" ] \ && node --version RUN addgroup --system --gid 1001 nestjs && \ adduser --system --uid 1001 nestjs && \ mkdir -p /app/user-files && \ chown nestjs:nestjs /app/user-files COPY --from=prod-deps /app/package.json /app/pnpm-workspace.yaml /app/pnpm-lock.yaml ./ COPY --from=prod-deps /app/node_modules ./node_modules COPY --from=prod-deps /app/apps/api/node_modules ./apps/api/node_modules COPY --from=prod-deps /app/apps/api/package.json ./apps/api/ COPY --from=prod-deps /app/packages/shared/package.json ./packages/shared/ COPY --from=builder /app/apps/api/dist ./apps/api/dist COPY --from=builder /app/apps/api/prisma ./apps/api/prisma COPY --from=builder /app/packages/shared/src ./packages/shared/src COPY apps/api/scripts ./apps/api/scripts # Kopfbild der Willkommensmail (MailService.loadWelcomeHeaderPng liest # apps/api/assets/mail/welcome-header.png relativ zu dist/mail/). COPY apps/api/assets ./apps/api/assets # Desktop-Pakete (Phase 18, D-08): im CI legt desktop-collect.sh Pakete + # manifest.json in diesen Ordner, lokal liegt nur der Platzhalter. Nur # lesend zur Laufzeit -- kein chown noetig. COPY desktop-dist ./desktop-dist USER nestjs EXPOSE 3001 CMD ["sh", "apps/api/scripts/migrate-and-start.sh"]