← back to Commercialrealestate
CRCP agent-profile: agents now show their real listings across ALL data paths — commercial (broker_listing), condo (broker_condo edge + condoBrokers() overlay by name/co-agent), and an overlay-only profile for residential agents not in the broker graph; fixes empty agent pages found in the 5x click-through test
0b756296d5701686e48c560b001165ab253ee802 · 2026-08-19 10:15:13 -0700 · Steve Abrams
Files touched
Diff
commit 0b756296d5701686e48c560b001165ab253ee802
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Wed Aug 19 10:15:13 2026 -0700
CRCP agent-profile: agents now show their real listings across ALL data paths — commercial (broker_listing), condo (broker_condo edge + condoBrokers() overlay by name/co-agent), and an overlay-only profile for residential agents not in the broker graph; fixes empty agent pages found in the 5x click-through test
---
scripts/serve.js | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 50 insertions(+), 3 deletions(-)
diff --git a/scripts/serve.js b/scripts/serve.js
index 747c11c..7489d07 100644
--- a/scripts/serve.js
+++ b/scripts/serve.js
@@ -350,13 +350,60 @@ app.get('/api/agent-profile', async (req, res) => {
FROM broker b LEFT JOIN firm f ON f.id = b.firm_id`;
const b = (await brokerdb.pool.query(
id ? `${sel} WHERE b.id = $1 LIMIT 1`
- : `${sel} WHERE lower(b.name) = lower($1) ORDER BY (b.phone IS NOT NULL OR b.email IS NOT NULL) DESC NULLS LAST LIMIT 1`,
+ : `${sel} WHERE lower(b.name) = lower($1)
+ ORDER BY ((SELECT count(*) FROM broker_listing bl WHERE bl.broker_id=b.id)
+ + (SELECT count(*) FROM broker_condo bc WHERE bc.broker_id=b.id)) DESC,
+ (b.phone IS NOT NULL OR b.email IS NOT NULL) DESC NULLS LAST LIMIT 1`,
[id || name])).rows[0];
- if (!b) return res.json({ name, firm: null, listings: [], found: false });
- const listings = (await brokerdb.pool.query(
+ if (!b) {
+ // The agent may exist ONLY in the condo overlay (a residential listing agent not in the broker
+ // graph). Recover their profile + condos from condoBrokers() so their page isn't empty.
+ const ov = condoBrokers(); const nlc = name.toLowerCase(); let contact = null;
+ const ids = name ? Object.keys(ov).filter(cid => { const e = ov[cid] || {};
+ const ae = Array.isArray(e.agents) ? e.agents.find(a => a && String(a.name || '').toLowerCase() === nlc) : null;
+ const hit = (e.broker_name && String(e.broker_name).toLowerCase() === nlc) || !!ae;
+ if (hit && !contact) contact = { firm: (ae && ae.firm) || e.firm_name || null, dre: (ae && ae.dre) || e.broker_dre || null, phone: e.agent_phone || null, email: e.agent_email || null };
+ return hit; }) : [];
+ if (!ids.length) return res.json({ name, firm: null, listings: [], found: false });
+ const oc = (await brokerdb.pool.query(
+ `SELECT address, city, zip, 'Condo' AS type, price, NULL::int AS units, NULL::numeric AS cap_rate
+ FROM condo_card WHERE id::text = ANY($1::text[]) ORDER BY price DESC NULLS LAST`, [ids]).catch(() => ({ rows: [] }))).rows;
+ return res.json({ found: true, id: null, name, firm: contact && contact.firm, phone: contact && contact.phone,
+ email: contact && contact.email, title: null, agent_type: 'residential', license: contact && contact.dre, office: null, linkedin: null,
+ listings: oc, count: oc.length, closed: [], closed_count: 0, firm_listings: [], firm_count: 0,
+ total_value: oc.reduce((s, l) => s + Number(l.price || 0), 0), closed_value: 0,
+ cities: [...new Set(oc.map(l => l.city).filter(Boolean))], source: 'condo-overlay' });
+ }
+ const commercial = (await brokerdb.pool.query(
`SELECT l.address, l.city, l.zip, l.type, l.price, l.units, l.cap_rate
FROM broker_listing bl JOIN listing l ON l.id = bl.listing_id
WHERE bl.broker_id = $1 ORDER BY l.price DESC NULLS LAST`, [b.id])).rows;
+ // Condo listings — a residential agent's book lives in broker_condo → condo (NOT broker_listing),
+ // so an agent surfaced from condos.html would otherwise show an empty page. Mirrors /api/firm.
+ const condoRows = (await brokerdb.pool.query(
+ `SELECT c.address, c.city, NULL::text AS zip, 'Condo' AS type, c.price, NULL::int AS units, NULL::numeric AS cap_rate
+ FROM broker_condo bc JOIN condo c ON c.id = bc.condo_id
+ WHERE bc.broker_id = $1 ORDER BY c.price DESC NULLS LAST`, [b.id]).catch(() => ({ rows: [] }))).rows;
+ // Name-match fallback: broker↔listing edges are sparse; a condo often stores the agent only as a
+ // broker_name STRING (no broker_condo row). So also pull condos where broker_name matches this agent,
+ // so a named-but-unlinked agent (seen on condos.html) still shows their book. Deduped by address+city.
+ // The condo↔agent linkage lives in the id-keyed condoBrokers() overlay (condo_card.broker_name is
+ // overwritten by it), so a name-column match misses co-listing agents. Scan the overlay by name to
+ // recover EVERY condo this agent is on (primary or co-agent), then fetch those cards.
+ let overlayCondos = [];
+ try {
+ const ov = condoBrokers(); const nlc = String(b.name || '').toLowerCase();
+ const ids = b.name ? Object.keys(ov).filter(cid => { const e = ov[cid] || {};
+ return (e.broker_name && String(e.broker_name).toLowerCase() === nlc)
+ || (Array.isArray(e.agents) && e.agents.some(a => a && String(a.name || '').toLowerCase() === nlc)); }) : [];
+ if (ids.length) overlayCondos = (await brokerdb.pool.query(
+ `SELECT address, city, zip, 'Condo' AS type, price, NULL::int AS units, NULL::numeric AS cap_rate
+ FROM condo_card WHERE id::text = ANY($1::text[]) ORDER BY price DESC NULLS LAST`, [ids]).catch(() => ({ rows: [] }))).rows;
+ } catch (_) {}
+ const seen = new Set();
+ const listings = commercial.concat(condoRows, overlayCondos)
+ .filter(l => { const k = (l.address || '') + '|' + (l.city || ''); if (seen.has(k)) return false; seen.add(k); return true; })
+ .sort((x, y) => Number(y.price || 0) - Number(x.price || 0));
// Past / closed (sold) listings — the agent's track record, mirrors /api/broker.
const closed = (await brokerdb.pool.query(
`SELECT address, city, sold_price, sold_date, type, source
← 58c2ad4 auto-data-snapshot: 2026-08-19T10:08:05 (1 data files) — dat
·
back to Commercialrealestate
·
CRCP: backfill broker contacts for Lyon Stahl/WESTMAC/BuildO fb68fcb →