Phase 1 + 2 + 3 — MVP → partner hardening → scale

Embeddable conversion core: design a campaign, embed it anywhere, turn submissions into classified inquiries.

One portable campaign JSON is the contract between Studio, the Campaign Service, and the Loader — so the same campaign renders in the OneHub app today and on a partner site in Phase 2 without a rewrite.

Studio (builder)

GrapesJS + OneHub tokens

Campaign Service

Next.js route handlers + store

Loader SDK

Vanilla TS, Shadow DOM, 9.4 KB

Lead pipeline

submission → inquiry → ingest

Analytics

PostHog events (view/interact/submit)

Multi-tenancy

per-partner keys + origin allowlist

A/B + dashboards

sticky variants, per-partner self-serve

The core loop

  1. 1Marketer builds a form / popup in Studio (GrapesJS) — no engineer.
  2. 2Publish → an immutable campaign version is frozen server-side.
  3. 3Loader fetches it and renders inside an isolated Shadow DOM.
  4. 4Visitor submits → /api/submit stores it and fires form_submit.
  5. 5Pipeline normalizes it into an inquiry and ingests it (classified + tagged to workspace).
  6. 6view / interact / submit land in PostHog → conversion baseline.

Current configuration

Storage
Postgres
Analytics (PostHog)
no-op (console)
Inquiry pipeline
no-op (stored + logged)
Campaign schema
v0 (portable JSON)
Loader isolation
Shadow DOM (+ iframe fallback)
Cross-origin
per-partner key + origin allowlist
Campaign types
inline · modal · slide-in · sticky
Experiments
A/B variants (sticky, per-visitor)

All integrations are optional in Phase 1. With nothing configured the app runs on a local file store and logs analytics/inquiries to the console — copy .env.example to .env.local to wire the real services.