137 lines
6.1 KiB
Markdown
137 lines
6.1 KiB
Markdown
|
|
# 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 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:**
|
|||
|
|
|
|||
|
|
1. **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
|
|||
|
|
|
|||
|
|
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; 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
|
|||
|
|
|
|||
|
|
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)
|