React Native + Expo
Cross-platform app, New Architecture enabled. Expo Router for navigation, EAS for builds and over-the-air updates.
Technical details
Tsamaya is a React Native app backed by a geospatial database and a Python data pipeline with a Claude-assisted review step. Here’s how the pieces fit.
The stack
Cross-platform app, New Architecture enabled. Expo Router for navigation, EAS for builds and over-the-air updates.
Map tiles, Directions API for routing, and Geocoding for search and reverse-geocoding the map.
Postgres with PostGIS geometry holds every zone and corridor. The app reads live; the editor writes via typed RPC functions.
Map-data fetch → proprietary crime-density scoring → zone/corridor classification → staging → promotion to live.
A second-opinion review pass flags questionable classifications for a human before anything reaches drivers.
Versioned SQL migrations keep the database reproducible; TestFlight and Google Play open testing get builds to testers.
Three repos, one system
Crime and map data flow through a pipeline, get reviewed, then go live for the app to read.
The routing model
The routing logic is a small set of deliberate rules, tuned over real South African routes, that decide when a detour is worth it and when it isn’t.
| What triggers a detour | Only higher-risk areas. Caution-level zones are drawn on the map but never trigger a detour |
|---|---|
| Route check | The route is sampled and tested against every active zone for the current time |
| Corridor awareness | Recognises when a route already runs a corridor we have checked, and leaves it be |
| Detour limits | Bypasses are capped so they never wander unreasonably far from the direct line |
| Corridor selection | Only nearby checked corridors are used to steer around a risk area |
| Sanity check | Any detour that ends up excessively longer than the direct route is rejected. You get the direct route, clearly flagged |
| Time-aware | Separate risk weighting for daytime, evening and night |
Data model
Polygons with a name, city, three time-band risk levels, crime types, and a source. Soft-deleted (never hard-deleted) so history is recoverable.
red · orange · yellow
LineStrings with a buffer width that mark roads as safe (preferred when threading past risk) or danger (actively avoided). The safe value is the stored field name for what the rest of the site calls a checked corridor: a road we have reviewed, not a promise about it. Identity is always (city, name), because road names repeat across metros.
safe · danger
Geometry is stored as PostGIS geometry and written through ST_SetSRID(ST_GeomFromGeoJSON(…), 4326) RPCs, since PostgREST can’t auto-cast GeoJSON to geometry.
Coverage
Live across Gauteng (Johannesburg, Pretoria, Ekurhuleni and the West Rand), Durban, Gqeberha, Cape Town and Stellenbosch, Rustenburg and Pilanesberg, Mossel Bay, and Secunda. Mapped metros: Johannesburg · Cape Town · Pretoria · Ekurhuleni · West Rand · Secunda · Stellenbosch · Rustenburg · Pilanesberg · Mossel Bay · Durban · Gqeberha. Adding a new city follows a documented runbook, which is how the map went from one metro to 12.
We’re always glad to talk shop, or to find sponsors who want to fund the next metro.