Root cause: the runner stage copied /app/node_modules (the pnpm
content-addressed .pnpm store) instead of apps/gateway/node_modules
(which holds the symlinks Node.js uses to resolve packages relative
to the gateway entrypoint). In a stripped image without pnpm's virtual
store topology, dotenv and every other dep were unresolvable, causing
ERR_MODULE_NOT_FOUND on startup.
Fix: replace the broken node_modules copy with `pnpm deploy --legacy`
which produces a flat, self-contained node_modules at /deploy — no
workspace symlinks required. Also corrected the filter name (@mosaic/gateway
→ @mosaicstack/gateway), added COPY plugins/ to the pre-install step so
turbo's dependency graph can resolve the telegram/discord plugins that
are workspace deps of the gateway, and switched the build step to
`pnpm turbo run build --filter @mosaicstack/gateway...` so all
transitive workspace packages are compiled in topological order before
the gateway.
Verification: local build succeeded (image sha256:dd44b49b5cf49bafd91f8733792b25b08a4711d2ee1bb278460aea747c305bd0,
~254 MB). Running the image with stub env reaches Postgres connection
error (TierDetectionError: postgres unreachable at nope:5432) — dotenv
loads cleanly, past module resolution. No ERR_MODULE_NOT_FOUND.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>