Milestone 1 — live web search: - mock/server.js: /search + /search-status proxy to the self-hosted SearXNG (third leg of the 3-source blend; engine endpoint stays server-side), /spatial + /spatial-status proxy to the spatial service - mock/app.js: background enrichment of suggestion cards — each candidate gets a web element (discovery cards + "you might like" rows) that is checked via SearXNG in the background (one in-flight query per place, 1 h TTL, failures retry in ~5 min) and APPENDS sourced facts with provenance URLs; never reorders/rewrites the plan. New LLM tools: web_search (cite URLs) and poi_near (PostGIS). Status badge gains 'web' / 'spatial'. - styles.css: .cc-web live-facts blocks, t-web verified chip Milestone 2 — PostGIS spatial DB (code complete; needs docker access to run — see spatial/README.md): - spatial/: docker-compose (postgis/postgis:16-3.4 + osm2pgsql:16 one-shot importer + spatiald), schema.sql (poi table w/ GIST index, spatial_extract bookkeeping, refresh_poi()), import.sh for the PBF extracts in ../osm, spatiald (Go, lib/pq): /health, /near (ST_DWithin), /nearest (KNN), /corridor (ST_Buffer along a route), with kind/name/extract/limit filters
82 lines
3.3 KiB
Markdown
82 lines
3.3 KiB
Markdown
# spatial — PostGIS source of truth
|
|
|
|
Native spatial queries for the trip planner (DESIGN.md §Data: "PostGIS
|
|
(Postgres) — import PBF via osm2pgsql; gives SQL spatial queries (radius,
|
|
nearest, bbox)"). Replaces the flat-file/Overpass approximations.
|
|
|
|
## Stack
|
|
|
|
| Piece | What it is |
|
|
|---|---|
|
|
| `docker-compose.yml` | `postgis/postgis:16-3.4` (DB, port 5432) + one-shot `osm2pgsql:16` importer + `spatiald` (query service, port 5005) |
|
|
| `schema.sql` | runs on first boot: `poi` table (named POIs as points, GIST index), `spatial_extract` bookkeeping, `refresh_poi()` |
|
|
| `import.sh` | loads a PBF from `../osm/` via osm2pgsql, refreshes `poi` |
|
|
| `main.go` (spatiald) | JSON query service over `poi` |
|
|
| `Dockerfile` | builds spatiald |
|
|
|
|
## Prerequisites
|
|
|
|
* Docker with the current user in the `docker` group (on this box:
|
|
one-time `sudo usermod -aG docker $USER`, then re-login).
|
|
* PBF extracts in `../osm/` (already present: `nh.osm.pbf`,
|
|
`colombia.osm.pbf`, US state extracts).
|
|
|
|
## Usage
|
|
|
|
```bash
|
|
docker compose up -d postgis # first: runs schema.sql
|
|
./import.sh ../osm/nh.osm.pbf nh # load New England (default)
|
|
./import.sh ../osm/colombia.osm.pbf colombia
|
|
docker compose up -d spatiald # query service on :5005
|
|
```
|
|
|
|
The mock server (`mock/server.js`) proxies it: `GET /spatial/*` → `:5005`,
|
|
plus `GET /spatial-status` for the UI badge. When the service is up, the
|
|
chat assistant gains the `poi_near` tool automatically.
|
|
|
|
## spatiald endpoints
|
|
|
|
All return `{"count":N,"results":[{extract,osm_id,name,kind,opening_hours,
|
|
fee,website,addr_city,dist_m},…]}`. Common filters:
|
|
|
|
* `extract=nh` — one loaded extract
|
|
* `kind=amenity=restaurant` — exact kind, or `kind=restaurant` (any family)
|
|
* `name=café` — ILIKE substring
|
|
* `limit=20` (max 200)
|
|
|
|
| Endpoint | Query | SQL core |
|
|
|---|---|---|
|
|
| `GET /health` | — | extract bookkeeping |
|
|
| `GET /near` | `lat,lng,r(m; default 500)` | `ST_DWithin(geography, …, r)` + KNN ordering |
|
|
| `GET /nearest` | `lat,lng` | `ORDER BY geom <-> point` |
|
|
| `GET /corridor` | `points=lng,lat;…`, `r` | `ST_DWithin(geom::geography, ST_Buffer(line::geography, r))` |
|
|
|
|
Examples:
|
|
|
|
```bash
|
|
curl 'localhost:5005/near?lat=42.35&lng=-71.06&r=1000&kind=restaurant'
|
|
curl 'localhost:5005/nearest?lat=10.40&lng=-75.54&kind=tourism&limit=5'
|
|
curl 'localhost:5005/corridor?r=300&kind=fuel&points=-71.06,42.35;-71.07,42.36'
|
|
```
|
|
|
|
## Data notes
|
|
|
|
* `poi` covers every **named** node (or polygon way, via centroid) with an
|
|
`amenity`/`tourism`/`shop`/`leisure`/`historic`/`place` tag — the kinds the
|
|
planner asks about. Unnamed amenities (e.g. a nameless kiosk) are out of
|
|
scope for v1.
|
|
* `opening_hours`, `fee`, `website`, `addr_city` are carried straight from
|
|
the OSM tags; the live web enrichment (SearXNG, `mock/app.js`) fills gaps
|
|
the tags don't have (the 3-source blend).
|
|
* Multiple extracts coexist in one DB, disambiguated by `poi.extract`
|
|
(set automatically by `import.sh`).
|
|
* pgvector (semantic POI index, later milestone) gets its own init script +
|
|
embedding importer — the base image doesn't ship the `vector` package.
|
|
|
|
## Roadmap hooks
|
|
|
|
* `bbox` queries: trivial addition (`ST_Contains(ST_MakeEnvelope,…)`).
|
|
* Routing-graph join: OSRM/GraphHopper geometries can be loaded into the
|
|
same DB (`route_geom` table) for true along-route analytics instead of
|
|
the current buffer-over-polyline.
|