[object Object]

← back to Nationalrealestate

USRE: searched address in a parcel-covered county deep-links to the property page (prefill+auto-search); graceful fallback to county market (v0.14.0)

7c0710ffac35aa9c2b1abbd31be5d450bded7496 · 2026-07-26 21:25:46 -0700 · Steve

Files touched

Diff

commit 7c0710ffac35aa9c2b1abbd31be5d450bded7496
Author: Steve <steve@designerwallcoverings.com>
Date:   Sun Jul 26 21:25:46 2026 -0700

    USRE: searched address in a parcel-covered county deep-links to the property page (prefill+auto-search); graceful fallback to county market (v0.14.0)
---
 package-lock.json    |  4 ++--
 package.json         |  2 +-
 public/property.html |  4 ++++
 src/server/index.ts  | 23 +++++++++++++++++++++--
 4 files changed, 28 insertions(+), 5 deletions(-)

diff --git a/package-lock.json b/package-lock.json
index 68254b3..7b9f6a3 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
 {
   "name": "nationalrealestate",
-  "version": "0.13.0",
+  "version": "0.14.0",
   "lockfileVersion": 3,
   "requires": true,
   "packages": {
     "": {
       "name": "nationalrealestate",
-      "version": "0.13.0",
+      "version": "0.14.0",
       "dependencies": {
         "better-sqlite3": "^13.0.1",
         "dotenv": "^16.4.5",
diff --git a/package.json b/package.json
index 35be955..035c45f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "nationalrealestate",
-  "version": "0.13.0",
+  "version": "0.14.0",
   "private": true,
   "type": "module",
   "description": "USRealEstate — national U.S. residential market explorer. Free-data v1 (Redfin Data Center, Zillow Research, Census ACS, FHFA). Internal analyst tool behind basic auth.",
diff --git a/public/property.html b/public/property.html
index c3ef4f3..8eb247d 100644
--- a/public/property.html
+++ b/public/property.html
@@ -352,7 +352,11 @@ async function initCounties(){
 
 initCounties();
 const loc = qs.get('loc');
+const prefillQ = qs.get('q');
 if (loc) load(loc);
+else if (prefillQ) { // deep-linked from the top location search — prefill + auto-run the address search
+  const qi = document.getElementById('q'); qi.value = prefillQ; search(prefillQ);
+}
 </script>
 <script src="/nav-drawer.js"></script>
 <script src="/geo-search.js"></script>
diff --git a/src/server/index.ts b/src/server/index.ts
index c58f0bc..f10bd5e 100644
--- a/src/server/index.ts
+++ b/src/server/index.ts
@@ -122,6 +122,18 @@ app.get('/api/regions', async (req, res) => {
   }
 });
 
+// parcel-covered counties (parcel_source registry), cached — lets geo-search deep-link
+// an address to the property page only where we actually have parcels.
+let _coveredCache: { at: number; set: Set<string> } | null = null;
+async function coveredCounties(): Promise<Set<string>> {
+  if (_coveredCache && Date.now() - _coveredCache.at < 10 * 60_000) return _coveredCache.set;
+  try {
+    const r = await query<{ county_fips: string }>(`SELECT county_fips FROM parcel_source`);
+    _coveredCache = { at: Date.now(), set: new Set(r.rows.map(x => x.county_fips)) };
+  } catch { _coveredCache = { at: Date.now(), set: new Set() }; }
+  return _coveredCache.set;
+}
+
 // universal location search — resolves a typed county / city / metro / state to a
 // market page. National coverage via the region table (fast; ~4.2k rows). ZIP + exact
 // street address are county-scoped and live on the property page (no national ZIP index).
@@ -154,10 +166,17 @@ app.get('/api/geo-search', async (req, res) => {
           const r = await query<{ canonical_key: string; name: string; state_code: string | null }>(
             `SELECT canonical_key, name, state_code FROM region WHERE fips = $1 AND region_type = 'county'`, [co.GEOID]);
           if (r.rows.length) { const x = r.rows[0];
+            // property-level intent: if the county has parcel coverage, deep-link into the
+            // property page prefilled with the address; else fall back to the county market.
+            const covered = await coveredCounties();
+            const hasParcels = covered.has(co.GEOID);
+            const url = hasParcels
+              ? '/property.html?county=' + encodeURIComponent(co.GEOID) + '&q=' + encodeURIComponent(q)
+              : '/market.html?key=' + encodeURIComponent(x.canonical_key);
             return res.json({ q, results: [{ type: 'address', name: m.matchedAddress || q, state: x.state_code || null,
-              sub: x.name, key: x.canonical_key, url: '/market.html?key=' + encodeURIComponent(x.canonical_key) }] }); }
+              sub: hasParcels ? x.name + ' · view property →' : x.name, key: x.canonical_key, url }] }); }
         }
-      } catch (e) { /* geocoder timeout/failure → fall through to name search */ }
+      } catch (e) { /* geocoder timeout/failure → fall through to empty (client shows a hint) */ }
       return res.json({ q, results: [] });
     }
 

← e08091b USRE: geo-search now resolves ZIP (zip_county crosswalk) + s  ·  back to Nationalrealestate  ·  USRE geo-search: recent searches (localStorage) shown on emp 9ab361e →