Incident reports, normalised, geocoded against a local Nominatim and stored as PostGIS geography. One vertical path from a raw record to a point on a map, and one registry from which every surface is generated.
source record → normalise (CrisisMap.Ingest.Normalizer) → persist (CrisisMap.Events, idempotent on external_id) → geocode (CrisisMap.Geocoding, adapter: Nominatim) → store position (geography(Point,4326), or NULL with a reason) → query (PostGIS ST_DWithin / ST_Distance) → LiveView (map, list, detail, filters)
11 capabilities are declared once and projected onto each of these. None of them can offer an operation the others do not.
| Surface | Where |
|---|---|
| Command line | mix crisis_map.run <capability> |
| JSON API | /api/v1/… |
| OpenAPI | openapi.json, Swagger UI |
| MCP | POST /mcp (JSON-RPC: initialize, tools/list, tools/call) |
| Cockpit | /cockpit |
| Documentation | capabilities, catalog |
Every stored event separates what the source said from what this system
worked out. The source fields are normalised, never invented; the derived
fields always carry the evidence that produced them, and an unknown
position is NULL with a status that says why — never a
guessed coordinate.