Acceptance Spec — Email / Leads / Sales Funnel
Property: cwa · Registry suite: email-funnel · Created: 2026-06-13
Origin: the 2026-06-13 funnel audit found four silent regressions (From-brand collision, dead delivered_at, no reply capture, invisible engagement). This spec defines what "correct" means at each stage so it stays fixed. Full design + test plan: churchwiseai-web/docs/EMAIL_FUNNEL_SPEC_AND_TESTPLAN.md.
Funnel stages
SOURCE → SEND → DELIVERED → OPENED → CLICKED → DEMO VIEWED → ENGAGED (chat/voice) → REPLIED / BOOKED → CLAIMED → ONBOARDED → PAID
Two parallel models, same stages:
- Church →
outreach_contacts(one row per prospect). - Local business (wiseaiagency) →
leads+campaign_members.
Correctness invariants (MUST hold)
- From / Reply-To isolation — each campaign resolves its sender from its OWN env var; brands never collide:
- Church →
OUTREACH_DEMO_FROM(john@churchwiseai.com) - Local-biz →
LOCALBIZ_OUTREACH_FROM(hi@wiseaiagency.com) - SermonWise →
SERMONWISE_OUTREACH_FROM(john@sermonwise.ai)
- Church →
- One Resend webhook, account-level, subscribed to
email.delivered/opened/clicked/bounced/complained. Handler stamps the matching model (church first; local-bizcampaign_membersonly on a church miss) — church path must stay byte-for-byte unchanged. Idempotent; HTTP 200 no-match / 401 bad-sig / 500 DB-error. - Open/click tracking per sending domain — open-tracking ON for
churchwiseai.com,sermonwise.ai,wiseaiagency.com(founder dashboard toggle; opens stay 0 until enabled). - Replies auto-captured — gmail-poll matches inbound sender → prospect, stamps
replied_atfor both models. (Local-biz reachability depends onhi@wiseaiagency.comforwarding into the connected Gmail.) - Demo engagement persisted —
/s/[slug]view + chat/voice stamp the prospect row (church RPC; local-biz →campaign_members.demo_data). - Deliverability — every batch send is hard-blocked unless every row has a NeverBounce
DELIVERABLEresult (campaign-preflight.ts). SPF/DKIM/DMARC + custom tracking subdomain per sending domain. - CASL — founder presses every real send; no cron auto-sends to prospects; working unsubscribe + physical address on every campaign email; suppressed/bounced/unsubscribed rows excluded.
- Visibility — engagement is surfaced: church Warm Leads tab (outreach-engine) and Local Biz funnel tab (GCC
/growth/local-biz), ranked Hot/Warm/Reached.
Enforcement
The unit suites listed under the email-funnel registry entry run in the blocking test CI job on every PR. They must not be deleted or skipped. Changes to the listed code_files should keep all suites green.
Definition of done (operating)
All invariants hold AND the founder-only steps are complete: open-tracking toggled on for all three domains, hi@wiseaiagency.com reply-forwarding confirmed, and sends are founder-initiated.