AI-assisted HTML email design studio. Chat with Claude to design rich, campaign-grade
HTML emails — with AI-generated images (Imagen) and video (Veo 3) — then send them, schedule
them, embed live polls, and track results. Output is tuned to render beautifully in
Apple Mail (semantic system colors for automatic dark mode, CSS-only interactivity,
native <video> support) while staying compatible with other clients.
Bring your own keys. AI features run on your Anthropic key (design chat) and your Google AI Studio key (image/video generation). Keys travel per-request as headers and are never persisted server-side.
- AI design chat — Claude generates and surgically edits email HTML/CSS, with intent-aware editing (edit vs. replace vs. redesign) and structure-preserving rules
- AI media — request images (Imagen 4) and videos (Veo 3.x) inline; optimistic shimmer placeholders hot-swap when generation completes
- Visual editor — Shadow-DOM preview canvas, drag-and-drop sections, inline toolbar, Monaco code editor, snippet library
- Data-to-email skill — drop a CSV/PDF/XLSX/JSON/Markdown file on the chat and get a status dashboard, KPI grid, timeline, or transcript summary email
- Send pipeline — CID-embedded images and videos (Apple Mail plays
<video src="cid:…">natively), fail-loud on missing assets, send preflight, per-user rate limiting - Campaigns — scheduled & recurring sends, recipient lists, embedded polls with one-click signed vote links, send analytics
- Teams & RBAC — every template/list/schedule/poll is team-scoped; personal team auto-created per user; owner/member roles; team invites
- Admin — audit log, send history, security alerts, AI token usage telemetry
Next.js 15 · React 19 · TypeScript · Tailwind + Radix/shadcn · Zustand · Drizzle ORM + Postgres · Anthropic SDK (Claude) · Gemini API (Imagen + Veo) · nodemailer · Puppeteer screenshots · Vitest + Playwright
Prereqs: Node 20+, Docker, Supabase CLI.
# 1. Database (local Postgres on :54322 via Supabase CLI)
supabase start
# 2. App
cd application
cp .env.example .env.local # defaults work out of the box
npm install
npm run db:migrate # apply Drizzle migrations
# 3. Local mailbox — sent emails land here instead of the real world
docker run -d -p 1025:1025 -p 8025:8025 axllent/mailpit
# 4. Run
npm run dev # → http://localhost:3000Local dev uses open mode (SUPERCOMPOSER_OPEN_MODE=true): a mock user, no auth
proxy needed. Sent emails appear at http://localhost:8025 (Mailpit).
| Feature | Key | Where to get it |
|---|---|---|
| Design chat | ANTHROPIC_API_KEY |
console.anthropic.com |
| Image + video gen | GEMINI_API_KEY |
aistudio.google.com |
Add keys in-app via the key icon in the chat header — they're stored only in your
browser's localStorage and sent per-request as x-anthropic-key / x-gemini-key
headers. For local dev you can also set them in .env.local. Bonus: with no key set
in dev, chat falls back to your authenticated claude CLI if installed (text-only).
├── application/ # Next.js App Router app
│ ├── app/
│ │ ├── api/ # 60+ API routes (templates, send, schedule, polls, teams, admin, chat, …)
│ │ ├── admin/ # Admin dashboard (super-admin only)
│ │ ├── components/ # React components (editor, gallery, teams, chat, …)
│ │ ├── store/ # Zustand state (editorStore)
│ │ └── lib/
│ │ ├── db/ # Drizzle schema (single source of truth)
│ │ ├── dal/ # Data access: templates, revisions, sendLog, auditLog,
│ │ │ # recipientLists, scheduledSends, polls, teams, …
│ │ ├── teamAuth.ts # Route-level team membership gate
│ │ ├── emailPipeline.ts # CID embed, fail-loud on missing assets
│ │ └── skills/ # data-to-email skill prompt + detection
│ ├── e2e/ # Playwright E2E tests
│ ├── drizzle/ # Generated SQL migrations
│ └── Dockerfile
├── supabase/ # Local Supabase CLI config
├── samples/ # Drag-and-drop sample data for the data-to-email skill
└── CLAUDE.md # Project constitution (rules, architecture, conventions)
Browser ──→ Next.js App
├── Middleware (CSRF origin check + 50MB size limit)
├── App Router (editor, gallery, /admin) + 60+ API routes
├── ShadowPreview (email canvas in Shadow DOM)
├── /api/chat ──→ Anthropic API (user's key)
│ └──→ Gemini API: Imagen images + Veo videos (user's key)
├── Team gate (requireTemplateOwner / assertRowTeamAccess)
├── DAL ──→ Drizzle ──→ Postgres
├── Filesystem (uploads, screenshots)
└── nodemailer ──→ SMTP relay (Mailpit in dev)
- ShadowPreview — renders email HTML in a Shadow DOM for CSS isolation
- buildEmailForSend — assembles final email HTML: inlines CSS, rewrites URLs, optionally inlines images as base64
- Fail-loud sends — if any referenced asset can't be resolved,
/api/sendreturns 422 with the file list; broken images never ship to recipients - DAL — all DB access goes through
app/lib/dal/modules, never raw queries in routes - Team scoping — every list/read/write on team-owned tables passes a membership gate
cd application
npx vitest run # unit tests
npm run test:e2e # Playwright (needs dev server)CI (GitHub Actions) runs typecheck, unit tests, and a production build on every push/PR.
- SSRF protection —
app/lib/urlSafety.tsblocks fetches to private IPs, localhost, link-local, and cloud metadata endpoints - XSS — all HTML rendered via
innerHTMLpasses through DOMPurify - Path traversal — asset serving rejects
..segments at any position - Header injection — sender fields sanitized; subjects reject control characters
- Send policy — optional
ALLOWED_RECIPIENT_DOMAINS/ALLOWED_REPLY_DOMAINSallowlists; non-admin senders are locked to their own identity - Zod validation — every API route validates input at the boundary
- BYOK — AI keys are per-user and per-request; never logged, never stored
The app is a standard Next.js server: npm run build + next start behind any
auth proxy that sets x-oidc-* identity headers, or adapt app/lib/auth.ts to your
auth provider. Dockerfile / Dockerfile.base build a production image with
Chromium + ffmpeg for screenshots and video conversion. Cloud deployment
(Supabase Auth + Storage + hosted Postgres) is on the roadmap.
| Doc | Purpose |
|---|---|
CLAUDE.md |
Project constitution — rules, architecture, conventions |
.claude/docs/CASE_STUDY.md |
Decision log + lessons learned |
.claude/docs/ROADMAP.md |
What's next |
samples/README.md |
Sample data for the data-to-email skill |
MIT