← back to Ventura Corridor
iter 62: walk-route priority-aware ordering — /api/pitches/walk-route?sort=(geographic|priority); priority sort joins through v_building_roster and orders by inline-computed priority_score (unpitched / GREATEST(miles, 0.05)), groups all doors at same building together so Steve walks highest-leverage building floor-by-floor before moving on; also filters out merged_into businesses; /walk-route.html gets a 'route order' selector at the top of the controls — Geographic (E↔W lap) vs ⚡ Priority (highest-leverage bldgs first); direction selector auto-hides when in priority mode (irrelevant); top 8 priority slots all from 15821 Ventura (score 1183, 556 unpitched doors)
31c424310a98bc175a4e16c230fa36e7cc32abde · 2026-05-06 14:30:20 -0700 · SteveStudio2
Files touched
M public/walk-route.htmlM src/server/index.ts
Diff
commit 31c424310a98bc175a4e16c230fa36e7cc32abde
Author: SteveStudio2 <steve@designerwallcoverings.com>
Date: Wed May 6 14:30:20 2026 -0700
iter 62: walk-route priority-aware ordering — /api/pitches/walk-route?sort=(geographic|priority); priority sort joins through v_building_roster and orders by inline-computed priority_score (unpitched / GREATEST(miles, 0.05)), groups all doors at same building together so Steve walks highest-leverage building floor-by-floor before moving on; also filters out merged_into businesses; /walk-route.html gets a 'route order' selector at the top of the controls — Geographic (E↔W lap) vs ⚡ Priority (highest-leverage bldgs first); direction selector auto-hides when in priority mode (irrelevant); top 8 priority slots all from 15821 Ventura (score 1183, 556 unpitched doors)
---
public/walk-route.html | 13 ++++++++++++-
src/server/index.ts | 27 +++++++++++++++++++++++++--
2 files changed, 37 insertions(+), 3 deletions(-)
diff --git a/public/walk-route.html b/public/walk-route.html
index 147955b..600d39d 100644
--- a/public/walk-route.html
+++ b/public/walk-route.html
@@ -165,6 +165,13 @@
<div class="controls">
<div class="ctrl-group">
+ <label>route order</label>
+ <select id="sort">
+ <option value="geographic" selected>Geographic (E↔W lap)</option>
+ <option value="priority">⚡ Priority (highest-leverage bldgs first)</option>
+ </select>
+ </div>
+ <div class="ctrl-group" id="direction-group">
<label>direction</label>
<select id="direction">
<option value="east">East (Sherman Oaks → Encino)</option>
@@ -254,10 +261,13 @@ const PITCH_SCRIPT = {
let allRows = [];
async function load() {
+ const sort = document.getElementById('sort').value;
const direction = document.getElementById('direction').value;
const limit = document.getElementById('limit').value;
const filterStatus = document.getElementById('filter-status').value;
- const url = `/api/pitches/walk-route?direction=${direction}&limit=${limit}`;
+ // Hide direction selector when sorting by priority — it's irrelevant
+ document.getElementById('direction-group').style.display = sort === 'priority' ? 'none' : '';
+ const url = `/api/pitches/walk-route?sort=${sort}&direction=${direction}&limit=${limit}`;
const res = await fetch(url);
if (!res.ok) {
document.getElementById('route').innerHTML = `<div class="empty"><div class="big">Could not load route.</div><div>${res.status} ${res.statusText}</div></div>`;
@@ -385,6 +395,7 @@ async function markAllSent(stopOrder) {
function reload() { load(); }
+document.getElementById('sort').addEventListener('change', load);
document.getElementById('direction').addEventListener('change', load);
document.getElementById('limit').addEventListener('change', load);
document.getElementById('filter-status').addEventListener('change', load);
diff --git a/src/server/index.ts b/src/server/index.ts
index 85ba2fe..7c8d907 100644
--- a/src/server/index.ts
+++ b/src/server/index.ts
@@ -629,19 +629,42 @@ app.get('/api/pitches/walk-route', async (req, res) => {
try {
const limit = Math.min(parseInt(String(req.query.limit ?? '30'), 10) || 30, 80);
const direction = String(req.query.direction || 'east'); // 'east' | 'west'
+ const sort = String(req.query.sort || 'geographic'); // 'geographic' | 'priority'
+
+ let orderClause: string;
+ let extraSelect = '';
+ if (sort === 'priority') {
+ // Group all doors at the same building together, ordered by that building's priority score.
+ // priority_score is computed inline (same formula as /api/buildings/priority).
+ extraSelect = `,
+ TRIM(regexp_replace(b.address, '\\s*(SUITE|STE|UNIT|#).*$', '', 'i')) AS bldg_address,
+ ROUND((br.unpitched::numeric / GREATEST(br.dw_miles, 0.05)::numeric)::numeric, 1) AS priority_score`;
+ orderClause = `(br.unpitched::numeric / GREATEST(br.dw_miles, 0.05)::numeric) DESC NULLS LAST, br.bldg_address ASC, p.priority ASC`;
+ } else {
+ orderClause = `b.lng ${direction === 'west' ? 'DESC' : 'ASC'}, b.lat ASC`;
+ }
+
+ const joinClause = sort === 'priority'
+ ? `LEFT JOIN v_building_roster br
+ ON br.bldg_address = TRIM(regexp_replace(b.address, '\\s*(SUITE|STE|UNIT|#).*$', '', 'i'))`
+ : '';
+
const r = await query(`
SELECT p.id, p.pitch_type, p.priority, p.status, p.dw_proximity, p.li_message,
b.name, b.address, b.city, b.zip, b.lat, b.lng,
p.research_links->>'gmaps' AS gmaps_url
+ ${extraSelect}
FROM pitches p
JOIN businesses b ON b.id = p.business_id
+ ${joinClause}
WHERE p.dw_proximity IN ('same_building','same_block','walk_2min','walk_5min','walk_10min')
AND p.status NOT IN ('skip','sent','won','lost')
AND b.lat IS NOT NULL AND b.lng IS NOT NULL
- ORDER BY b.lng ${direction === 'west' ? 'DESC' : 'ASC'}, b.lat ASC
+ AND b.merged_into IS NULL
+ ORDER BY ${orderClause}
LIMIT $1
`, [limit]);
- res.json({ count: r.rowCount, direction, rows: r.rows });
+ res.json({ count: r.rowCount, direction, sort, rows: r.rows });
} catch (e: any) {
res.status(500).json({ error: e.message });
}
← 40a7c21 iter 61: building prioritization 'walk here next' — /api/bui
·
back to Ventura Corridor
·
iter 63: 🏇 crawl derby — racetrack-style live progress view 1c3e46f →