rd13_tile_server/docs/adr/001-martin-tileserver-gl-stack.md

137 lines
6.1 KiB
Markdown
Raw Normal View History

# 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.mbtiles` contains 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 24 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:**
1. **Martin** (stays)
- Role: Vector tile distribution API
- Input: `osm.mbtiles` (static snapshot, updated manually 24×/year)
- Output: PBF tiles via REST API (`/{layer}/{z}/{x}/{y}.pbf`)
- Purpose: Foundation for future MapLibre GL integration, internal vector APIs
2. **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; 35 GB footprint
- **High setup cost** 35 days to operationalize + ongoing maintenance burden
- **Not needed yet** static 24×/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
1. **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
2. **Week 2**
- Test end-to-end: MediaWiki mapframe → PNG delivery
- Verify cache headers and CDN-friendliness
- Document in ADMIN.md: tile update workflow
3. **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
## References
- [Martin Tile Server Docs](https://maplibre.org/martin/)
- [tileserver-gl Docs](https://tileserver.readthedocs.io/)
- [REQ-001: Tile Server öffentlich erreichbar](../requirements/REQUIREMENTS.md#req-001)
- [REQ-004: MediaWiki Integration](../requirements/REQUIREMENTS.md#req-004)