WiseAI Realtor — Analytics & Reporting Expected Output Spec
⛔ STATUS: DRAFT — NOT APPROVED. CLAUDE.md Rule #17 (HARD GATE) is NOT satisfied.
Stage-1 agent research, pre-populated from the realtor design docs + the
analytics.htmlmock. 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-06-29):
backend-completeness-audit.md(the five "which X creates leads" reports = the core value narrative; speed-to-lead; first-vs-last touch),data-model.md§4 (the lead-source taxonomy + first/last touch onre_contacts;re_interactionsas the attribution stream),compliance-privacy-analytics.md(first-party / privacy-safe attribution),design-direction.md(KPI tile, color rules), andrealtor-mockups/analytics.html.
0. Scope — what this spec covers, and what it does NOT
This spec covers the Analytics & Reporting workspace — the value-narrative reporting: a KPI strip, lead-source attribution & ROI (first vs last touch), a conversion funnel with drop-off, speed-to-lead + unactioned, a language breakdown, the "what's creating your leads" panels (top listings / QR signs / content), and team performance — plus date range, compare, export, and scheduled reports.
Does NOT cover: the QR builder + its own scan analytics
(realtor-qr-campaigns-mvp.md — QR appears here as one source); the dashboard's
"Today" tiles (realtor-dashboard-mvp.md — analytics is the deeper "Insights"
view); the deals board (realtor-deals-mvp.md); raw event capture (voice/chat →
re_interactions, ai-front-desk.md).
Build posture: Partial → new (information-architecture.md build map —
demo-event analytics exist; the realtor-framed reporting view is new). Reads the
proposed re_interactions/re_contacts spine + existing lead_events
(migrate-before-use).
1. The mock screen this spec governs + what it reads
Governs: realtor-mockups/analytics.html — section tabs (Overview /
Attribution & ROI / Funnel / Team), a date-range + Compare: prev. period
toggle, Export + Schedule report, and a "First-party · privacy-safe · no
cookie banner needed" note. Sections:
- KPI strip (5): Leads, Lead→client %, Showings booked [§6], Deals firm/closed, GCI pipeline (weighted) [§3 — deferred/capability-gated].
- Lead-source attribution & ROI: a table (Source, Leads, Share, Cost/lead, Deals, GCI [§3]) with a First touch ⇄ Last touch toggle + an "Aria's read" insight.
- Leads by language (auto-detected) + a Punjabi-conversion insight.
- Conversion funnel: Visits/scans → Chat/voice → Lead → Appointment → Client → Closed, with drop-off % per step (biggest drop highlighted).
- Speed-to-lead: median first response (AI < 1m vs human follow-up), a response-time distribution, and an unactioned > 24h alert list.
- What's creating your leads: Top listings / Top QR signs (scans→leads) / Top content by leads.
- Team performance: Terry vs Sheri (+ Aria as the AI front office row: median response < 1m, "books & qualifies before hand-off") with GCI columns [§3].
Reads (target-state — WS7; verify exact route names; do not fabricate):
| Report | Underlying read |
|---|---|
| KPI strip | re_contacts (leads, lead→client), re_deals (firm/closed, value), showings (captured requests §6) |
| Source attribution & ROI | re_contacts.source_category/source_detail + first_touch_*/last_touch_* (the toggle); cost where ad spend is connected |
| Funnel | re_interactions (visit/scan → chat/voice) → re_contacts (lead → appointment → client) → re_deals (closed) |
| Speed-to-lead | re_interactions (first inbound vs first outbound), unactioned threshold |
| Language breakdown | re_contacts.preferred_language (auto-detected) |
| What's creating leads | re_interactions grouped by listing / QR campaign / content piece |
| Team performance | per-agent rollups (local_business_agents ownership) |
| GCI / commission | DEFERRED (A2) + capability-gated (rbac.ts) — see §3 |
Demo tenant: Terry & Sheri Real Estate (…0c01). Mock data is demo; NEVER
a real customer (feedback_never_modify_customer_data).
2. The AI-Bridge / honesty anchor
- Honest, first-party attribution only. Every number is a real count from the event stream — no fabricated figures, no "opens/impressions" dressed up as engagement (honest metrics: scans/clicks/leads/deals, real bounce — never "Delivered/Opened" theater). A no-data range reads honestly ("Not measured / no data this period"), not a placeholder chart.
- "Aria's read" is an insight, not advice. The AI-summary callouts (e.g.
"shift spend from Google Ads to QR") are framed as a suggestion to the agent,
grounded in the shown numbers — never a guarantee, a valuation, or financial
advice (
ai-guardrails.mdRULE 2). - Privacy-safe. First-party attribution (no third-party cookie banner needed)
per
compliance-privacy-analytics.md; PIPEDA/Law 25 honored.
3. GCI / commission in analytics — DEFERRED (A2) + capability-gated (rbac.ts)
⚠️ NEW INCONSISTENCY — flagged, not silently resolved. The
analytics.htmlmock shows a GCI pipeline ($186k) hero KPI, GCI columns in the source table, and per-agent GCI ($102k / $84k) in Team performance. But A2 = commissions deferred and this batch's directive says commission is role-gated and deferred. Reconcile (consistent withrealtor-deals-mvp.md§3):
- MVP: analytics ships without GCI/commission. The hero KPI uses volume ($ transaction volume) or deal count — not GCI; the source table and team table omit the GCI column (or show volume). This avoids depending on deferred commission data.
- If/when commission lands (post-MVP, founder-gated): GCI/commission is gated
by capability (
rbac.ts):brokerage_owneredits;broker_admin/team_admin/brokerage_ownerread at brokerage/team scope; anagentreads their OWN commission (commissions:amount:read:own) — so an agent's own-performance GCI is visible to them, but team/peer GCI is not;isa/transaction_coordinator/marketing_assistant/external_partnerhave no commission capability; enforced at the API/query layer; every read logged (data-model.md§5.2). - Stage-2 confirms: defer GCI in analytics entirely for MVP (recommended), or ship it capability-gated.
Other role scoping:
| Bucket | Roles (rbac.ts) | Analytics scope |
|---|---|---|
| Brokerage management | brokerage_owner, broker_admin (brokerage scope) | Brokerage-wide reports + Team performance (per-agent comparison); GCI (read brokerage) if it lands |
| Team management | team_admin (team scope) | Team reports + team performance; GCI (read team) if it lands |
| Agent / ISA | agent, isa (own scope) | Own performance + own-attributed sources/funnel; no peer comparison; an agent sees own GCI (read:own) if it lands, isa none |
| Support / external | transaction_coordinator, marketing_assistant, external_partner (bounded) | Scoped/read-only; never commission capability |
4. Expected outputs — the five "which X creates leads" reports
4.1 — Lead-source attribution & ROI (first vs last touch)
Should see:
- A ranked source table (QR yard signs / Website-AI chat / REALTOR.ca / Google
Ads / Referral…) with Leads, Share, Cost/lead, Deals, and a First touch ⇄
Last touch toggle that recomputes attribution (from
re_contacts.first_touch_*vslast_touch_*+ there_interactionsmulti-touch history,data-model.md§4). AI-owned sources honestly at $0/lead; paid sources at real cost where spend is connected (else cost "—"). - An honest blended cost + total row.
Should NOT see:
- Fabricated cost where no spend is wired (show "—").
- GCI column in MVP (§3).
Success: the agent sees which sources produce leads and deals, at what cost, under both first- and last-touch attribution.
4.2 — Conversion funnel with drop-off
Should see:
- A funnel: Visits/scans → Chat/voice → Lead captured → Appointment → Client → Closed, each step with a count and the drop-off % to the next, with the biggest drop-off highlighted + a plain-language note ("nurture longer").
- End-to-end summary (e.g. "2,140 visits → 6 closings (0.28%)").
Should NOT see:
- A funnel step that double-counts or shows an impossible (>100%) conversion.
- "Appointment" implying the AI booked it (§6 — captured request → agent confirm).
Success: the agent sees where prospects fall out of the funnel and where to focus.
4.3 — Speed-to-lead + unactioned
Should see:
- Median first response (AI < 1m, all hours) vs median human follow-up, a
response-time distribution, and an unactioned > 24h alert list (the
speed-to-lead enforcement, tied to Notifications
realtor-notifications-mvp.md).
Should NOT see:
- A speed-to-lead number that ignores the human leg (show both AI + human).
Success: speed-to-lead is measured honestly (AI instant, human follow-up separately) and stale leads are surfaced.
4.4 — Language breakdown + "what's creating your leads"
Should see:
- Leads by language (auto-detected
preferred_language) with an insight (the Punjabi-conversion wedge) — languages shown are whatever the data contains, not a hardcoded list. - What's creating leads: Top listings by leads, Top QR signs (scans→leads), Top content by leads — the concrete "which X creates leads" answers.
Should NOT see:
- A hardcoded language set; fabricated content/listing/QR numbers.
Success: the agent sees which listings, signs, content, and languages actually produce leads.
4.5 — Team performance + date range / compare / export / scheduled reports
Should see:
- Team performance (brokerage/team management): per-agent Leads / median response / appointments / deals / lead→client, with Aria shown as the AI front-office row (instant response, "books & qualifies before hand-off" → captures & qualifies, §6). GCI columns deferred/capability-gated (§3).
- A date range + Compare: prev. period, Export, and Schedule report (a scheduled report is a delivery to the account's own users — a staff alert, not a prospect send — and is allowed; it must NOT email a lead/client).
Should NOT see:
- An agent-scope user seeing the per-agent comparison or another agent's numbers (§3).
- A "scheduled report" that sends to a prospect (it goes to the account's own
users only — boundary in
realtor-notifications-mvp.md§1).
Success: management compares team performance and schedules reports to itself; agents see only their own.
5. Empty / loading / error states
| State | Expected output |
|---|---|
| No data in range | Honest "No data for this period" per report — never a fabricated chart (anti-pattern #6 / honest metrics). |
| Source unconnected (e.g. ad spend) | Cost reads "—"; leads still shown; no invented cost. |
| Loading | Per-section skeletons, not a spinner (anti-pattern #7). |
| Read error | Inline "Couldn't load this report — retry"; other sections still render. |
| Export/schedule error | Inline retry; nothing partially sent. |
6. Carried-forward constraints (consistent across the batch)
- Aria does NOT book/schedule — "Showings booked" KPI / funnel "Appointment" /
team "books & qualifies" all reflect captured showing requests (agent-
confirmed), never AI-confirmed bookings (
ai-front-desk.mddecision 4; relabel e.g. "Showing requests" / "captures & qualifies"). - GCI/commission deferred (A2) + capability-gated (§3).
- SMS off-by-default + consent-gated; crisis never gated (a scheduled report
is a staff alert, never a prospect send —
realtor-notifications-mvp.md§1). - Role enum (rbac.ts — implemented source of truth): agent | team_admin | transaction_coordinator | broker_admin | brokerage_owner | marketing_assistant | isa | external_partner (scopes own|team|brokerage).
- No realtor pricing ("$0/lead" is an honest attribution stat, not a price).
- Honest metrics only (no Delivered/Opened theater); language never hardcoded; first-party / privacy-safe attribution.
7. Accessibility (AODA → WCAG 2.1 AA)
- Charts (sparklines, funnel, bars, distributions) have text/table equivalents and data labels; meaning never conveyed by color alone.
- Tables: real header/row semantics; sortable/toggle controls labelled with
state; numerals
tabular-nums. - Section tabs + first/last-touch + compare toggles are keyboard-operable with visible focus.
- Insights ("Aria's read") are real text, readable by assistive tech.
- Contrast ≥4.5:1; gold = accent only (e.g. the GCI hero accent — and only if/when GCI ships, capability-gated); teal links/actions meet AA; 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.
// The five reports + honesty
test.fixme('source attribution table recomputes on First touch ⇄ Last touch; AI sources $0/lead; cost "—" when unwired', () => {});
test.fixme('conversion funnel shows per-step drop-off (biggest highlighted); no >100% / double-count', () => {});
test.fixme('speed-to-lead shows AI median AND human follow-up separately + unactioned>24h list', () => {});
test.fixme('language breakdown is data-driven (not hardcoded); "what creates leads" ranks listings/QR/content from real events', () => {});
test.fixme('no fabricated numbers anywhere; a no-data range reads "No data for this period"', () => {});
// Commission deferred + RBAC
test.fixme('MVP analytics show NO GCI/commission (deferred A2); hero uses volume/deal-count, not GCI', () => {});
test.fixme('if GCI ships, it is capability-gated (brokerage_owner edits; broker_admin/team_admin read at scope; agent reads OWN; isa/support/external none); peer/team GCI never shown to an agent; API-enforced + read-logged', () => {});
test.fixme('an agent sees only own performance — no team comparison, no peer numbers; sees OWN GCI (read:own) if it ships, never peer/team GCI; isa none', () => {});
// Reports delivery + carried-forward
test.fixme('"Schedule report" delivers to the account’s own users only — never to a lead/client', () => {});
test.fixme('"Showings booked"/"Appointment"/"books & qualifies" reflect captured REQUESTS, not AI-"booked"', () => {});
// States + a11y
test.fixme('no-data/unconnected/loading/error/export-error states render per §5; never a fabricated chart', () => {});
test.fixme('charts have text/table equivalents; toggles keyboard-operable; no color-only meaning; reduced-motion honored', () => {});
9. Guardrails for agents building against this spec
- Rule #17 not satisfied — do not build until founder approval.
- Honest, first-party attribution only — real counts or "Not measured"; never
Delivered/Opened theater; privacy-safe (
compliance-privacy-analytics.md). - GCI/commission deferred (A2) + capability-gated — MVP ships volume, not GCI;
reconcile with
realtor-deals-mvp.md§3 +data-model.md§1.4 before building (flag for founder); if it lands, gate + log (data-model.md§5.2). - Scheduled reports go to the account's own users, never a prospect
(
realtor-notifications-mvp.md§1;feedback_never_cron_send_campaigns). - Migrate-before-use —
re_interactions/re_contacts/re_dealsare proposals; verify columns viainformation_schema(Rule #18); founder-gated DDL. - Aria books nothing; language never hardcoded; honest metrics; verify on the real host; behaviour not DOM presence; evidence-or-nothing.
- 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) defer GCI in analytics entirely for MVP vs capability-gated (reconcile mock vs A2); (2) the attribution model default (first vs last touch) + whether multi-touch weighting is in MVP; (3) which reports are exportable/schedulable; (4) ad-spend connection sources for real cost/lead.