Feature: Saved Search Alerts + Notification Center (Price Drops, New Matches, Open Houses)
#127 aperta il 10 gen 2026
Metriche repository
- Star
- (38 stelle)
- Metriche merge PR
- (Metriche PR in attesa)
Descrizione
Summary
Add Saved Searches that users can turn into alerts (in-app + optional email). Users define filters (price, beds/baths, zip/neighborhood, keywords, lifestyle tags, commute constraints, etc.). EstateWise periodically re-runs those queries against Pinecone / property store and notifies users when new listings match, prices drop, or status changes (pending/sold) for watched homes.
This creates a “market watch” loop so the app isn’t only reactive in chat.
Problem / Motivation
Right now, EstateWise excels at interactive discovery, but users must manually return and re-ask to track changes. Real estate decisions are time-sensitive; users want the app to keep watching and surface updates automatically.
Goals
-
Let authenticated users save searches from:
- the Map page query (
/map?q=...) - chat-derived filters (parsed intent)
- a dedicated “Saved Searches” UI
- the Map page query (
-
Run alerts on a schedule and generate notifications when there’s something new:
- New listing matches since last run
- Price drop > X% or > $Y
- Status changes (e.g., active → pending)
-
Provide a Notification Center page + badge in the navbar.
Non-goals (for first iteration)
- True real-time MLS streaming ingestion
- Paid tiering / billing
- SMS / WhatsApp (email + in-app first)
Proposed UX
-
User runs a search (Map or chat).
-
Click “Save search” → name it → choose alert types + frequency.
-
A bell icon shows unread notifications.
-
Notifications deep-link to:
/map?zpids=...for relevant homes- or a “Saved Search Results” view with diffs (new/changed)
Backend Design
Data model (MongoDB)
-
saved_searchesuserIdnamequery(raw string) + normalized filter JSON (structured)frequency(daily|hourly|custom)alertTypes(new_match,price_drop,status_change)lastRunAtlastResultIds(or hash / bloom-style summary)- thresholds:
priceDropPercent,priceDropAmount
-
notificationsuserIdtypetitlebodymetadata(zpids, old/new price, searchId)isReadcreatedAt
Job runner
- Simple start: Node cron in backend (or a dedicated worker container)
- More robust: queue-based (BullMQ/Redis) if desired later
Core algorithm
-
On each run:
-
Execute the saved query (
properties.search/ existing Pinecone search pipeline) -
Compare current results vs previous snapshot:
- New matches =
current - previous - For watched ZPIDs, compare last known price/status metadata
- New matches =
-
Emit notifications + update
lastRunAtand snapshot
-
API endpoints
POST /api/saved-searchescreateGET /api/saved-searcheslistPUT /api/saved-searches/:idupdate (frequency/thresholds)DELETE /api/saved-searches/:iddeletePOST /api/saved-searches/:id/runmanual run (debug)GET /api/notifications?unreadOnly=truePUT /api/notifications/:id/readPUT /api/notifications/read-all
Optional email
- Use provider abstraction (
EMAIL_ENABLE,EMAIL_FROM,RESEND_API_KEYetc.) - Send digest emails (e.g., daily) to avoid spam
Frontend Design
-
Saved Searches page:
- list cards with name, filters summary, last run, next run
- toggles for alert types + thresholds
- “Run now” (optional)
-
Notification Center page:
- grouped by date
- quick actions: mark read, open in map, open property detail
-
Navbar bell with unread badge
-
On Map and Chat:
- CTA “Save this search” (pre-fills config)
Acceptance Criteria
-
Authenticated users can create/update/delete saved searches
-
Alert job runs on schedule and generates notifications for:
- new matches
- price drop threshold
- status change
-
Notification Center UI displays unread/read states
-
Notifications deep-link to Map with
?zpids=...or saved search results -
No duplicate notifications for the same event (idempotency)
-
Basic tests:
- diff logic unit tests
- API route tests for CRUD + mark read
Implementation Notes / Risk
- Data freshness: depends on how/when property data is updated in Pinecone/DB. If updates are batchy, notifications should reflect that (show “as of …”).
- Idempotency: include a deterministic event key (
searchId + type + zpid + changeVersion) to prevent duplicates. - Load: cap max saved searches per user initially (e.g., 20) + cap topK per run.