c1d7f41b59
M11.1 — /[slug]/catalog page renders the live catalog from tenant-registry,
gates already-owned products with an 'Active' chip, and exposes two
server actions per remaining card:
- Request → POST /v1/catalog/request (emits an audit event; sales
follow-up flow will pick this up when M8.x lands ERPNext + the
Lead webhook)
- Start 14-day trial → POST /v1/catalog/trial-request (provisions
the entitlement immediately; 14-day expiry per M4.2)
Flash banner on success/error (?ok= / ?err= query params).
M12.1 — Public /start route. Server action calls
createTenant({slug, name, plan, admin_email}) → tenant-registry's
KC-aware POST /v1/tenants → user lands at /<slug>/dashboard. The
dashboard now renders a trial-days-left banner when status=trial
and trial_ends_at is set (urgent styling when ≤3 days remain).
Library:
src/lib/tenant-registry.ts widened from one-call client to the
full read+mutate surface (fetchCatalog, fetchEntitlements,
requestProduct, startTrial, createTenant). Returns typed
{ok: true, ...} | {ok: false, error: '...'} so server actions
branch cleanly. 22 vitest cases, 100% line+branch+function
coverage of src/lib/.
Catalog tests rely on the mock-fetch pattern; the user-visible
flow is exercised by Playwright when the dev stack is up.
Refs: M11.1 + M12.1