Geospatial extension for FormBD - spatial indexing without compromising auditability.
Location-aware evidence tracking for investigative journalism.
FormBD-Geo adds geospatial capabilities to FormBD while preserving the core guarantees:
-
Auditability preserved - Spatial operations are projections, source data remains in FormBD
-
Reversibility maintained - Spatial index is derived, can be rebuilt from journal
-
Provenance tracked - "Where did this location data come from?"
┌─────────────────────────────────────────────────────────────┐
│ FormBD-Geo API │
│ REST endpoints for spatial queries │
├─────────────────────────────────────────────────────────────┤
│ Spatial Index (R-tree) │
│ Materialized projection of FormBD data │
│ Rebuilt on demand from FormBD journal │
├─────────────────────────────────────────────────────────────┤
│ FormBD HTTP API (reads) │
│ All writes go through FormBD (provenance preserved) │
└─────────────────────────────────────────────────────────────┘FormBD-Geo does NOT store source data. It:
-
Reads documents from FormBD via HTTP API
-
Extracts location fields (lat/lon, GeoJSON, WKT)
-
Builds spatial index as materialized view
-
Serves spatial queries against the index
-
Returns FormBD document IDs for full provenance
FormBD Journal (source of truth)
│
├── doc_123: { location: { lat: 51.5, lon: -0.1 }, ... }
├── doc_456: { location: { lat: 48.8, lon: 2.3 }, ... }
│
▼
FormBD-Geo R-tree Index (derived)
│
├── Point(51.5, -0.1) → doc_123
├── Point(48.8, 2.3) → doc_456
│
▼
Spatial Query: "within 10km of London"
│
▼
Result: [doc_123] (with full FormBD provenance)-
Point queries: Find documents at exact coordinates
-
Bounding box: Documents within rectangular region
-
Radius search: Documents within distance of point
-
Polygon containment: Documents within arbitrary shape
-
Nearest neighbor: K closest documents to point
-
Point (lat/lon)
-
LineString
-
Polygon
-
MultiPoint, MultiLineString, MultiPolygon
-
GeometryCollection
GET /geo/within-bbox?minLat=...&minLon=...&maxLat=...&maxLon=...
GET /geo/within-radius?lat=...&lon=...&radius=...&unit=km
GET /geo/within-polygon?geojson=...
GET /geo/nearest?lat=...&lon=...&k=10
POST /geo/reindex # Rebuild from FormBD
GET /geo/health # Index status# Find evidence within 50km of London
curl "http://localhost:8081/geo/within-radius?lat=51.5074&lon=-0.1278&radius=50&unit=km"
# Find evidence in bounding box (UK)
curl "http://localhost:8081/geo/within-bbox?minLat=49.9&minLon=-6.4&maxLat=55.8&maxLon=1.8"
# Find 10 nearest documents to a location
curl "http://localhost:8081/geo/nearest?lat=48.8566&lon=2.3522&k=10"{
"query": {
"type": "within-radius",
"center": { "lat": 51.5074, "lon": -0.1278 },
"radius_km": 50
},
"results": [
{
"formbd_id": "doc_123",
"location": { "lat": 51.5, "lon": -0.1 },
"distance_km": 0.82,
"provenance_url": "http://formbd:8080/documents/doc_123"
}
],
"index_timestamp": "2026-01-16T12:00:00Z",
"total_indexed": 15234
}# formbd-geo.toml
[formbd]
api_url = "http://localhost:8080"
collection = "evidence" # Collection to index
location_field = "location" # Field containing coordinates
[server]
host = "127.0.0.1"
port = 8081
[index]
# Rebuild interval (0 = manual only)
auto_rebuild_minutes = 0
# Memory limit for R-tree
max_memory_mb = 512| Component | Technology | Rationale |
|---|---|---|
Core |
Rust |
Performance, memory safety, no GC pauses |
Spatial Index |
rstar (R-tree) |
Pure Rust, no C dependencies |
HTTP Server |
axum |
Async, tower ecosystem |
Geometry |
geo crate |
Rust-native geometry primitives |
Serialization |
serde + GeoJSON |
Standard formats |
-
Not a PostGIS replacement - Use PostGIS for heavy GIS workloads
-
Not a tile server - Use Martin/pg_tileserv for map tiles
-
Not storing source data - FormBD is the source of truth
-
Not real-time tracking - Batch indexing from FormBD journal
formbd-geo/
├── src/
│ ├── main.rs # Entry point
│ ├── lib.rs # Library root
│ ├── index/
│ │ ├── mod.rs
│ │ ├── rtree.rs # R-tree implementation
│ │ └── projection.rs # FormBD → spatial projection
│ ├── api/
│ │ ├── mod.rs
│ │ ├── routes.rs # HTTP endpoints
│ │ └── queries.rs # Spatial query handlers
│ ├── formbd/
│ │ ├── mod.rs
│ │ └── client.rs # FormBD HTTP client
│ └── config.rs # Configuration
├── spec/
│ └── spatial-queries.adoc # Query specification
├── Cargo.toml
├── README.adoc
├── ECOSYSTEM.scm
├── STATE.scm
├── META.scm
└── LICENSE-
❏ R-tree spatial index
-
❏ FormBD HTTP client
-
❏ Bounding box queries
-
❏ Radius queries
-
❏ Manual reindex endpoint
-
❏ Polygon containment
-
❏ Nearest neighbor (k-NN)
-
❏ LineString queries (route intersection)
-
❏ Incremental index updates (watch FormBD journal)
-
❏ Index persistence (avoid full rebuild on restart)
-
❏ Query result caching
-
FormBD - The narrative-first database (source of truth)
-
FormBD Studio - GUI (map visualization target)
-
FormBD Analytics - OLAP analytics engine
-
BoFIG - Evidence graph (potential consumer)