WiseAI Realtor — Integrations (v1: honest connections hub) Expected Output Spec
⛔ STATUS: DRAFT — NOT APPROVED. CLAUDE.md Rule #17 (HARD GATE) is NOT satisfied.
Stage-1 agent research. Do not build the customer-facing screen until the founder approves and confirms the open items in a Stage-2 interview.
Sourced from (read-only, 2026-07-01):
information-architecture.md§G ("Connect — Integrations / APIs / Connectors": CRM, DDF/MLS, calendar, email/SMS, Zapier/webhooks, API keys),design-direction.md(card-grid pattern: logo, status pill, Connect/Manage),competitive-analysis.md(FUB's 250+ integrations as the long-run benchmark — explicitly NOT the v1 bar),settings/feeds/page.tsx(the EXISTING honesty precedent for exactly this situation — DDF is "board-registration-gated… connected BY the WiseAI Agency team… routes to WiseAI for setup — it never fakes a self-serve connect flow"),rbac.ts(integrations:crm:editcapability already defined, currently unused by any screen), and a repo-wide search that found zero CRM/Zapier/per-tenant-Calendar connector code anywhere inchurchwiseai-web.
0. Scope — what this spec covers, and what it does NOT
This spec covers Integrations v1: a single hub screen at
/realtor/app/integrations that replaces the bare RealtorStub with a
card per category, each showing either a REAL status (DDF/MLS only, in v1)
or an honest "not self-serve — here's what it takes / who to contact" state.
Does NOT cover: any actual OAuth flow (CRM, Calendar, Zapier); any working "Connect" button that creates a live external connection; API key issuance (no public partner API exists yet for a key to authenticate against — issuing keys with nothing to call would be a feature with no use, not an MVP); webhook subscriptions (no event bus/outbox exists to fire them from). All of the above are explicitly out of scope and shown as "Coming soon" / "Contact WiseAI" states, not disabled-but-implied-imminent buttons.
Build posture: Mirror settings/feeds/page.tsx's existing pattern, do
not invent a new one. That screen already solved this exact problem for DDF
(a real capability that isn't self-serve) — Integrations v1 generalizes the
same honest-status-card approach to the other categories the founder has
publicly described (settings/page.tsx's own nav description: "Connect your
CRM (Follow Up Boss, IXACT, kvCORE), calendar, email/SMS, and Zapier — plus API
keys"). This is a read-and-explain screen, not a new integration platform.
1. The screen this spec governs + what it reads
Layout: a card grid (per design-direction.md's pattern), one card per
category:
| Card | v1 status shown | Source of truth |
|---|---|---|
| DDF & MLS | REAL status (Connected/Not connected) | local_businesses.metadata.ddf.authorized — same read settings/feeds/page.tsx already does; card links to /realtor/app/settings/feeds rather than duplicating the explanation |
| CRM (Follow Up Boss, IXACT, kvCORE) | "Not available yet — tell your WiseAI contact which CRM you use and we'll scope a 2-way sync" | none (no connector exists) |
| Calendar (Google) | "Not self-serve yet — your WiseAI team can wire calendar sync for your showings; ask your contact" | none (existing google-calendar.ts is a single system-level connection, not per-tenant OAuth — do not claim it as connectable per-account) |
| Email & SMS | Informational only: "Email and SMS are already built into your Lead Alerts and follow-ups — nothing to connect." Links to /realtor/app/settings/notifications | existing lead-alerts infra (no new work; this card exists so the category isn't a dead end when the founder's own settings copy promises it) |
| Zapier / Webhooks | "Not available yet" | none |
| API keys | "Not available yet — no public API to key against" | none |
Each non-connected card is honest about WHY (board-gated, not-yet-built,
no-per-tenant-OAuth) rather than a generic "Coming soon" — matching the level
of specificity settings/feeds/page.tsx already sets as the bar.
Reads: local_businesses.metadata.ddf.authorized (existing column, read
via the same account_id → business_id resolution every other /realtor/app/*
screen uses). Writes: none in v1 — this is a read-only status/explainer
screen. (A "Request this integration" mailto/contact link is allowed — it is
not a write to the DB, just a mailto: or a link to the existing support
contact pattern used elsewhere in the dashboard.)
Demo tenant: Terry & Sheri Real Estate (…0c01, slug terry-and-sheri).
2. The AI-Bridge / honesty anchor
- Never fake a self-serve connection. A "Connect" button that doesn't
actually connect anything is the exact anti-pattern
settings/feeds/page.tsxwas already built to avoid for DDF ("the 'Connect DDF' CTA used to dead-end on /settings… it never fakes a self-serve connect flow" — its own docstring). Every card in this spec either shows a real status or explains, specifically, what's missing and who to ask. - No invented integration count. If a marketing surface elsewhere claims "50+ integrations" or similar, this screen must not be used to justify that claim unless the integrations are real — Content Studio/Integrations parity with actual product truth is the same honesty bar as pricing/product claims (CLAUDE.md Rule #13).
3. Role-based visibility
| Bucket | Roles | Scope |
|---|---|---|
| Brokerage / team management | brokerage_owner, broker_admin, team_admin (granted integrations:crm:edit) | Full hub; sees all cards + can use the "Request this integration" contact link |
| Agent / ISA / support | everyone else | Fail-closed RealtorStub (mirrors website/page.tsx's pattern) — Integrations is an account-level admin surface, not a per-agent one, consistent with settings/page.tsx gating this nav item behind integrations:crm:edit already |
Uses the already-defined integrations:crm:edit capability in rbac.ts
(currently defined but unused by any screen) — no new capability needed.
4. Expected outputs
4.1 — DDF & MLS card (the one real status)
Should see: "Connected" (green) if metadata.ddf.authorized is true, else
"Not connected yet" (neutral, not alarming red — this is board-gated, not a
failure); a "Manage" link to the existing /realtor/app/settings/feeds page
(no duplicated explanation — that page already owns the full story).
Should NOT see: a fabricated "Connected" status when the flag is false or
missing; a second, inconsistent explanation of DDF that could drift from
settings/feeds/page.tsx's copy over time.
Success: an owner glancing at Integrations sees, correctly, whether their MLS feed is live — and is routed to the ONE real place to act on it.
4.2 — Not-yet-available categories (CRM, Calendar, Zapier/Webhooks, API keys)
Should see: a clearly-labelled, non-alarming "Not available yet" state per category with a one-line reason and, where the founder has a real intake path, a "Tell us what you need" contact link; no fake "Connect" button, toggle, or progress bar implying work is already underway unless it genuinely is.
Should NOT see: any button that appears actionable but does nothing on click, or that opens a form that silently no-ops (the exact class of bug PR #1091 fixed for QR campaigns — this spec exists partly to prevent a repeat of that failure mode in a brand-new surface).
Success: an agent who wants Follow Up Boss sync knows immediately it isn't built yet and how to ask for it — never wastes ten minutes clicking a dead button.
4.3 — Email & SMS card (informational redirect)
Should see: a short note that email/SMS lead alerts already work via
Settings → Lead alerts, with a direct link there — this card exists so
settings/page.tsx's own promised copy ("email/SMS") isn't a dead end, without
duplicating or re-implementing the notifications screen.
Should NOT see: a second, competing SMS on/off toggle here that could
drift from whatever settings/notifications actually controls.
Success: no confusion about where email/SMS settings actually live.
5. Empty / loading / error states
| State | Expected output |
|---|---|
| DDF status unknown (missing metadata / table not provisioned) | Card reads "Not connected yet" (the honest default), not an error — matches settings/feeds/page.tsx's existing fallback behavior. |
| Loading | Card-grid skeletons, not a spinner. |
Role lacks integrations:crm:edit | Fail-closed RealtorStub message naming the missing permission. |
6. Carried-forward constraints (consistent across the batch)
- No realtor pricing shown in-product; gate by role/capability only.
- Honest status only — every card reflects real, verifiable state or an honest "not built" explanation; never a placeholder implying imminent availability without founder confirmation of a real timeline.
- Do not duplicate another screen's source of truth — DDF status and email/SMS settings each have exactly one owning screen; Integrations links to them rather than re-reading/re-explaining independently.
7. Accessibility (AODA → WCAG 2.1 AA)
- Card grid: real heading semantics per card; status conveyed by text, not color-pill alone.
- Links/contact actions: labelled buttons/links, not icon-only.
- Contrast ≥4.5:1; reduced-motion honored.
8. Acceptance checklist (QA runs on the deployed URL)
Behavioural verification on wiseaiagency.com (real host) against the demo
tenant (…0c01); never "build passes". Sample at ≥2 timepoints.
test.fixme('DDF & MLS card reflects the REAL metadata.ddf.authorized value, not a hardcoded status', () => {});
test.fixme('DDF & MLS card "Manage" link routes to /realtor/app/settings/feeds, no duplicated explanation on this page', () => {});
test.fixme('CRM / Calendar / Zapier / API-key cards show an honest "not available yet" state with a specific reason, no button that no-ops on click', () => {});
test.fixme('Email & SMS card links to /realtor/app/settings/notifications, introduces no competing toggle', () => {});
test.fixme('a membership without integrations:crm:edit sees the fail-closed RealtorStub, not the hub', () => {});
test.fixme('loading state renders skeletons, not a spinner; DDF-unknown state reads "Not connected yet", never an error banner', () => {});
9. Guardrails for agents building against this spec
- Rule #17 not satisfied — do not build until founder approval.
- Do NOT build any OAuth flow, API key issuance, or webhook subscription system in v1 — none of the underlying infra exists (confirmed by repo-wide search); building UI in front of nonexistent infra is the same honesty violation this spec exists to prevent.
- Reuse, do not duplicate: DDF status source (
settings/feeds/page.tsx's read ofmetadata.ddf.authorized) and the lead-alerts settings screen own their domains; Integrations links out rather than re-reading/re-explaining. integrations:crm:editalready exists inrbac.ts— do not invent a new capability string.- If code diverges, update the spec first (founder approval), then the code.
End of spec. STATUS: DRAFT — NOT APPROVED. Open items for Stage-2: (1) confirm the "Tell us what you need" contact link's destination (mailto to founder? a support form?); (2) confirm whether Calendar should be omitted entirely from v1 rather than shown as "not available" (founder may not want to advertise a category with zero near-term plan); (3) confirm this spec's read-only v1 scope is acceptable, or whether the founder wants API-key issuance pulled forward as a genuinely useful v1.1 once outbound webhooks/leads-export has a real consumer.