Add spa flag for static deployments; fix Hugo navigation

Static (manager: caddy) deployments always emitted the SPA fallback
`try_files {path} /index.html`, which serves the root index.html for
every unmatched path. That's correct for React/Vite apps but swallows a
multi-page content site's in-page links back to the homepage, so a Hugo
site (payne.io) couldn't navigate off its landing page.

Add an explicit `spa: bool` on CaddyDeployment (default True, preserving
existing SPA behavior). When False, the gateway serves plain file_server
— resolving directory indexes (/posts/ -> /posts/index.html) and 404ing
missing paths. Threaded through the registry snapshot + mesh and the
route computation so both the internal wildcard and public apex blocks
honor it. `castle program create --stack hugo` now sets spa: false.
This commit is contained in:
2026-07-12 23:41:47 -07:00
parent 1767a0a304
commit d152e79cee
6 changed files with 58 additions and 24 deletions

View File

@@ -41,6 +41,11 @@ STACK_BUILD_OUTPUTS: dict[str, str] = {
"hugo": "public",
}
# Stacks whose static output is a multi-page content site (not a single-page app):
# the gateway resolves directory indexes and 404s missing paths instead of falling
# back to the root index.html. See CaddyDeployment.spa.
CONTENT_SITE_STACKS: set[str] = {"hugo"}
# Substrate a stack's apps depend on — seeded as a deployment `requires` at creation
# so the relationship graph shows it. This keeps `stack` uncoupled from the runtime
# model: the stack declares the edge once here; the graph only ever reads the encoded
@@ -142,6 +147,7 @@ def run_create(args: argparse.Namespace) -> int:
manager="caddy",
program=name,
root=static_root or "dist",
spa=stack not in CONTENT_SITE_STACKS,
description=description,
requires=seeded_requires,
)