Skip to main content

Acceptance Spec — Realtor Sold / "Our Track Record" Gallery (P1 MVP)

  • Status: Proposed (MVP) — 2026-07-02
  • Priority: P1. High-trust seller-conversion asset. No board data / no VOW required — this is the agent's OWN past sales.
  • Product: WiseAI Realtor Pro Website (/s/[slug])
  • Parent: WISEAI_REALTOR_BACKEND_REPLACEMENT_REQUIREMENTS_2026-07-02.md §1.9. SellingToolz parity: "SOLD with teambeckett" gallery.

1. Why

The Becketts' current site has a "Get SOLD with teambeckett" gallery of their own past sales — their strongest seller-conversion proof. This is distinct from VOW/board sold-comps (which need a data agreement): it's the team marketing their own completed transactions, so it's shippable now with zero board-data dependency. The earlier parity doc wrongly filed this under the VOW track.

2. Do NOT reinvent — extend these (verified)

  • Status already exists: REListingStatus = 'active' | 'conditional' | 'sold' | 'pending' (types.ts); DB local_business_listings.status already carries 'sold' rows.
  • Section already exists: RealEstateSiteTemplate.tsx already renders <SoldStoriesSection config soldListings /> where soldListings = listings.filter(l => l.status === 'sold'). The homepage sold surface is built — the gap is (a) letting owners add/mark their own sold listings, and (b) an optional dedicated /sold page + richer treatment.
  • Listings manager exists: the self-serve Listings CRUD on local_business_listings (/realtor/app + /api/real-estate/listings) — extend to set status='sold' + a SOLD banner (column exists) + sort_order.

3. Scope

In: owner can mark/add a manual listing as sold (own marketing), with an optional sold date and sold price; a "Recently Sold / Our Track Record" gallery on the homepage (existing SoldStoriesSection) + a dedicated /s/[slug]/sold page; SOLD banner treatment. Out: board VOW sold-comps, market stats, AVM (all the separate VOW track).

4. Data

  • Reuse local_business_listings with status='sold'. Decision (flag): to display a sold price/date, add nullable sold_price numeric + sold_date date columns (migration in churchwiseai-web/migrations/); MVP can ship with just the SOLD banner + list_price if we defer sold-price display. Own-sold rows are source='manual' (never board-fed).
  • Compliance: these are the agent's OWN sales (own marketing) — not board sold data. No MLS®/REALTOR.ca sold-data claims; label clearly as the team's own transactions.

5. UI

  • Homepage: the existing SoldStoriesSection renders when the tenant has ≥1 sold listing; empty → section hidden (no empty state).
  • Dedicated /s/[slug]/sold page: grid of sold listings (photo + SOLD banner + address + optional sold price/date), "Sold by {brand}" framing, CTA to a home evaluation. Reuse the listing card + detail patterns.
  • Hydration-safe dates (timezone-pinned per the PR #1097/#1099 lint guard).

6. Owner surface

  • In the Listings manager: a status control incl. Sold, optional sold date + sold price inputs, and the SOLD banner toggle. Reuse the existing manual-listing editor; account_id-in-query rule applies (feedback_realtor_client_calls_need_account_id_query).

7. Acceptance criteria

  1. Owner marks a manual listing sold (+ optional date/price) → it appears in the homepage sold section and on /sold; is removed from the active for-sale grid.
  2. A tenant with zero sold listings shows no sold section (homepage) and an honest empty state on /sold.
  3. SOLD banner renders; sold price/date shows only when set.
  4. Sold rows are source='manual'; no board/DDF row is ever relabeled sold (DDF carries no sold data).
  5. Tenant isolation + published gating hold.

8. Verification (deployed URL)

  • On the TeamMoelker test tenant: add a sold listing via the manager, then Playwright the public /s/[slug] + /sold — assert it renders in the sold section with the SOLD banner, and that removing it hides the section. Evidence-or-nothing.

9. See also

do-not-reinvent.md · vow-sold-data-track.md (the SEPARATE board-sold track) · parent requirements doc §1.9.