← back to Commercialrealestate

scripts/sources/wholivedthere.js

102 lines

// sources/wholivedthere.js — READ-ONLY bridge from the CRE app to the WhoLivedThere / stayclaim /
// pastdoor archive (local Postgres DB `pastdoor`). Given a listing's street address, returns the
// property-history facts the archive holds: LA County assessor parcel (year built, units, use type,
// assessed land/improvement/total value), building-permit history (alterations + valuations),
// curated place events, and film-shoot history ("filmed here").
//
// HONEST SCOPE: pastdoor is a CURATED archive, not a full county parcel DB (la_parcel ~252,
// la_permit ~25, place_event ~71, filming_location ~1528 but keyed to featured listings). So most
// commercial CRE addresses will return NO match — that's expected. When it DOES hit, the assessor
// value + permit history are genuinely useful underwriting cross-checks. The bridge never throws into
// the request path: any DB error returns { available:false } so the CRE app degrades gracefully.
//
// Connection: local Unix socket (/tmp) as the OS user, matching how psql reaches pastdoor (peer auth,
// no password). Override with WLT_PG* env if the DB moves. Read-only by intent — only SELECTs here.

'use strict';
const { Pool } = require('pg');

const pool = new Pool({
  host: process.env.WLT_PGHOST || '/tmp',
  port: +(process.env.WLT_PGPORT || 5432),
  database: process.env.WLT_PGDATABASE || 'pastdoor',
  user: process.env.WLT_PGUSER || process.env.USER || 'stevestudio2',
  max: 4, idleTimeoutMillis: 10000, connectionTimeoutMillis: 4000,
  // statement_timeout guards against a runaway query blocking the CRE viewer.
  statement_timeout: 4000
});
pool.on('error', () => {}); // never crash the host process on an idle-client error

// Split a street address into a leading house number + the first significant street-name word, so we
// can match "13350 Victory Blvd" against assessor strings like "13350 VICTORY BLVD VAN NUYS CA 91401".
function addrParts(address) {
  const s = String(address || '').trim();
  const num = (s.match(/^\s*(\d+)/) || [])[1] || '';
  const name = (s.replace(/^\s*\d+\s*/, '')
    .replace(/\b(n|s|e|w|north|south|east|west)\b/gi, ' ')
    .match(/[a-z]{3,}/i) || [])[0] || '';
  return { num, name };
}

let warned = false;

// lookupAddress: best-effort property-history enrichment for one address. Returns:
//   { available:true, matched:true, parcel, permits[], events[], filming[] }  on a hit
//   { available:true, matched:false }                                          when the archive has nothing
//   { available:false, reason }                                                when the DB can't be reached
async function lookupAddress(address, city /*, zip */) {
  const { num, name } = addrParts(address);
  if (!num || !name) return { available: true, matched: false };
  let client;
  try {
    client = await pool.connect();
    // Parcel: number-prefix AND street-name contained. City is a soft bonus (assessor city strings
    // are abbreviated, e.g. "W HOLLYWOOD CA"), so we don't hard-filter on it.
    const parcelQ = await client.query(
      `select apn, situs_address, city, zip, year_built, effective_year, sqft_main, units, use_type,
              use_description, land_value, improvement_value, total_value, roll_year, listing_id
         from la_parcel
        where situs_address ilike $1 and situs_address ilike $2
        order by (city ilike $3) desc, roll_year desc nulls last
        limit 1`,
      [num + '%', '%' + name + '%', '%' + String(city || '') + '%']
    );
    const parcel = parcelQ.rows[0] || null;

    const permitsQ = await client.query(
      `select permit_nbr, primary_address, permit_type, permit_subtype, status, issue_date, valuation, use_description
         from la_permit
        where primary_address ilike $1 and primary_address ilike $2
        order by issue_date desc nulls last
        limit 8`,
      [num + '%', '%' + name + '%']
    );

    let events = [], filming = [];
    if (parcel && parcel.listing_id) {
      const ev = await client.query(
        `select kind, summary, valid_from, source_label
           from place_event
          where listing_id = $1 and coalesce(public_visible, true) = true
          order by valid_from desc nulls last limit 10`, [parcel.listing_id]);
      events = ev.rows;
      const fl = await client.query(
        `select fl.role, fl.scene_note, fl.shoot_date_from, p.title, p.year, p.kind
           from filming_location fl left join film_production p on p.id = fl.production_id
          where fl.listing_id = $1 and coalesce(fl.public_visible, true) = true
          order by fl.shoot_date_from desc nulls last limit 10`, [parcel.listing_id]);
      filming = fl.rows;
    }

    const matched = !!(parcel || permitsQ.rows.length);
    return { available: true, matched, parcel, permits: permitsQ.rows, events, filming };
  } catch (e) {
    if (!warned) { console.warn('[wholivedthere] DB unavailable:', e.message); warned = true; }
    return { available: false, reason: e.message };
  } finally {
    if (client) client.release();
  }
}

module.exports = { lookupAddress, addrParts, pool };