Root cause: componentGroups.ts hardcoded `/component-logos/<id>.svg`. The
catalyst-ui SPA is served at the Vite base `/sovereign/`, so the browser
fetches `/component-logos/...` (no prefix), which Traefik routes to the
website ingress, not catalyst-ui — every logo 404'd and the IconFallback
letter avatar took over for all 63 cards.
Fix: derive logo URLs from `path()` in shared/config/urls.ts, which reads
`import.meta.env.BASE_URL`. Vite injects the base at build time
(`/sovereign/` in prod, `/` in dev/test) so the URL stays in sync with
`vite.config.ts` and the ingress without any hardcoded prefix
(INVIOLABLE PRINCIPLE #4).
Also:
- powerdns.svg was never vendored — set logoUrl: null so the wizard
renders the letter-mark fallback for that one card by design.
- Add Vitest coverage for the null-logoUrl fallback path (PowerDNS).
- Add CI smoke step that asserts /component-logos/<id>.svg returns 200
for 11 representative components so a missing or mis-cased vendored
SVG fails the build, not the user.
- Document the logo path convention in a docblock at the top of
componentGroups.ts so future devs can't reintroduce a hardcoded path.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>