# 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"] 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 # PWA static assets (apps/pwa) are built and served separately; /health works # without them and the catch-all static route 404s gracefully. CMD ["node", "dist/index.js"]