Feat/deploy container image #48

Merged
Zayin_Admin merged 3 commits from feat/deploy-container-image into main 2026-10-02 01:16:21 +00:00
2 changed files with 15 additions and 5 deletions
Showing only changes of commit 4468335e8f - Show all commits
+6 -4
View File
@@ -54,10 +54,12 @@ FROM toolchain AS build
COPY . . COPY . .
RUN --mount=type=cache,id=ekklesia-pnpm-store,target=/pnpm/store \ RUN --mount=type=cache,id=ekklesia-pnpm-store,target=/pnpm/store \
pnpm install --frozen-lockfile --store-dir /pnpm/store pnpm install --frozen-lockfile --store-dir /pnpm/store
# The same gates `pnpm verify` runs for modules and migrations, against exactly the module set in this # The same gates `pnpm verify` runs for boundaries, modules, and migrations, against exactly the
# context. Each script builds first; the final build is a Turbo cache hit that keeps the intent # module set in this context. `pnpm boundaries` comes first and reads only sources: among its rules,
# explicit. # a module that imports something at run time without declaring it a production dependency fails
RUN pnpm modules:validate && pnpm migrations:validate && pnpm build # here, because the production-only install below would leave it unresolvable at API startup. Each
# validate script builds first; the final build is a Turbo cache hit that keeps the intent explicit.
RUN pnpm boundaries && pnpm modules:validate && pnpm migrations:validate && pnpm build
# What the runtime resolves at startup, at the paths it resolves them from: # What the runtime resolves at startup, at the paths it resolves them from:
# - every workspace package's `dist/` (every package exports only from `dist/`), which includes # - every workspace package's `dist/` (every package exports only from `dist/`), which includes
# the Dashboard and display host assets under `surfaces/shell/dist/browser/`; # the Dashboard and display host assets under `surfaces/shell/dist/browser/`;
+9 -1
View File
@@ -27,7 +27,7 @@ this file.
| `base` | `node:24.18.0-trixie-slim`, pinned by its multi-architecture index digest. Debian, so glibc, because module dependencies such as sharp ship glibc prebuilt binaries. Every stage starts here. | | `base` | `node:24.18.0-trixie-slim`, pinned by its multi-architecture index digest. Debian, so glibc, because module dependencies such as sharp ship glibc prebuilt binaries. Every stage starts here. |
| `toolchain` | Enables pnpm through Corepack, at exactly the root `packageManager` version. | | `toolchain` | Enables pnpm through Corepack, at exactly the root `packageManager` version. |
| `manifests` | Collects the lockfile, workspace configuration, `.npmrc`, and every workspace `package.json` at its repository path. | | `manifests` | Collects the lockfile, workspace configuration, `.npmrc`, and every workspace `package.json` at its repository path. |
| `build` | `pnpm install --frozen-lockfile`, then `pnpm modules:validate`, `pnpm migrations:validate`, and `pnpm build`, against exactly the modules in the context. Never uses host `node_modules`: `.dockerignore` excludes them. | | `build` | `pnpm install --frozen-lockfile`, then `pnpm boundaries`, `pnpm modules:validate`, `pnpm migrations:validate`, and `pnpm build`, against exactly the modules in the context. Never uses host `node_modules`: `.dockerignore` excludes them. |
| `prod-deps` | The same lockfile with `--prod`: production dependencies only. | | `prod-deps` | The same lockfile with `--prod`: production dependencies only. |
| `runtime` | Production dependencies plus built outputs, owned by root and run as the unprivileged `node` user (uid 1000). No pnpm, no compiler, no curl. | | `runtime` | Production dependencies plus built outputs, owned by root and run as the unprivileged `node` user (uid 1000). No pnpm, no compiler, no curl. |
@@ -62,6 +62,14 @@ set `DOCKER_BUILDKIT=1` if your Docker CLI has no buildx plugin.
No secret is a build argument, and none enters any layer. `.env` files are excluded from the build No secret is a build argument, and none enters any layer. `.env` files are excluded from the build
context entirely, and no registry credentials are needed. context entirely, and no registry credentials are needed.
**A module missing a production dependency fails the build, not the API.** The runtime receives
production dependencies only, so a module that imports a package at run time but declares it only
as a development or peer dependency would build and then fail at startup. `pnpm boundaries` runs
in the build stage and rejects that module first
(`runtime-imports-are-production-dependencies`, see
[Repository boundaries](../docs/architecture/repository-boundaries.md)). The same applies to every
other boundary rule: a module the platform's own CI would reject cannot be built into an image.
**A platform-only image does not exercise native module dependencies.** With no modules in the **A platform-only image does not exercise native module dependencies.** With no modules in the
context, nothing like sharp is installed, so the CI image build proves nothing about them. An context, nothing like sharp is installed, so the CI image build proves nothing about them. An
instance build that includes such a module must smoke-test the built image itself: start it, instance build that includes such a module must smoke-test the built image itself: start it,