v3.7.6 is the first version explicitly aligned to the imported demo frontend in interactive-map-explorer while preserving the backend architecture we settled on in v3.6 and v3.7:
- backend remains the source of truth for analysis
- overview remains a navigation layer, not a report generator
- detail remains the place where deterministic ranking happens
- final report remains a separate confirm action
- frontend should change as little as possible
This version therefore optimizes for:
- minimal frontend breakage
- backend-first implementation
- stable contracts that can keep evolving after the frontend catches up
- a Pensar-friendly architecture with thin adapters instead of duplicated logic
Overview is the city-scale map experience.
It supports:
generalamenitiestransitsafety
Overview does not generate reports.
Overview should help the user answer:
- where should I click next?
- which part of the city looks elevated under this lens?
Detail preview begins after the user clicks a point on the map.
The user can then adjust:
- radius:
200m,500m,1000m - priority ranking:
Amenities,Transit,Safety
Preview is deterministic and does not call the LLM.
Preview should answer:
- what rises to the top around this point right now?
- how does that change if I change the radius or reorder the priorities?
The detail panel contains a dedicated Generate Report button.
Only after the user clicks that button do we generate the final local governance brief.
The final report:
- reuses the same deterministic detail pipeline
- adds one LLM pass at the end
- stays grounded in evidence and local context
Open app
->
Overview map loads on "general"
->
User optionally switches map lens (general / amenities / transit / safety)
->
User clicks a point
->
Detail preview request runs
->
User changes radius and/or priority order
->
Detail preview refreshes
->
User clicks "Generate Report"
->
Final detail request runs
->
LLM writes local governance brief
v3.7.6 keeps three layers.
The React frontend remains the user-facing shell.
It should continue to:
- render the UI
- host drag ordering and radius controls
- own the detail panel state
It should not:
- reimplement analysis logic
- invent synthetic scores
server.js remains in the stack, but only as a thin integration layer.
Responsibilities:
- serve local vector tiles and fonts
- serve the built frontend if needed
- proxy a small whitelist of API routes to Python
- keep legacy demo endpoints alive as compatibility aliases
It should not:
- perform real analysis
- fabricate overview/detail results
- diverge from backend truth
Python remains the analysis system of record.
Responsibilities:
- overview contract
- detail preview
- detail final
- deterministic signals / trends / priorities / evidence
- final brief generation
Frontend-facing category labels stay aligned to the imported demo:
AmenitiesTransitSafety
Backend canonical ids in v3.7.6:
amenitiestransitsafetybuildingoverall
Accepted aliases:
general -> overalloverall -> overallfacilities -> amenitiestraffic -> transit
GET /api/healthGET /api/categoriesGET /api/coveragePOST /api/overviewPOST /api/detail/previewPOST /api/analyze-pointPOST /api/watchlist/run
These exist to preserve the current frontend shape with minimal rewiring:
GET /api/render/globalPOST /api/render/local
Behavior:
render/globaladapts to backendoverviewrender/localadapts to backenddetail preview
Node may also proxy through:
GET /api/healthGET /api/categoriesGET /api/coveragePOST /api/detail/previewPOST /api/analyze-pointPOST /api/watchlist/run
We do not force the frontend to abandon the demo map APIs immediately.
Instead:
Map.tsxkeeps using/api/render/globaland/api/render/localApp.tsxstarts using/api/detail/previewand/api/analyze-point- Node translates the legacy render endpoints into backend calls
This is the least disruptive path and best matches the current frontend code.
Allowed detail radii:
200m500m1000m
Recommended interpretation:
200m: immediate frontage / near-building context500m: walkable local context1000m: broader neighborhood context
The report must explicitly mention the selected radius.
These should use the selected user radius directly:
- collisions
- rodent inspections
- 311 complaints
- restaurant inspections
- LinkNYC
- public toilets
- street trees
- other point/facility signals
Building signals must use a bounded near-building radius:
building_radius = min(selected_radius, 250m)
This prevents building-specific risk from being washed out at 1000m.
These stay area-context proxies:
- EMS
- Fire
They must be described as ZIP-level context in the final report.
First implementation may continue to use simplified access/proxy logic.
If polygon precision is limited, the report should acknowledge it in data_gaps.
Final intended approach:
- radius-specific baselines for
200m,500m,1000m
Interim fallback:
- density-style normalization when radius-specific baselines are not ready
This prevents 1000m from looking worse purely because counts are larger.
Overview should return enough structure for the frontend to color cells later, even if the current map renderer still adapts them into point-like hints.
Recommended cell fields:
cell_idorh3latitudelongitudeoverall_scorecategory_scoresbuilding_stress_scorerisk_level
general on the frontend corresponds to backend overall.
overall is produced from fixed platform weights, not user drag order.
If overview layers are not ready:
- return
overview_ready: false - return empty
cells - return a UI message prompting point-based detail analysis
This must not crash the frontend.
Preview is the main deterministic local analysis payload.
It should include:
targetpriority_profilepriority_actionswhy_nowcurrent_statedetail_itemsevidence_tabledata_gapsscores
It should not include:
- LLM-generated longform brief
Final detail is preview plus:
report_summaryreport_markdown
The final report must be generated only when the user explicitly confirms with Generate Report.
We keep 4A as the final design.
Overview may expose aggregated building stress fields, but building is not a primary toggle category in the current map UX.
Detail includes a separate building section.
That section appears only when building findings exist.
Recommended outputs:
building_stress_scorebuilding_flagsopen_class_c_countaep_flagseverity_level
This keeps the backend ready for future building-specific map styling without overcommitting the frontend today.
When the user clicks a point:
- open detail panel
- run preview
- show local scores, top priorities, evidence, and preview narrative
When the user changes:
- radius
- drag order
the app refreshes preview only.
When the user clicks Generate Report:
- keep the same selected point
- keep the same radius
- keep the same priority order
- call final analysis endpoint
- replace preview narrative with final report text
The report should read like a concise local governance brief for managers, operators, or community-facing decision-makers.
It should not read like:
- a dashboard dump
- a rigid form
- a generic area summary
The prompt must ensure the report:
- states concrete conclusions
- mentions the selected radius
- distinguishes local-radius findings from ZIP-level service context
- explains why the current priorities rose to the top
- acknowledges data gaps
The prompt should not force identical paragraphing every time.
The model should be free to adapt to:
- good evidence
- bad evidence
- mixed evidence
- sparse evidence
The target is not a summary.
The target is:
a specific, evidence-grounded local conclusion about what matters most here right now
Final reports may include a light overview_context when available.
This should remain lightweight.
Example use:
- “This point sits within a citywide-elevated safety overview cell...”
It should not become a separate dominant report section.
If overview context is unavailable, the report should still complete successfully.
- schema version moved to
v3.7.6 - canonical categories align to frontend naming
detail previewremains a first-class endpoint
/api/render/globalnow adapts from backend/api/overview/api/render/localnow adapts from backend/api/detail/preview- Node proxies a safe whitelist of backend routes
- Node no longer needs synthetic analysis logic to serve the current frontend
- Vite proxies
/apito the Node server - map keeps existing render endpoints
- detail panel uses real preview/final requests
- detail panel gets a dedicated
Generate Reportbutton - building section appears only when building findings exist
Even after v3.7.6, some limitations remain.
The current search is still a lightweight offline landmark/coordinate resolver in the frontend.
It is acceptable for now because it only helps place the user on the map.
The existing map visual language still approximates overview coloring by adapting backend overview cells into point-based building coloring.
That is acceptable for this stage because:
- it preserves the existing frontend
- it keeps the backend contract stable
- it can later be upgraded to native cell or polygon rendering
The current detail panel is still visually score-heavy.
However, its data flow is now moving toward:
- preview priorities first
- report on explicit confirm
- evidence-backed narrative
v3.7.6 keeps the integration strategy compatible with the “Least Likely to get Hacked” direction:
- Python remains canonical
- Node remains a thin proxy, not a second analysis engine
- category ids are normalized
- radius is allow-listed
- render endpoints are compatibility wrappers, not free-form arbitrary queries
Future hardening should continue to tighten:
- CORS
- token-based demo auth
- request budgets
- watchlist size
- backend timeout behavior
v3.7.6 is considered landed when:
- overview buttons still work without rewriting the map component
- clicking a point opens detail preview from the real backend
- changing radius/order refreshes preview
- clicking
Generate Reportproduces final report text - building section appears only when building findings exist
- frontend no longer fabricates detail scores and summaries locally
- Node does not invent synthetic analysis responses for active product paths
- harden Node and Python for Pensar
- add
overview_contextinto final detail payload - improve real overview layer availability
- replace overview point adaptation with true cell rendering when frontend is ready
- promote batch/watchlist only after detail flow is fully stable