Skip to main content

WiseAI Realtor — Listings 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 listings.html + studio.html mocks. 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): do-not-reinvent.md (the shipped DDF sync + ListingStudio + REListing types + the "edit=manual / feature+reorder=all" BEAT + the SellingToolz duplication trap + the listings/REALTOR.ca direction + trademark rules), data-model.md §1.5/§1.6 (local_business_listings KEEP + re_listing_overlay NEW), backend-completeness-audit.md (media data model; "coming soon"/exclusive board rules), ai-guardrails.md RULE 3 (facts-used / no fabricated listing facts), and realtor-mockups/{listings.html,studio.html}.


0. Scope — what this spec covers, and what it does NOT

This spec covers the Listings manager (card gallery / table / map, filter bar, status, the featured + reorder overlay, listing media) and the listing side of Content Studio (the AI Listing Kit — MLS copy ×3, fair-housing scrub, social/email, variants). Sibling of realtor-qr-campaigns-mvp.md (a QR campaign connects to a listing) and realtor-analytics-mvp.md (per-listing leads/DOM).

Does NOT cover (cross-referenced, not duplicated):

  • The public listing-detail page + search + scan landing — already shipped (/s/[slug]/listing, /scan; do-not-reinvent.md).
  • The broader Content Studio (blog / newsletter / buyer-guide / market-update / per-language content generation) — the listing-copy mode of studio.html is covered here (it IS the Listing Kit); the multi-type content side is covered by the already-approved acceptance/real-estate-content-editor-mvp.md
    • real-estate-blog-mvp.md, and per-language generation is partly greenfield (do-not-reinvent.md "Genuinely greenfield"). Cross-reference those; do not re-spec them here.
  • The DDF sync engine itself (LIVE, PR #1064 — ddf/sync.ts is manual-safe; do NOT rebuild). This spec governs the manager UI over it.

Build posture: Listing Studio, DDF sync, the REListing shape, and the public listing pages already shipped (do-not-reinvent.md). This screen extends them with the manager UI + the re_listing_overlay (featured/sort) — the one genuinely new piece. Extend, do not rebuild.


1. The mock screens this spec governs + what they read

Governs realtor-mockups/listings.html: a card gallery (Gallery / Table / Map toggle) with a header ("8 active · 2 manual · 6 from MLS") + a CREA DDF · sample feed pill, a filter bar (location/address/MLS#, min/max price, beds, baths, type, status Active/Pending/Sold), and cards showing photo, status badge (Active/Pending/Sold gold-celebration), a source badge (Manual vs MLS), price, beds/baths/sqft, DOM + leads, and a Listing kit ✦ affordance on manual cards. (Table view adds sortable columns: price, beds, DOM, leads.)

Governs realtor-mockups/studio.html (listing-copy mode = the Listing Kit): a 3-pane editor — brief (content type incl. Listing copy, the selected listing, tone, languages, key facts used verbatim) · editor (the generated MLS description) · AI assistant (quick commands: Shorten / More luxury / Add CTA / Translate → Punjabi / Make social post / Email-to-database; a Fair-housing check passed card; A/B/C variants; a social preview).

Reads/writes (verify exact route names; do not fabricate):

SurfaceUnderlying store
Card gallery / table / maplocal_business_listings (price/status/beds/baths/sqft/photos/maps; source manual|ddf, ddf_id) via src/lib/real-estate/server/listings.ts
Source badge (Manual vs MLS)local_business_listings.source
Featured + sort orderre_listing_overlay (NEW — featured flag + sort_order keyed by listing_id/mls_number/ddf_id; §4.2)
DOM + leads per listinglisting dates + re_interactions/re_contacts attributed to the listing
Listing Kit (MLS copy ×3, fair-housing scrub, social/email)ListingStudio.tsx + src/lib/real-estate/listing-kit.ts + fair-housing.ts
Translate → languageper-language generation (greenfield; reuse chat multilingual path)

Demo tenant: Terry & Sheri Real Estate (…0c01, terry-and-sheri) — Beckett c01 has 11 real own DDF listings (office 296475) + manual additions that coexist and survive sync (do-not-reinvent.md). NEVER a real customer (feedback_never_modify_customer_data).


2. The AI-Bridge / honesty anchor

  • No fabricated listing facts. The Listing Kit generates copy from the key facts used verbatim + the live local_business_listings row — it never invents a feature, price, or status (ai-guardrails.md RULE 3; the manual vs MLS honesty rule).
  • Fair-housing scrub on generated copy. Every generated listing description passes the fair-housing linter (fair-housing.ts) — "describes the home, not the buyer", Ontario Human Rights Code safe — surfaced as a visible check. Copy that fails is flagged, not silently published.

3. Role-based visibility

BucketRolesListings scope
Brokerage managementbrokerage_owner, broker_admin (brokerage scope)All listings (brokerage) + featuring/order + Listing Kit
Team managementteam_admin (team scope)All listings within the team + featuring/order + Listing Kit
Agent / ISAagent, isa (own scope)Own manual listings (edit) + feature/reorder per policy; team feed listings visible
Support / externaltransaction_coordinator, marketing_assistant, external_partner (bounded)View / scoped; marketing_assistant may run Listing Kit per policy; external_partner read-only

4. Expected outputs

Should see:

  • A Gallery / Table / Map toggle over a unified set of manual + DDF listings (the CREA DDF sample feed + the agent's exclusives in one view), each card with a status badge (Active / Pending / Sold = gold celebration), a source badge (Manual vs MLS), price, beds/baths/sqft, and DOM + leads.
  • A filter bar (location/address/MLS#, price, beds, baths, type, status). Table view = sortable columns (price/beds/DOM/leads — the founder sortable-header rule, persisted per view). Map view plots listings.

Should NOT see:

  • Manual and DDF listings in separate silos (the value is a unified manager).
  • A DDF (source='ddf') row presented as editable MLS data (§4.3).

Success: the agent manages every listing — own exclusives + MLS feed — in one place, with source/status/DOM/leads legible per card.


4.2 — THE BEAT: edit = manual only; feature + reorder = ALL (via overlay)

This is the differentiator that beats SellingToolz (do-not-reinvent.md).

Should see:

  • Editing listing facts (price/beds/description/photos) is allowed for MANUAL listings only — DDF/feed listings are read-only (you can't edit the board's authoritative record).
  • Featuring AND drag-reordering works on ALL listings — feed (DDF) AND manual — via the re_listing_overlay (a featured flag + sort_order keyed by listing_id/mls_number/ddf_id). The homepage "Featured/Scroll" carousel renders featured DESC, sort_order ASC. No editing of MLS data; no duplication.
  • The overlay is decoupled from the feed: the 30-minute DDF sync.ts upserts feed rows but never touches the overlay, so an agent's featuring/order survives every sync (the silent-reset regression the on-row approach risks — data-model.md §1.6).

Should NOT see:

  • A DDF listing made editable, or an agent forced to re-create (duplicate) a feed listing to feature/reorder it (the SellingToolz trap we explicitly beat).
  • Featuring/order silently reset after a DDF sync.

Success: an agent features + drags a DDF listing to the top of their carousel; a sync runs; the featuring/order persists and the MLS data is untouched (verify across a sync cycle — behaviour at ≥2 timepoints).


4.3 — MLS®/REALTOR® trademark + manual = pre-market (compliance)

Should see:

  • Trademark correctness only on real MLS listings: MLS#/REALTOR.ca references, "Powered by REALTOR.ca", and "courtesy of [listing brokerage]" attribution attach only to source='ddf' rows. A manual listing carries no MLS#, is not on REALTOR.ca, and is labelled pre-market / coming-soon / exclusive.
  • A "coming soon" manual listing surfaces the board exclusive-listing rule (CREA cooperation: on MLS within ~3 days of public marketing; PropTx requires immediate showing availability) — the UI must not design features that encourage off-MLS marketing.

Should NOT see:

  • A manual/coming-soon listing implying it is on REALTOR.ca or carrying an MLS#.
  • MLS®/REALTOR® trademarks in a page title/meta/slug/domain (that's the website compliance gate — realtor-website-builder-mvp.md).

Success: trademark + attribution appear only where legitimate; manual listings are honestly pre-market with the exclusive-rule reminder.


Should see:

  • A listing media manager: gallery photo ordering (drag), support for video / 3D tour / floorplan assets, alt-text per image (accessibility + AI honesty), and storage/upload handling. (Audit P1 listing-media gap.)
  • For DDF listings, media comes inline from the feed (the live feed returns Media inline; $expand=Media is invalid — do-not-reinvent.md); the manager surfaces feed media read-only and lets the agent add alt-text/overlay without editing the MLS record.

Should NOT see:

  • Media editing that mutates the DDF authoritative record.
  • Images without an alt-text affordance (AODA).

Success: the agent orders the gallery, adds video/floorplan + alt-text, and it renders on the public listing page.


4.5 — Listing Kit (AI MLS copy ×3 + fair-housing scrub + social/email + translate)

Should see (studio.html listing-copy mode):

  • The Listing Kit: AI MLS description in 3 lengths/variants (A warm / B punchy / C luxury) from the key facts used verbatim, a visible fair-housing check result, quick commands (Shorten / More luxury / Add CTA / Translate → Punjabi / Make social post / Email-to-database), and a social preview.
  • Generated copy is editable and draft → publish to the manual listing / social channels.

Should NOT see:

  • Generated copy that fabricates a fact not in the key facts / listing row (ai-guardrails.md RULE 3).
  • Copy that fails the fair-housing scrub being publishable without a flag.
  • ⚠️ Carried-forward (minor): the Listing Kit must NOT generate a CTA that implies the AI books a showing ("book your showing today" as agent copy is fine; an AI auto-booking is not) — showings are captured requests (ai-front-desk.md decision 4).

Success: the agent generates compliant, fact-grounded MLS copy in 3 variants + a translation + a social post, all passing the fair-housing scrub.


5. Empty / loading / error states

StateExpected output
No listingsDemo-seeded preview + "Add your first listing / connect DDF" CTA — never a blank gallery (anti-pattern #6).
DDF not authorized / feed downHonest "MLS feed not connected / temporarily unavailable" (non-destructive — manual listings still render); never a fake feed (mock labels its feed "sample").
LoadingCard/table skeletons, not a spinner (anti-pattern #7).
Listing Kit generation errorInline "Couldn't generate — retry"; the draft + key facts preserved.
Fair-housing failThe generated copy is flagged with the offending phrase; publish is gated until resolved.
Media upload errorInline retry; other media intact.

6. Carried-forward constraints (consistent across the batch)

  • Aria does NOT book/schedule — Listing Kit CTAs frame showings as agent-handled / captured requests, never AI bookings (§4.5).
  • SMS off-by-default + consent-gated; crisis/safety never gated (a listing chat that surfaces a crisis still routes to 988).
  • 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 — gate by role/module.
  • Honest metrics + no fabricated facts; language never hardcoded (translate targets = the agent's enabled languages; non-EN copy needs native review per ai-guardrails.md).
  • Reuse existing embed/infra, not a new cdn domain.

7. Accessibility (AODA → WCAG 2.1 AA)

  • Gallery/table/map: keyboard-navigable; cards are links/buttons with accessible names; Table uses real semantics + aria-sort; status/source badges convey by text, not color alone (Sold gold is celebration accent + label).
  • Media: alt-text is first-class (required affordance per image); video has controls + captions affordance; drag-reorder has a keyboard alternative.
  • Listing Kit: editor + variant cards + commands keyboard-operable; the fair-housing result is text (not color-only).
  • 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.

// Manager + source/status
test.fixme('Gallery/Table/Map show manual + DDF unified; cards show source (Manual/MLS) + status + DOM + leads', () => {});
test.fixme('Table view sorts price/beds/DOM/leads (persisted per view); filters narrow the set', () => {});

// THE BEAT
test.fixme('editing listing facts is allowed for MANUAL only; DDF/feed rows are read-only', () => {});
test.fixme('feature + drag-reorder works on ALL listings (DDF + manual) via re_listing_overlay — no duplication', () => {});
test.fixme('featuring/order survives a DDF sync cycle (overlay decoupled; MLS data untouched)', () => {});

// Trademark + manual = pre-market
test.fixme('MLS#/REALTOR.ca/"courtesy of" attach ONLY to source=ddf rows; manual = no MLS#, pre-market/coming-soon', () => {});
test.fixme('a "coming soon" manual listing surfaces the board exclusive-rule reminder; no off-MLS-marketing nudge', () => {});

// Media + Listing Kit
test.fixme('media manager orders gallery + supports video/3D/floorplan + REQUIRES alt-text; DDF media stays read-only', () => {});
test.fixme('Listing Kit generates 3 fact-grounded variants + translate + social, all passing the fair-housing scrub', () => {});
test.fixme('generated copy fabricates NO fact beyond key facts/listing row; a fair-housing fail gates publish', () => {});

// States + a11y
test.fixme('empty/DDF-down/loading/error/fair-housing-fail states render per §5; never blank, never a spinner, no fake feed', () => {});
test.fixme('gallery/table keyboard-navigable; alt-text first-class; badges not color-only; reduced-motion honored', () => {});

9. Guardrails for agents building against this spec

  • Rule #17 not satisfied — do not build until founder approval.
  • Extend the shipped Listing Studio + DDF sync + REListing types — do NOT rebuild (do-not-reinvent.md); ddf/sync.ts is manual-safe and LIVE.
  • THE BEAT lives in re_listing_overlay — feature/sort decoupled from the feed so sync never clobbers it; edit=manual, feature+reorder=all; never duplicate. Migrate-before-use (data-model.md §1.6, Rule #18); founder-gated DDL.
  • Trademark only on real MLS rows; manual = pre-market, no MLS#, board exclusive rules (audit compliance must-haves).
  • No fabricated facts; fair-housing scrub gates publish; Aria books nothing; language never hardcoded; honest metrics; verify on the real host; 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) cut over featured/sort_order to re_listing_overlay now vs special-case the DDF upsert (data-model.md §1.6 recommends the overlay); (2) media storage backend + video/3D providers; (3) which Listing-Kit languages ship + native-review gating; (4) how DOM/active-vs-total counts reconcile (Beckett showed 11 board vs 9 scroll).