doxa-maps/serving/traefik-embed-headers.yaml
doxa-maps-88655c70 3a2cf0e8f2 Research Gallery: embed on someone else's page, in both modes
The gallery is going onto the DX-life research page, and nothing had tried
it on a page it didn't generate. From a second origin, a bare
<script> + <doxa-maps-spa> drew over the host's header, and 8 of 13 tabs
showed an error card.

Three causes, each fixed in the shell:

- No :host box. The layout root is position:absolute, so it anchored to the
  viewport instead of the element. :host is now a positioned block with a
  default height the host can override.
- A foreign page sets none of the globals a leaf page bakes. Every data call
  hit the host's own origin and got HTML back. The manifest now publishes a
  `runtime` block (apiBaseUrl + the public token every leaf already carries).
  The shell fills window.MAP_APP_API_URL / window.MAP_TOKEN only when the page
  hasn't set them, and forwards tk in profile-config.
- Nested elements resolved assets to <tree>/../assets, a sibling pool the
  publisher doesn't ship (404 live). The shell now forwards an absolute
  <tree>/assets. This also fixes the iframe mode, where Cities with Internet
  and Gospel Resources were failing the same way.

Also adds a `tab` attribute (plus ?tab=) to deep-link into one map, and a
`tab-change` event for the host.

check:gallery-embed drives every tab in both modes from a second origin. It
passes here and fails on the previous tree (7 findings).

EMBED.md documents the contract. The Traefik template now sends CORS for the
whole tree: live manifest.json answers without Access-Control-Allow-Origin.
2026-09-24 19:03:37 +00:00

33 lines
1.6 KiB
YAML

# Traefik dynamic-config reference: the doxa-maps frame-policy split
# (documentation/architecture/embeddability.md). Adjust host/service names to your deploy.
# Direct-embed pages (>=2 path segments under the tree) must be framable anywhere;
# staging pages stay preview-only. frame-ancestors is header-only, so the proxy
# owns this — the bundler can only document and template it.
#
# CORS (added 2026-09-24): the WHOLE tree must send Access-Control-Allow-Origin, not only the
# embed pages. A composed surface (the cap-5 Research Gallery, cap-4 composites) mounted by
# <script> on a partner page fetch()es manifest.json at the tree ROOT and assets/ after it mounts,
# and fetch() enforces CORS. Measured live: manifest.json answered 200 with NO ACAO (it sits one
# segment deep, outside the embed-pages rule), so every gallery tab would fail on doxa.life.
http:
middlewares:
doxa-maps-cors:
headers:
accessControlAllowOriginList: ["*"]
accessControlAllowMethods: ["GET", "HEAD", "OPTIONS"]
doxa-maps-embed-framable:
headers:
customResponseHeaders:
Content-Security-Policy: "frame-ancestors *"
X-Frame-Options: ""
routers:
doxa-maps-embed-pages:
rule: "PathRegexp(`^/doxa-maps/[^/]+/[^/]+/`)"
priority: 70 # above the site catch-all
middlewares: [doxa-maps-embed-framable, doxa-maps-cors]
service: your-static-service
doxa-maps-tree:
rule: "PathPrefix(`/doxa-maps/`)"
priority: 60 # below the embed-pages router, above the site catch-all
middlewares: [doxa-maps-cors]
service: your-static-service