Skip to content

feat(shadow): scaffold node-backend blog shadow spoke (WS-5)#216

Draft
Jesssullivan wants to merge 4 commits into
mainfrom
shadow-deploy/node-backend-spoke
Draft

feat(shadow): scaffold node-backend blog shadow spoke (WS-5)#216
Jesssullivan wants to merge 4 commits into
mainfrom
shadow-deploy/node-backend-spoke

Conversation

@Jesssullivan

Copy link
Copy Markdown
Owner

Node-backend blog SHADOW spoke — SCAFFOLD (draft, operator-gated)

Scaffolds a tailnet-only node-backend shadow of the blog without touching production. Per the node-shadow recon ruling (2026-07-05): scaffold now; the production blog stays adapter-static and FROZENtransscendsurvival.org is not touched by this PR.

What this adds (all additive)

  • svelte.config.js — adapter is env-selectable: BLOG_ADAPTER=node@sveltejs/adapter-node; default (and production) stays @sveltejs/adapter-static. adapter-static is not removed; prerender/config for the static path is intact.
  • Containerfile.node — multi-stage node:22-alpine image mirroring the epp adapter-node pattern: tini as PID 1, non-root uid 1000, ENV PORT=3000, EXPOSE 3000, builds with BLOG_ADAPTER=node, runs node build/index.js.
  • src/routes/healthz/+server.tsprerender = false, GET200 {status:'ok'}. Non-prerendered, so it is absent from the frozen static artifact (nothing links it; strict:false) and live only under the node adapter.
  • docs/blog-node-shadow.md — operator surface.
  • @sveltejs/adapter-node added to devDependencies; package-lock.json + pnpm-lock.yaml updated. The pnpm-lock regen also corrects a pre-existing dompurify 3.4.7 → ^3.4.11 range violation (the committed pnpm-lock did not satisfy package.json).

Verification (local)

  • npm run build (default/static path) → exit 0, Using @sveltejs/adapter-static, build/index.html + build/404.html present, no build/index.js. The non-prerendered /healthz endpoint does not break the static build.
  • BLOG_ADAPTER=node npm run buildexit 0, Using @sveltejs/adapter-node, produces build/index.js.

Scope / safety

  • Shadow-only. Production remains adapter-static and FROZEN; the static build output is byte-unchanged.
  • Operator-gated at merge (draft).
  • Infra stack (tofu/stacks/jesssullivan-blog-node-shadow) lands in a sibling jesssullivan-infra draft PR.

Refs WS-5, node-shadow ruling 2026-07-05.

Add an env-selectable SvelteKit adapter so the same source can produce
either the frozen static production artifact (default) or a tailnet-only
node-backend shadow image.

- svelte.config.js: BLOG_ADAPTER=node selects @sveltejs/adapter-node;
  default (and production) stays @sveltejs/adapter-static, unchanged.
- Containerfile.node: multi-stage node:22-alpine image (tini PID 1,
  non-root uid 1000, PORT=3000) that builds with BLOG_ADAPTER=node and
  runs node build/index.js.
- src/routes/healthz/+server.ts: non-prerendered liveness/readiness
  endpoint (200 {status:'ok'}); absent from the static artifact,
  live only under the node adapter.
- docs/blog-node-shadow.md: operator surface.

Shadow-only. Production (transscendsurvival.org) remains adapter-static
and FROZEN; static build output is unchanged. pnpm-lock regeneration
also corrects a pre-existing dompurify 3.4.7 -> ^3.4.11 range violation.

Refs WS-5, node-shadow ruling 2026-07-05.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant