# GoSec My UI — Production Dockerfile # # Build context MUST be the monorepo root (/srv/k8s): # podman build -f web/gscMy/Dockerfile -t gsc-my-ui /srv/k8s # Mirrors web/gscAdmin/Dockerfile. # Stage 1: Builder. FROM node:22-alpine AS builder RUN apk add --no-cache libc6-compat openssl # @limitless/ui — build dist/ first. COPY templates/limitless-ui /srv/k8s/templates/limitless-ui WORKDIR /srv/k8s/templates/limitless-ui RUN npm install --no-audit --no-fund && npm run build # @gsc/web-kit — build dist/, drop bundled next-intl/next-auth so they # resolve from this app's tree (React-context unity). COPY templates/gsc-web-kit /srv/k8s/templates/gsc-web-kit WORKDIR /srv/k8s/templates/gsc-web-kit RUN npm install --no-audit --no-fund && npm run build && \ rm -rf node_modules/next-intl node_modules/next-auth # @gsc/chat — dist/ is gitignored; build in place. COPY infra/gscAICoreSystem/frontends/gscBicameralFrontend /srv/k8s/infra/gscAICoreSystem/frontends/gscBicameralFrontend WORKDIR /srv/k8s/infra/gscAICoreSystem/frontends/gscBicameralFrontend RUN npm install --no-audit --no-fund && npm run build # Make @gsc/chat resolvable from inside @gsc/web-kit. RUN mkdir -p /srv/k8s/templates/gsc-web-kit/node_modules/@gsc && \ ln -sfn ../../../../infra/gscAICoreSystem/frontends/gscBicameralFrontend \ /srv/k8s/templates/gsc-web-kit/node_modules/@gsc/chat # gscMy — package.json + prisma schema first so postinstall finds it. WORKDIR /srv/k8s/web/gscMy COPY web/gscMy/package.json web/gscMy/package-lock.json* ./ COPY web/gscMy/prisma ./prisma RUN npm install --no-audit --no-fund --no-package-lock # Link this app's next-intl + next-auth into the kit's node_modules # so the kit's compiled chrome shares the same module instances. RUN ln -sfn ../../../web/gscMy/node_modules/next-intl \ /srv/k8s/templates/gsc-web-kit/node_modules/next-intl && \ ln -sfn ../../../web/gscMy/node_modules/next-auth \ /srv/k8s/templates/gsc-web-kit/node_modules/next-auth # Rest of source. COPY web/gscMy/. ./ ARG NEXT_PUBLIC_APP_URL=https://my.gosec.internal ENV NEXT_PUBLIC_APP_URL=$NEXT_PUBLIC_APP_URL ENV NEXT_TELEMETRY_DISABLED=1 # Strip local-dev env so it doesn't bake into the image (esp. AUTH_URL # pointing at my.gosec.cloud:3000). RUN rm -f .env .env.local .env.development.local .env.production.local RUN npm run build # Stage 2: Runtime FROM node:22-alpine AS runner RUN apk add --no-cache openssl WORKDIR /app ENV NODE_ENV=production ENV NEXT_TELEMETRY_DISABLED=1 # outputFileTracingRoot=/srv/k8s preserves the web/gscMy subtree in the # standalone bundle, so server.js lands at /app/web/gscMy/server.js. COPY --from=builder --chown=node:node /srv/k8s/web/gscMy/.next/standalone ./ COPY --from=builder --chown=node:node /srv/k8s/web/gscMy/public ./web/gscMy/public COPY --from=builder --chown=node:node /srv/k8s/web/gscMy/.next/static ./web/gscMy/.next/static USER node EXPOSE 3000 ENV PORT=3000 HOSTNAME=0.0.0.0 ENTRYPOINT ["node", "web/gscMy/server.js"]