WiseAI Realtor — Reviews Manager 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 Reviews tab of
reviews-automations.html. 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): the already-approved + shipped
acceptance/reviews-engine-mvp.md(the owner-pressed, dry-run, CASL/FTC engine — Reviews Engine Phase 2 shipped via PR #1017),do-not-reinvent.md(reviews tables +/r/[token]+ ReviewRequestsTab exist),design-direction.md, and the Reviews tab ofrealtor-mockups/reviews-automations.html.
0. Scope — what this spec covers, and what it does NOT
This spec covers the Reviews MANAGER screen — the command-center surface that restores Reviews to the realtor nav (the audit flagged it "shipped in prod — dropped from nav") and exposes the shipped engine: the review funnel, platform targets, the owner-pressed request list, CSV past-client import, testimonial curation → website, and response drafting.
This spec BUILDS ON and does NOT duplicate acceptance/reviews-engine-mvp.md —
the approved + shipped engine spec that owns the behaviour + compliance
(owner-pressed sends with dry-run default; the CASL EBR consent gate; the
suppression/opt-out spine; the auto-stopping cadence; the NO-gating rule; the
no-incentives/no-fake/no-cross-copy rules; the Places-API storage constraint; the
per-vertical testimonial posture). This screen is the manager UI over that
engine; where this spec mentions a send, a consent check, or auto-stop, the
behaviour is reviews-engine-mvp.md.
Does NOT cover: the Automations / drip library (the other tab of
reviews-automations.html) — covered by realtor-tasks-calendar-mvp.md §4.3; the
public /s/[slug]/reviews page render (website specs); the /r/[token]
private-feedback page (kept as-is, non-gating — reviews-engine-mvp.md).
Build posture: the Reviews Engine already shipped (PR #1017; owner engine,
no cron, dry-run, CASL — do-not-reinvent.md, project_beckett_sutton_realestate).
This spec is the manager surface + nav restoration, extending the existing
ReviewRequestsTab. Do not rebuild the engine.
1. The mock screen this spec governs + what it reads
Governs the Reviews tab of realtor-mockups/reviews-automations.html: a
dry-run / owner-pressed banner ("nothing is sent automatically … you press
Send … no cron … consent & suppression re-checked before every touch"); a Review
funnel (Requests sent → Clicked → Public review / Private feedback,
with the honest note "Open rate tracked but never shown as engagement" + "same
public ask to every eligible client — no happy→public/unhappy→private routing");
Platform targets (Google priority 1, RateMyAgent priority 2 — note
rate-my-agent.com, reviewer-initiated Google cross-post OK / never copy text,
Facebook off); a Review requests table (Client, Consent (EBR), Target,
Status [Draft·approved / Sent·touch 1 / Clicked / Reviewed / Private
feedback / Opted out], Last touch, Actions [Send / Reviewed / Opt-out])
with a "Send approved batch (N)" button and a CASL footer (sender name +
current mailing address + one-tap unsubscribe); CSV import (past clients, 24-mo
EBR, import summary imported/skipped/rejected); a Testimonials gallery
(collect-only by default; republished with client consent + RECO registrant ID;
feeds the website).
Reads/writes (verify exact route names; do not fabricate):
| Surface | Underlying store |
|---|---|
| Funnel (sent/clicked/reviewed/private) | local_business_review_requests statuses + local_business_message_logs |
| Platform targets | local_business_review_targets (NEW) seeded from setup_profiles.google_review_url |
| Request list + Send/Reviewed/Opt-out | local_business_review_requests (status, cadence, reviewed_detected_via) |
| Consent (EBR) | ebr_basis/ebr_date (consent computed at send time) |
| Suppression / opt-out | local_business_client_suppressions (NEW) |
| CSV import | local_business_client_imports (NEW) |
| Testimonials | testimonial store → website (realtor-website-builder-mvp.md Reviews page) |
| Link to contact | re_contacts (the review request's long-lived person) |
Demo tenant: Terry & Sheri Real Estate (…0c01, terry-and-sheri, vertical
real_estate) — the canonical Beckett demo (reviews-engine-mvp.md §3). NEVER a
real customer (feedback_never_modify_customer_data).
2. The AI-Bridge / honesty anchor (and the engine's compliance spine)
Per reviews-engine-mvp.md §2 + ai-bridge-principle.md — surfaced, never weakened:
- NO gating, ever. The same public ask goes to every eligible client —
no happy→public / unhappy→private routing; the
/r/[token]private-feedback surface never gates the public ask. The manager UI must NOT add sentiment routing. - No incentives; no fake / no cross-copy. No reward field; the engine never drafts/pre-fills/submits review content; never auto-copies text to RateMyAgent.
- Honest metrics. The funnel shows clicks, not opens — opens are tracked for deliverability only and never shown as engagement (the mock states this).
- Owner-pressed, dry-run default, no cron. A human presses Send per batch;
consent + suppression re-checked before every touch; no cron auto-sends to
clients (
feedback_never_cron_send_campaigns).
3. Role-based visibility
| Bucket | Roles | Reviews scope |
|---|---|---|
| Brokerage / team management | brokerage_owner, broker_admin, team_admin (brokerage/team scope) | Full manager: targets, send approved batch, import, testimonial curation, responses |
| Agent / ISA | agent, isa (own scope) | Own clients' requests + send per policy (still owner/founder-blessed sends) |
| Support / external | marketing_assistant, transaction_coordinator, external_partner (bounded) | marketing_assistant curates testimonials/content per policy; view/scoped otherwise; cannot press Send; external_partner read-only |
The send gate never lifts regardless of role — a human at the business presses
Send; agents don't get an "auto-send" capability (reviews-engine-mvp.md Decision 1).
4. Expected outputs
4.1 — Review funnel (honest: clicks, not opens) + nav restoration
Should see:
- Reviews restored to the realtor nav (it was dropped — audit P1).
- A funnel: Requests sent → Clicked → Public review / Private feedback, with a clear "clicks, not opens" honesty label and the no-gating statement. Open rate may be shown only as a deliverability footnote, never as engagement.
Should NOT see:
- "Opened / Delivered" presented as engagement (honest-metrics rule).
- Any happy→public / unhappy→private routing in the funnel framing.
Success: the owner sees real sent/clicked/reviewed/private counts; the funnel reads honestly.
4.2 — Platform targets (Google + RateMyAgent; no cross-copy)
Should see:
- Managed targets: Google (priority 1; Place ID stored, write-review link built
at send), RateMyAgent (priority 2;
rate-my-agent.com— reviewer-initiated Google cross-post OK, we never copy text), Facebook (off/tertiary). Each with rating + count + enable/priority.
Should NOT see:
- An "auto-copy this review to other platforms" control (cross-copy banned).
ratemyagent.com(un-hyphenated = unrelated company) — the hyphen is load-bearing (reviews-engine-mvp.md§4.2).
Success: the owner manages multi-platform targets; the engine never copies review text.
4.3 — Owner-pressed request list (Send / Reviewed / Opt-out, dry-run)
Should see:
- A request list: client, Consent (EBR) (e.g. "Purchase · Apr 2026"), target, status (Draft·approved / Sent·touch 1 / Clicked / Reviewed / Private feedback / Opted out), last touch, and actions: Send (on approved drafts), Reviewed (operator-marked auto-stop), Opt-out.
- A "Send approved batch (N)" control — the owner presses it; dry-run is ON by default; consent + suppression are re-checked before every touch; a terminal/opted-out row shows no further touch.
- A CASL footer on every email: sender name (Team Beckett), a current mailing address, and a one-tap unsubscribe — opt-outs honored immediately + persist across batches; no date / lapsed EBR → no send.
Should NOT see (HARD — engine compliance):
- Any cron / unattended send to a client; a human presses Send
(
feedback_never_cron_send_campaigns,feedback_db_writes_ok_sends_need_blessing). - A send to a suppressed/opted-out/EBR-lapsed client (re-checked before each touch).
- A reminder after the request reached
reviewed/opted_out(auto-stop fires). - ⚠️ Carried-forward: SMS request steps shown as a live default. The
engine is email-first; SMS is OFF by default + consent-gated until the
founder confirms SMS-in-scope (
reviews-engine-mvp.md§1.3 / §7). The manager shows SMS as "coming soon", not an active sender.
Success: the owner approves + presses Send on a batch (dry-run by default), auto-stop fires on Reviewed/Opt-out, and no suppressed/lapsed client is ever sent.
4.4 — CSV past-client import (24-mo EBR)
Should see:
- A CSV import (name, email, phone, transaction date), last 24 months only (CASL EBR), with an import summary: imported (staged as drafts) / skipped (duplicate / lapsed / suppressed) / rejected (no date). Imported rows are staged only — nothing sends until the owner approves the batch.
Should NOT see:
- A row without a transaction date becoming sendable (rejected — no date, no send).
- An out-of-window contact enqueued for sending; an import auto-sending anything.
Success: a mixed CSV imports with correct accept/skip/reject counts; valid rows stage as drafts; nothing sends until approval.
4.5 — Testimonial curation → website + response drafting
Should see:
- A Testimonials gallery — collect-only by default; a testimonial is
republished to the website only with client consent + the RECO registrant-ID +
CREA material-connection disclosure (
reviews-engine-mvp.md§5.7). "On website ✓" / "Add to site" affordances feed the public Reviews page (realtor-website-builder-mvp.md). - Response drafting: for a private feedback item ("Read & reply") or a public review, the owner can draft a response — the AI may help draft, but the owner presses send/post (no auto-reply); responses follow the no-advice / honesty guardrails.
Should NOT see:
- A testimonial republished without consent + registrant-ID + disclosure.
- An auto-posted review response (owner-pressed only).
Success: consented testimonials publish with the required RECO/CREA disclosure; the owner drafts + sends review responses, never auto-posted.
5. Empty / loading / error states
| State | Expected output |
|---|---|
| No requests yet | Honest "No review requests yet" + a "create your first request / import past clients" CTA — never fabricated funnel numbers (reviews-engine-mvp.md §4.6). |
| Loading | Funnel / list / gallery skeletons, not a spinner (anti-pattern #7). |
| Send/import error | Inline retry; drafts preserved; nothing partially sent. |
| Suppressed/opted-out client | Row shown terminal ("Opted out · no further touch"), actions disabled. |
| No platform target | Prompt to add a Google target (seeded from google_review_url); no send without a target. |
6. Carried-forward constraints (consistent across the batch)
- Owner-pressed sends, dry-run default, NO cron — the gate that never lifts.
- SMS OFF by default + consent-gated ("coming soon") until SMS-in-scope confirmed; crisis/safety never gated.
- Aria does NOT book/schedule (N/A to reviews, but consistent).
- 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) — but the send gate never lifts for any role.
- No realtor pricing; honest metrics only (clicks, not opens); language never hardcoded (Punjabi-client requests use the contact's language).
- No gating / no incentives / no fake / no cross-copy (engine compliance).
7. Accessibility (AODA → WCAG 2.1 AA)
- Funnel has a text/table equivalent; not color-only.
- Request table: real semantics; status conveyed by text; Send/Reviewed/ Opt-out are labelled buttons with confirmation for Send.
- CSV import dropzone keyboard-operable with a browse fallback; the import-summary is text.
- Testimonials gallery + response drafting keyboard-operable; consent/registrant state is text.
- Contrast ≥4.5:1; gold accent only; teal 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; assert change.
// Funnel + nav + honesty
test.fixme('Reviews is restored to the nav; funnel shows sent/clicked/reviewed/private — clicks, not opens', () => {});
test.fixme('no happy→public / unhappy→private routing; same public ask framing; opens shown only as deliverability footnote', () => {});
// Targets
test.fixme('Google + rate-my-agent.com targets managed; NO auto-copy-to-other-platforms control; never ratemyagent.com', () => {});
// Owner-pressed sends (engine compliance)
test.fixme('"Send approved batch" requires a human press; dry-run ON by default; consent+suppression re-checked each touch', () => {});
test.fixme('NO cron/unattended send to a client; suppressed/opted-out/EBR-lapsed clients are never sent', () => {});
test.fixme('marking Reviewed/Opt-out auto-stops the cadence (no further touch); CASL footer present (name+address+unsubscribe)', () => {});
test.fixme('SMS request steps are OFF by default ("coming soon"), not an active sender, until SMS-in-scope', () => {});
// Import + testimonials + responses
test.fixme('CSV import: no date → rejected; lapsed/dup/suppressed → skipped; valid → staged drafts (not sent until approved)', () => {});
test.fixme('a testimonial republishes to the website ONLY with consent + RECO registrant-ID + CREA disclosure', () => {});
test.fixme('review responses are owner-pressed (AI may draft); never auto-posted', () => {});
// States + a11y
test.fixme('empty/loading/error/suppressed/no-target states render per §5; no fabricated funnel numbers', () => {});
test.fixme('funnel has a text equivalent; table semantics + labelled actions; Send confirms; reduced-motion honored', () => {});
9. Guardrails for agents building against this spec
- Rule #17 not satisfied — do not build until founder approval.
- Build ON the shipped Reviews Engine (
reviews-engine-mvp.md, PR #1017) + the existingReviewRequestsTab//r/[token]— do NOT rebuild the engine or re-specify its compliance; this is the manager surface + nav restoration. - Owner-pressed, dry-run, no cron is the gate that never lifts — for any role.
- No gating / no incentives / no fake / no cross-copy / clicks-not-opens / rate-my-agent.com (hyphen) — engine compliance, surfaced not weakened.
- SMS off-by-default + consent-gated ("coming soon"); crisis never gated; language never hardcoded; testimonials republish only with consent+registrant-ID; verify on the real host; evidence-or-nothing.
- Migrate-before-use — review targets/suppressions/imports columns per
reviews-engine-mvp.md§6 (verify viainformation_schema, Rule #18; founder-gated). - 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 SMS
review requests stay out-of-scope (email-first) for the realtor MVP; (2) how much
AI-assist is allowed in response drafting (draft-only, owner posts); (3) the
testimonial→website consent/registrant-ID capture flow; (4) link review requests to
re_contacts vs keep on the flat request table for now.