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); DBlocal_business_listings.statusalready carries'sold'rows. - Section already exists:
RealEstateSiteTemplate.tsxalready renders<SoldStoriesSection config soldListings />wheresoldListings = 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/soldpage + richer treatment. - Listings manager exists: the self-serve Listings CRUD on
local_business_listings(/realtor/app+/api/real-estate/listings) — extend to setstatus='sold'+ a SOLDbanner(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_listingswithstatus='sold'. Decision (flag): to display a sold price/date, add nullablesold_price numeric+sold_date datecolumns (migration inchurchwiseai-web/migrations/); MVP can ship with just the SOLD banner +list_priceif we defer sold-price display. Own-sold rows aresource='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
SoldStoriesSectionrenders when the tenant has ≥1 sold listing; empty → section hidden (no empty state). - Dedicated
/s/[slug]/soldpage: 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
- 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. - A tenant with zero sold listings shows no sold section (homepage) and an honest empty state on
/sold. - SOLD banner renders; sold price/date shows only when set.
- Sold rows are
source='manual'; no board/DDF row is ever relabeled sold (DDF carries no sold data). - 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.