# STS Maps — Data Layer

GeoJSON layers powering the interactive landscape map. Served as static files from `/data/maps/` on production.

## Source of truth

All layers are extracted from `assets/maps/00 - STS Master.kmz` (40MB, 118 layers). That KMZ is the canonical source and must remain the working file for any geographic edits.

**Do not edit GeoJSON files by hand.** Edit the master KMZ in Google Earth or QGIS, then re-run `scripts/extract-maps.py`.

## Files

### `catchment.geojson` (44KB)
Single polygon. The Sabie-Sand River catchment boundary.

| property | meaning |
|---|---|
| `name` | "Sabie-Sand Catchment" |
| `type` | `catchment` |
| `area_ha` | Polygon area in hectares — currently computes ~774,468 ha from the combined-catchment polygon, but **user-facing site copy uses ~630,000 ha** (the Verra-registered project area). The two numbers describe different things: 774,468 is the raw GIS polygon area, 630,000 is the registered project area as filed with Verra VCS 5375. Do not surface area_ha in popups, hero copy, or meta descriptions without coordinating with the registered figure. |

**Source as of 2026-05-26:** `assets/maps/Sabie_Sand_Combined_Catchment.kmz` (supersedes the prior `sts_catchment_area_dissolved` layer from the master KMZ, which was 663,598 ha &mdash; the combined-catchment file is the authoritative GIS boundary, while ~630,000 ha remains the registered Verra project area number used in marketing and legal copy across the site).

### `traditional-authorities.geojson` (11KB)
Nine polygons across eight unique jurisdictions. Mnisi is split into two non-contiguous parcels (resolved 2026-05-25 — both belong to the same TA, source KMZ had a spelling drift "Minsi" vs "Mnisi" for the second parcel).

| property | meaning |
|---|---|
| `name` | Full name as digitized in the source KMZ |
| `short_name` | Map-display label (e.g. "Mnisi") |
| `jurisdiction` | Deduplication key — multiple polygons of the same TA share one jurisdiction value. Use this to count unique TAs. |
| `type` | `traditional_authority` |
| `area_ha` | Polygon area in hectares |
| `needs_verification` | Reserved for future use; currently `false` on all |
| `publishable` | `true` on all current features |

### `planting-phases.geojson` (3.4MB / ~1MB gzipped)
Ten multipolygons. Five planting phases (one per TA) × two sub-categories (cropland, residential).

| property | meaning |
|---|---|
| `phase` | Integer 1&ndash;5 in execution order |
| `jurisdiction` | The TA where this phase sits (Jongilanga, Amashangana, Hoxane, Mnisi, Mathibela) |
| `category` | `cropland` or `residential` &mdash; the source land-use class |
| `area_ha` | Polygon area in hectares (true area, pre-simplification) |

**Note on excluded category:** The source KMZs contain a third sub-category called `uncertain` &mdash; land that is neither classified cropland nor residential. That category is **not extracted** because it does not represent planting targets. If you need it back, edit `CATEGORY_SUFFIXES` in `scripts/extract-maps.py`.

**Phase totals (cropland + residential only):**
- Phase 1 Jongilanga: 7,010 ha
- Phase 2 Amashangana: 14,924 ha
- Phase 3 Hoxane: 8,042 ha
- Phase 4 Mnisi: 7,000 ha
- Phase 5 Mathibela: 3,420 ha
- **Total: 40,396 ha across 5 phases**

