# RootNode Platform API — lightweight, no k3s, no --privileged, no Lab terminal runtime. # This is the fix for the Phase 2A "identity" instance problem: that was a full, # --privileged Lab image booting a k3s cluster nobody used, just to serve roster/curriculum/ # progress APIs. This image never runs k3s and needs no elevated privileges at all. # # Built from the REPO ROOT as build context (see platform/docker-compose.dev.yml's # `context: .. / dockerfile: platform/api/Dockerfile`), because it needs read-only access to # scenarios/ and the frontend source — both live outside platform/api/'s own directory. # # Multi-stage: the root .dockerignore excludes frontend/dist/ from every build context (it's a # build artifact, and the main Lab image always builds it fresh — see that Dockerfile's # node-pty fix commit for why leaking host-built artifacts into an image is actively # dangerous). Rather than special-case that, this image builds the frontend fresh too, the # same way the Lab image does, then discards the Node/npm frontend toolchain from the final # stage — the running image only ever needs the static output. FROM node:20-slim AS frontend-build WORKDIR /fe COPY frontend/package.json frontend/vite.config.js ./ RUN npm install COPY frontend/ ./ RUN npm run build FROM node:20-slim WORKDIR /app COPY platform/api/package.json ./ RUN npm install --production COPY platform/api/src/ ./src/ COPY platform/api/migrations/ ./migrations/ COPY platform/api/migrate-sqlite.js ./ # Read-only curriculum content — same source the Lab image ships, needed here purely for # listing/progress-shaping (never executed; setup/validate/teardown stay Lab-only). COPY scenarios/ ./scenarios/ # Platform-shell + admin frontend, built in the stage above — served statically, no nginx # needed for a lightweight Node API+static server. COPY --from=frontend-build /fe/dist/ /frontend-dist/ ENV FRONTEND_DIST_DIR=/frontend-dist EXPOSE 4300 CMD ["node", "src/server.js"]