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

136 lines
6.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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)