Closes openova#169.
Wizard UI:
- New StepDomain.tsx with three radio modes (pool / BYO manual NS / BYO
registrar API). Pool flow unchanged from #163. BYO-manual surfaces the
three OpenOva nameservers (ns1-3.openova.io) verbatim with copy buttons.
BYO-api adds a registrar dropdown (Cloudflare, Namecheap, GoDaddy, OVH,
Dynadot) + token field + Validate button — read-only validation hits
/api/v1/registrar/{r}/validate before Next is enabled.
- StepOrg trimmed to org-only fields (domain capture moved to StepDomain).
- WizardPage + WizardLayout add the new "Domain" step (now 7 steps total).
Wizard store:
- DomainMode expanded to 'pool' | 'byo-manual' | 'byo-api' with legacy
'byo' coerced to 'byo-manual' on rehydrate.
- New fields: registrarType (RegistrarType | null), registrarToken,
registrarTokenValidated.
- partialize() strips registrarToken + registrarTokenValidated from
localStorage (credential hygiene per docs/INVIOLABLE-PRINCIPLES.md #10).
- setSovereignDomainMode cascades a clean reset of irrelevant fields.
PDM (core/pool-domain-manager):
- New endpoint POST /api/v1/registrar/{registrar}/validate — read-only
twin of /set-ns. Calls adapter.ValidateToken; never flips NS records.
Maps registrar errors to canonical HTTP statuses (401/403/429/502).
Token never enters a logged struct.
catalyst-api (products/catalyst/bootstrap/api):
- New handler/registrar.go — thin proxy that forwards
/api/v1/registrar/{r}/{validate|set-ns} to PDM's matching endpoint,
reading the body once and streaming PDM's response status + body
verbatim so the wizard's error-mapping vocabulary stays consistent.
Tests:
- StepDomain.test.tsx — 18 vitest cases covering all three modes,
mode-switch field cleanup, validate fetch happy/error paths, token
invalidation on edit.
- store.test.ts — wizard-store mutations + persist hygiene.
- StepSuccess.test.tsx — fixture updated 'byo' -> 'byo-manual'.
- registrar_test.go (PDM) — 7 new test cases for /validate covering
happy, invalid-token, domain-not-in-account, unsupported-registrar,
missing-fields, bad-JSON, response-doesnt-leak-token.
103 vitest cases pass. Go tests pass for both PDM and catalyst-api.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>