The Property Finder enables users to search for real estate listings on the external market, save favorites, and manage saved searches. It integrat...
The Property Finder enables users to search for real estate listings on the external market, save favorites, and manage saved searches. It integrates with the RapidAPI "Realty in US" service to pull live property data and constructs validated listing URLs for realtor.com.
Client Server External
───────────────────── ───────────────────── ──────────────────
PropertyFinder.tsx → GET /api/property-finder/search → RapidAPI (Realty in US)
├─ Search tab → GET /api/property-finder/favorites
├─ Saved Searches tab → GET /api/property-finder/saved-searches
└─ Saved Properties → POST/DELETE /api/property-finder/favorites
POST/DELETE /api/property-finder/saved-searches
PATCH /api/property-finder/favorites/:id/notes
| Column | Type | Description |
|---|---|---|
| id | integer (PK) | Auto-generated identity |
| userId | integer (FK → users) | Owner |
| externalId | text | RapidAPI property_id |
| source | text | Always "realty-in-us" |
| address | text | Full address string |
| city | text | City name |
| state | text | Two-letter state code |
| zipCode | text | Postal code |
| price | real | Listing price |
| beds | integer | Bedroom count |
| baths | real | Bathroom count |
| sqft | real | Square footage |
| lotSizeAcres | real | Lot size in acres |
| propertyType | text | e.g., "single_family" |
| imageUrl | text | Primary photo URL |
| listingUrl | text | Validated realtor.com permalink |
| notes | text | User notes |
| rawData | jsonb | Full API response for reference |
| savedAt | timestamp | When favorited |
Unique constraint: (userId, externalId, source) — prevents duplicate favorites.
| Column | Type | Description |
|---|---|---|
| id | integer (PK) | Auto-generated identity |
| userId | integer (FK → users) | Owner |
| name | text | User-given search name |
| location | text | City, ST or ZIP |
| priceMin | text | Minimum price filter |
| priceMax | text | Maximum price filter |
| bedsMin | text | Minimum bedrooms filter |
| lotSizeMin | text | Minimum lot size (acres) |
| propertyType | text | Property type filter |
| savedAt | timestamp | When saved |
All routes require authentication (requireAuth).
GET /api/property-finder/search
| Param | Type | Required | Description |
|---|---|---|---|
| location | string | Yes | City, ST or ZIP code |
| priceMin | string | No | Min list price |
| priceMax | string | No | Max list price |
| bedsMin | string | No | Minimum bedrooms |
| lotSizeMin | string | No | Minimum lot size (acres) |
| propertyType | string | No | Property type filter ("any" = no filter) |
| offset | string | No | Pagination offset (default 0) |
Rate limited: 30 requests per minute per user.
Response: { results: NormalizedProperty[], total: number, offset: number }
| Method | Route | Description |
|---|---|---|
| GET | /api/property-finder/favorites | List user's saved properties |
| POST | /api/property-finder/favorites | Save a property |
| DELETE | /api/property-finder/favorites/:id | Remove a saved property |
| PATCH | /api/property-finder/favorites/:id/notes | Update notes on a saved property |
| Method | Route | Description |
|---|---|---|
| GET | /api/property-finder/saved-searches | List user's saved searches |
| POST | /api/property-finder/saved-searches | Save a search |
| DELETE | /api/property-finder/saved-searches/:id | Delete a saved search |
Realtor.com blocks server-side HEAD requests with 403 (bot detection). Instead of validating URLs by hitting the target site, we use format-based validation:
r.href or r.permalink from the API response. If it matches /realestateandhomes-detail/, prepend https://www.realtor.com.https://www.realtor.com/realestateandhomes-detail/{line}_{city}_{state}_{zip}_{property_id}
Address components: spaces → hyphens, non-alphanumeric stripped, joined with underscores.Stored URLs are validated against the regex pattern:
/^https:\/\/www\.realtor\.com\/realestateandhomes-detail\//
Invalid URLs are nulled out at read time (not mutated in DB).