# syntax=docker/dockerfile:1.7
ARG NODE_VERSION=22

FROM node:${NODE_VERSION}-alpine AS builder
RUN apk add --no-cache libc6-compat openssl
RUN corepack enable && corepack prepare pnpm@9 --activate
WORKDIR /repo
# Hoisted layout so `prisma generate` writes to predictable paths
# (/repo/node_modules/{@prisma,.prisma}/) instead of into .pnpm/<hash>/.
# Local dev keeps the isolated layout — this .npmrc only exists in the
# build context.
RUN echo "node-linker=hoisted" > /repo/.npmrc

COPY pnpm-workspace.yaml pnpm-lock.yaml package.json ./
COPY tehriehlbudget-backend/  tehriehlbudget-backend/
COPY tehriehlbudget-frontend/package.json tehriehlbudget-frontend/

RUN --mount=type=cache,id=pnpm-store,target=/root/.local/share/pnpm/store \
    pnpm install --frozen-lockfile --filter tehriehlbudget-backend...

RUN pnpm --filter tehriehlbudget-backend exec prisma generate
RUN pnpm --filter tehriehlbudget-backend run build

# pnpm deploy produces a self-contained prod-only bundle for the backend:
# only the dependencies the runtime actually needs, no frontend tooling,
# no devDeps. Drops vite, vitest, react, the whole NestJS CLI etc. that
# were leaking into the runtime via the workspace's hoisted node_modules.
RUN pnpm --filter tehriehlbudget-backend --prod deploy /deploy

# pnpm deploy pulls a fresh @prisma/client from the pnpm store, which ships
# with an unpopulated `.prisma/client/index.js` stub (it throws "did not
# initialize yet" if loaded). Re-run `prisma generate` against the deploy
# tree so the schema-specific client (enums, models, etc.) lands in
# /deploy/node_modules/.prisma/client. The CLI is a devDep so it's not in
# /deploy — invoke it from /repo where the full install still has it.
RUN cd /deploy && /repo/node_modules/.bin/prisma generate \
    --schema=./prisma/schema.prisma

FROM node:${NODE_VERSION}-alpine AS runtime
RUN apk add --no-cache libc6-compat openssl tini \
    # Remove the npm CLI that ships with node:alpine. We use pnpm via
    # corepack at build time and `node dist/main` at runtime — npm is
    # never invoked. Its bundled deps (cross-spawn, glob, minimatch,
    # tar) are the source of 11 of the 12 HIGH/CRITICAL CVEs Trivy flags
    # in the image, and they're all in code paths we never execute.
 && rm -rf /usr/local/lib/node_modules/npm \
           /usr/local/bin/npm \
           /usr/local/bin/npx
WORKDIR /app
RUN addgroup -S nodeapp && adduser -S nodeapp -G nodeapp
ENV NODE_ENV=production
COPY --from=builder --chown=nodeapp:nodeapp /deploy/ ./
USER nodeapp
EXPOSE 3000
ENTRYPOINT ["/sbin/tini", "--"]
CMD ["node", "dist/main"]
