6.1 KiB
6.1 KiB
ADR-001: Tile Rendering Stack – Martin + tileserver-gl
Date: 2026-06-12
Status: Accepted
Context
The tile server must serve map tiles to three external systems:
- MediaWiki (Kartographer extension) – requires raster PNG tiles for client-side rendering
- Home Assistant – requires raster PNG tiles for map visualization
- Nextcloud – may require vector or raster tiles in future
Current state:
- Martin tile server distributes vector tiles (PBF format) from
osm.mbtiles osm.mbtilescontains static OSM snapshot (not live-updated data)- No client-side rendering capability for Kartographer (requires PNG or pre-rendered output)
- Map rendering fails silently in MediaWiki without server-side PNG delivery
Key requirements:
- Maps must display in MediaWiki without external tile server dependency
- Styles and layer definitions must be customizable by team
- Map tile updates are planned 2–4 times per year (not live)
- Low operational overhead (single-server, docker-compose deployment)
- Horizontal scaling is not a near-term requirement
Decision
Adopt a two-tier tile architecture:
-
Martin (stays)
- Role: Vector tile distribution API
- Input:
osm.mbtiles(static snapshot, updated manually 2–4×/year) - Output: PBF tiles via REST API (
/{layer}/{z}/{x}/{y}.pbf) - Purpose: Foundation for future MapLibre GL integration, internal vector APIs
-
tileserver-gl (new)
- Role: PNG raster tile renderer + server
- Input: Vector tiles from Martin + Style definitions (stored in
/data/styles/) - Output: Raster PNG tiles via REST API (
/{style}/{z}/{x}/{y}.png) - Purpose: Serve Kartographer and other raster-only clients
URL routing in Reverse Proxy (NPM):
/osm/{z}/{x}/{y}.pbf→ Martin (internal/API use)/osm-intl/{z}/{x}/{y}.png→ tileserver-gl (Kartographer)/osm-intl/{z}/{x}/{y}@2x.png→ tileserver-gl (retina displays)
MediaWiki Config:
$wgKartographerMapServer = 'https://tiles.rd13server.de'$wgKartographerDfltStyle = 'osm-intl'(raster style)- No external tile dependency
Consequences
Benefits
- ✅ Minimal operational complexity – Both Martin and tileserver-gl fit in docker-compose, combined ~200MB RAM
- ✅ No external dependencies – Kartographer renders entirely from local server; no upstream tile requests
- ✅ Style customization – tileserver-gl uses standard MapLibre GL styles (JSON); team can adjust colors, fonts, layer visibility without code changes
- ✅ Flexible upgrade path – If live OSM updates become required (2027+), OpenMapTiles Server can be added without disrupting Martin or tileserver-gl
- ✅ Fast iteration – Update cycle: download new
osm.mbtiles→ docker-compose restart → ~30 seconds downtime - ✅ Vector + Raster simultaneously – Future clients (MapLibre GL, Leaflet vector) can coexist with raster-only systems (Kartographer)
Drawbacks
- ⚠️ Manual tile refresh cycle – No live OSM updates; requires download and swap of
osm.mbtiles - ⚠️ PNG caching complexity – Raster tiles are pre-rendered, so cached images may lag behind style changes by one tile-generation cycle
- ⚠️ CPU spike during rendering – tileserver-gl pre-warms cache on startup; brief CPU spike when new zoom level/area is requested for first time
- ⚠️ Storage – Raster caching will eventually consume disk space (~1GB per zoom level for Europe at full coverage); mitigation: define tile cache TTL
Alternatives Considered
Alternative A: OpenMapTiles Server (full-stack replacement)
Pros:
- Live OSM data import pipeline
- Central rendering engine with parametrized styling
- Full control over data freshness
Cons:
- Overengineered for current needs – Requires PostGIS, Lua, full data pipeline; 3–5 GB footprint
- High setup cost – 3–5 days to operationalize + ongoing maintenance burden
- Not needed yet – static 2–4×/year updates don't justify infrastructure investment
- Risk – Complex system = more failure modes; Martin is proven production-grade today
Why not chosen: Defers to future decision (ADR-002?) when live update requirement becomes real.
Alternative B: External tile server proxy (OSM.org, Mapbox)
Pros:
- Zero infrastructure investment
- Instant map display
Cons:
- Violates ToS – OSM.org tile server prohibits automated/bulk access (Kartographer = repeated requests)
- No resilience – Dependent on external uptime; tiles fail if upstream is down
- Violates NFR-001 – REQ-001 requires "maps must be independently hostable"
Why not chosen: Does not meet architectural requirements.
Alternative C: Martin + client-side rendering (MapLibre GL only)
Pros:
- Simpler stack (one service)
- Full styling flexibility at runtime
Cons:
- Breaks MediaWiki – Kartographer does not support MapLibre GL client-side rendering
- Blocks requirement – MediaWiki maps would remain broken; unacceptable to stakeholders
Why not chosen: Fails functional requirements.
Implementation Plan
-
Week 1
- Add tileserver-gl to docker-compose.yml
- Mount
/data/styles/and/data/fonts/for style/font config - Create baseline osm-intl style (JSON) for raster rendering
- Configure Nginx reverse proxy routing in NPM
-
Week 2
- Test end-to-end: MediaWiki mapframe → PNG delivery
- Verify cache headers and CDN-friendliness
- Document in ADMIN.md: tile update workflow
-
Week 3
- Performance testing (p95 response times, cache hit rates)
- Rollback procedure documentation
- Team training on style customization
Future Decisions
- ADR-002: Live OSM update pipeline (if 2027 requirement arises)
- ADR-003: Horizontal tile server scaling (if traffic exceeds single-server capacity)
- ADR-004: Sprites and fonts CDN distribution