From 24749de0c717660b728c274e4b7b5cd33a8b896a Mon Sep 17 00:00:00 2001 From: emi Date: Tue, 21 Jul 2026 22:48:59 +0000 Subject: [PATCH] Move static asset + SPA-shell ownership from backend to frontend (repo-split Stage 7a) (#22) --- deploy/Caddyfile | 22 ++++++++++--------- .../templates/Caddyfile.tftpl | 16 ++++++++------ 2 files changed, 21 insertions(+), 17 deletions(-) diff --git a/deploy/Caddyfile b/deploy/Caddyfile index 44d48b0..0d6a31a 100644 --- a/deploy/Caddyfile +++ b/deploy/Caddyfile @@ -14,23 +14,25 @@ # at "/" with no sub-path prefix. Repo-split Stage 4: backend and frontend are # two containers now (docker-compose.yml), each on its own loopback port -- # Caddy path-splits directly to whichever owns a given path, so the browser -# still sees one apparent origin. The exact path list mirrors -# backend/web/app.py's _FRONTEND_ROUTES; everything not listed (API, the -# interactive tool's SPA pages, static assets, /digest, /discord/interactions, -# and the dynamic IndexNow key file) falls through to backend, which also -# carries its own reverse-proxy fallback for the frontend-owned paths -- so a -# gap in this list degrades to "one extra hop", never a 404. +# still sees one apparent origin. Repo-split Stage 7a flipped which side owns +# the enumerated list: frontend now owns everything (content pages, the +# interactive tool's SPA shells, every static asset, the dynamic IndexNow key +# file) except the short, stable set below, which mirrors backend/web/app.py's +# own routing exactly (a single catch-all proxy to frontend for everything +# else) -- unlike frontend's paths, backend's don't grow every time a new +# static asset filename is added. A gap in this list still just degrades to +# "one extra hop" through backend's own proxy fallback, never a 404. thermograph.org { encode zstd gzip - @frontend_paths path / /about /privacy /glossary /glossary/* /climate /climate/* /robots.txt /sitemap.xml + @backend_paths path /api/* /digest /discord/interactions # Active health check on the same cheap /healthz route each container's own # HEALTHCHECK uses (Dockerfile) — so a deploy that's still restarting/booting # never gets proxied into (a reload alone has no gate, hop-1 runbook hazard #10). - handle @frontend_paths { - reverse_proxy 127.0.0.1:8080 { + handle @backend_paths { + reverse_proxy 127.0.0.1:8137 { health_uri /healthz health_interval 5s health_timeout 3s @@ -39,7 +41,7 @@ thermograph.org { } handle { - reverse_proxy 127.0.0.1:8137 { + reverse_proxy 127.0.0.1:8080 { health_uri /healthz health_interval 5s health_timeout 3s diff --git a/terraform/modules/thermograph-host/templates/Caddyfile.tftpl b/terraform/modules/thermograph-host/templates/Caddyfile.tftpl index 4141b09..340bdb7 100644 --- a/terraform/modules/thermograph-host/templates/Caddyfile.tftpl +++ b/terraform/modules/thermograph-host/templates/Caddyfile.tftpl @@ -4,23 +4,25 @@ # # The app owns the domain root and runs with THERMOGRAPH_BASE=/. Repo-split # Stage 4: backend (127.0.0.1:${port}) and frontend (127.0.0.1:${frontend_port}) -# are two containers now -- path-split directly to whichever owns a given path, -# same list backend/web/app.py's own reverse-proxy fallback (for Caddy-less -# hosts) uses, so the two never disagree about who owns what. +# are two containers now -- path-split directly to whichever owns a given +# path. Repo-split Stage 7a flipped which side owns the enumerated list: +# backend owns the short, stable set below (mirrors backend/web/app.py's own +# routing exactly -- a single catch-all proxy to frontend for everything +# else), so the two never disagree about who owns what. # # NOTE: the repo's deploy/Caddyfile additionally serves the emigriffith.dev portfolio # and legacy redirects; those are host-specific and intentionally not templated here. ${domain} { encode zstd gzip - @frontend_paths path / /about /privacy /glossary /glossary/* /climate /climate/* /robots.txt /sitemap.xml + @backend_paths path /api/* /digest /discord/interactions # Active health check on the same cheap /healthz route each container's own # HEALTHCHECK uses (Dockerfile) — so a `docker compose up -d --build` deploy # that's still restarting/booting never gets proxied into (a reload alone has # no gate, hop-1 runbook hazard #10). health_uri is relative to the upstream. - handle @frontend_paths { - reverse_proxy 127.0.0.1:${frontend_port} { + handle @backend_paths { + reverse_proxy 127.0.0.1:${port} { health_uri /healthz health_interval 5s health_timeout 3s @@ -29,7 +31,7 @@ ${domain} { } handle { - reverse_proxy 127.0.0.1:${port} { + reverse_proxy 127.0.0.1:${frontend_port} { health_uri /healthz health_interval 5s health_timeout 3s