# Built from the REPO ROOT context (see docker-compose.yml: build.context: .) # so the pnpm workspace manifest + lockfile are available for a deterministic, # workspace-aware install. apps/api is one package in the pnpm workspace. FROM node:22-alpine AS base WORKDIR /app RUN corepack enable pnpm # Install layer: copy only manifests + lockfile first for cache efficiency. # Both workspace package.json files are needed so --frozen-lockfile can validate # every importer in pnpm-lock.yaml. pnpm-workspace.yaml carries allowBuilds.esbuild. FROM base AS builder COPY pnpm-workspace.yaml pnpm-lock.yaml package.json ./ COPY apps/api/package.json ./apps/api/ COPY apps/pwa/package.json ./apps/pwa/ RUN pnpm install --frozen-lockfile --filter @familysync/api... COPY apps/api ./apps/api RUN pnpm --filter @familysync/api build FROM base AS dev WORKDIR /app/apps/api COPY --from=builder /app /app CMD ["node", "--watch", "dist/index.js"] # PWA build stage — produces apps/pwa/dist (relative API paths, env-agnostic). # Runs in parallel with `builder` under BuildKit; output is copied into the # production image's ./public so the API serves the PWA on the same port (:3000). FROM base AS pwa-builder COPY pnpm-workspace.yaml pnpm-lock.yaml package.json ./ COPY apps/api/package.json ./apps/api/ COPY apps/pwa/package.json ./apps/pwa/ RUN pnpm install --frozen-lockfile --filter @familysync/pwa... COPY apps/pwa ./apps/pwa RUN pnpm --filter @familysync/pwa build FROM base AS production COPY pnpm-workspace.yaml pnpm-lock.yaml package.json ./ COPY apps/api/package.json ./apps/api/ COPY apps/pwa/package.json ./apps/pwa/ RUN pnpm install --frozen-lockfile --prod --filter @familysync/api... COPY --from=builder /app/apps/api/dist ./apps/api/dist WORKDIR /app/apps/api # Enforce production identity — engages the NODE_ENV=production hard guard # in devBypass.ts, preventing dev-bypass activation even if DEV_AUTH_BYPASS # is accidentally set in the container environment. (D-07) ENV NODE_ENV=production # PWA static assets built from apps/pwa and served by this API from ./public # (single-port deployment for the Pangolin/newt tunnel). serveStatic resolves # ./public relative to the runtime CWD, which is this WORKDIR (/app/apps/api). COPY --from=pwa-builder /app/apps/pwa/dist ./public CMD ["node", "dist/index.js"]