### `nurseries.geojson` (1.3KB)
Five propagation nursery points across the catchment. Source: standalone `Nurseries.kmz` (replaces the earlier 5-nursery list pulled from the master KMZ's Agripark cluster).

Current roster: Ntirihiso, Tiyimeleni, Skukuza, Hlulani Farm, Amashangani TA.

| property | meaning |
|---|---|
| `name` | Nursery name as it appears on the site |
| `type` | `nursery` |
| `custodian` | Custodian name if this nursery is custodian-linked. Currently empty on all features &mdash; reserved for future linkage. |
| `publishable` | `true` on all current features |

### `rivers.geojson` (63KB)
The Sand and Sabie River network with all named tributaries inside the catchment.

| property | meaning |
|---|---|
| `name` | Watercourse name as digitized in OpenStreetMap (e.g. "Sand River", "Mutlumuvi", "Phabeni") |
| `class` | `mainstem` (Sand or Sabie), `tributary` (any other named river), `stream` (named smaller drainages) |
| `system` | `primary` if the feature is in the connected component containing Sand River or Sabie River; `orphan` if disconnected (often a data gap in OSM between named segments — the actual watercourse is real, just unmapped connectors) |
| `waterway` | Source OSM `waterway` tag (`river` or `stream`) |

The component renders primary-system features (including locally-named upper-Sand reaches like Mhlambanyathi, Mutlumuvi, Mosehla) with bolder strokes than orphan features, because they're geographically continuous with the Sand or Sabie River even when their names don't say so.

**Source:** OpenStreetMap, queried via Overpass Turbo for `waterway=river` (all named) and `waterway=stream` (named only) in the broader bbox. Processed through `scripts/process-rivers.py`:
1. Drop point features
2. Clip to `catchment.geojson` (drops everything draining to Olifants, Komati, etc.)
3. Classify into mainstem / tributary / stream
4. Dissolve same-name segments into single multilinestrings (so the Sand mainstem renders as ONE feature, not 9 disconnected ways)
5. Simplify to ~30m tolerance for web display

To refresh: re-run the Overpass query, drop the new raw export at this path, run `python3 scripts/process-rivers.py`. The script overwrites the same file with the cleaned result.

### `learning-centers.geojson` (1.4KB)
Five GWF (Good Work Foundation) Digital Learning Centers across the catchment. Source: standalone `GWF Learning Centers.kmz`.

Centers: Dumphries, Justicia, Dixie, Huntington, Hazyview.

| property | meaning |
|---|---|
| `name` | Full center name (e.g. "GWF Justicia Digital Learning Center") |
| `type` | `learning_center` |
| `operator` | `GWF` for all current features &mdash; reserved for future multi-operator support |
| `publishable` | `true` on all current features |

### `land-use.geojson` (1.4MB)
Three multipolygons covering the **catchment minus TAs** area only. Within each TA, separate per-TA land-use breakdowns exist in the master KMZ and can be extracted in Tier B.

| property | meaning |
|---|---|
| `category` | `cropland`, `residential`, or `uncertain` |
| `scope` | `catchment_outside_tas` (this file's scope) |
| `area_ha` | Multipolygon area in hectares |

Geometries simplified to ~50m tolerance for web display.

### `feature-details.json` (~4KB)
Popup enrichment lookup. Hand-edited. Keyed by TA `short_name`, nursery `name`, and Learning Center `name`. Fields that exist appear in the popup; missing fields are quietly omitted.

Currently populated:
- TAs: FPIC status + date (for 5 of the 8 mapped TAs), 1-line description for each
- Nurseries: type label + 1-line geographic note
- Learning Centers: opening year (from GWF's site, May 2026), campus URL link, 1-line note

**Moletele asymmetry &mdash; verify before publishing FPIC count externally.** BRIEF.md lists six signed-FPIC TAs (Amashangana, Jongilanga, Hoxani/Hoxane, Mathibela, Mnisi, and **Moletele**). Moletele is in the signed list but is NOT one of the eight mapped TA polygons &mdash; either Moletele falls outside the new combined catchment, or our TA polygon layer is incomplete. The map currently reports five signed-FPIC TAs to be safe. Reconcile this with the source data before any external claim about "all six FPIC TAs visible on the map."

## Coordinate reference system

All files use **EPSG:4326** (WGS 84, lat/lng decimal degrees). Z-coordinates have been stripped.

## Updating

When the master KMZ changes:

```bash
pip install geopandas pyogrio shapely   # one-time
python3 scripts/extract-maps.py
```

Diff the resulting GeoJSON against the prior version. Visual inspection in QGIS recommended before commit. Bump the revision line below.

**Source data revision:** Master KMZ from 2026-05-21 (40MB, 118 layers).
**Last extraction:** 2026-05-25 (added nurseries, merged Mnisi parcels).

## Not yet extracted (Tier B / C backlog)

The master KMZ contains the following layers that have not yet been extracted to GeoJSON:

- Per-TA land-use breakdowns (cropland/residential/uncertain for each of 8 TAs)
- Hub clusters: Injaka, Zoeknog, New Forest, Huntington, Hoxane, Agritech/Agripark polygons
- Agripark cluster non-nursery points: Uys Marula Processing & Propagation, GWF Hazyview Learning Center, BlueHazy FM, Mkhuhlu Agrihub, Huntington Agrihub
- Farm and village placemarks across all hubs
- "Save the Sand – Nkhensani Marula Block" — the named project block tied to a custodian
- GLTFC, Implementation, Guild (Large / Medium / Small), C4 layers

## Sensitive data note

GPS coordinates for sensitive features (marula tree clusters at risk of harvest theft; individual custodian homes) should be **fuzzed to a 500m grid or aggregated to zone level** before publishing. Current layers are administrative boundaries, propagation site centroids, and aggregate land-use polygons — no individual-level sensitivity applies.
