Datenmodell
Lodapi hat zwei Schema-Layer:
lodapi_meta— Cross-BL Metadaten (Datasets, Tilesets, Terrain-Datasets, Lizenzen, Attribution).bl_<code>— Pro Bundesland ein Schema mit Postgres-Tabellen aus dem Import (LoD2-Slim-Variante + ggf. 3DCityDB-v5-Schema im Hintergrund).
lodapi_meta — Plattform-Schicht
lodapi_meta.license (license_id PK, url, text, ...)
lodapi_meta.attribution (attribution_id PK, bundesland_code, text, ...)
lodapi_meta.dataset (dataset_id PK uuid, bundesland_code, snapshot_date, ...)
lodapi_meta.tileset (tileset_id PK uuid, dataset_id FK, region_code, s3_key, bounding_volume, ...)
lodapi_meta.terrain_dataset (terrain_dataset_id PK, bundesland_code, snapshot_date, source, format, ...)
lodapi_meta.terrain_tile (tile_id PK, terrain_dataset_id FK, bbox, easting_km, northing_km, source_url, ...)
lodapi_meta.terrain_mesh_dataset (mesh_dataset_id PK, bundesland_code, snapshot_date, tileset_s3_key, build_params jsonb, ...)
| API-Endpoint | Quelltabelle(n) |
|---|---|
/v1/datasets | dataset JOIN attribution |
/v1/tilesets | tileset + spatial-index bounding_volume |
/v1/tilesets/{id} | tileset |
/v1/terrain/datasets | terrain_dataset (DISTINCT ON BL) |
/v1/terrain/elevation | terrain_tile (ST_Contains) → /vsicurl/ |
/v1/terrain/profile | terrain_tile × N + batch-COG-sample |
/v1/terrain-mesh/datasets | terrain_mesh_dataset (DISTINCT ON BL) |
/v1/admin/datasets (POST) | UPSERT in dataset + tileset |
bl_<code> — Per-BL-Schicht
Phase-1-Slim-Layout (Decision 2026-05-13, Surfaces-Pivot):
bl_<code>.surfaces_slim (surface_id PK, building_id, gmlid, surface_class, geom MultiPolygonZ, ...)
bl_<code>.dataset_metadata (snapshot_date, building_count, ...)
surface_class ist die AdV-Klassifikation:
709= Wall (Fassade)710= Ground (Bodenfläche)712= Roof (Dach)
| API-Endpoint | Quelltabelle |
|---|---|
/v1/buildings (bbox) | bl_<code>.surfaces_slim (DISTINCT building per bbox) |
/v1/buildings/{gmlid} | bl_<code>.surfaces_slim GROUP BY building_id |
/v1/buildings/3d.glb | bl_<code>.surfaces_slim mit class-Filter |
Snapshot-Versionierung
Jedes BL hat ein aktives Snapshot zu einem Zeitpunkt. Re-Imports überschreiben das Schema in einer Transaktion. dataset.snapshot_date ist die Identitätsachse.
Cursor-Pagination in /v1/buildings ist Federation-aware: <bundesland>:<surface_id> als base64-encoded String. Behandle den Cursor als opak — surface_id ist nicht als stabile ID über Snapshots hinweg garantiert.
Index-Strategie
| Tabelle | Index | Zweck |
|---|---|---|
surfaces_slim | GIST(geom) | Bbox-Queries |
surfaces_slim | btree(building_id) | GROUP BY für Detail-Endpoints |
surfaces_slim | btree(gmlid) | /v1/buildings/{gmlid} |
terrain_tile | GIST(bbox) | /v1/terrain/elevation ST_Contains |
tileset | GIST(bounding_volume) | /v1/tilesets?bbox= |
CRS in der DB
Per-BL unterschiedlich:
| BL-Gruppe | Geometry-CRS |
|---|---|
| BW, BY, HB, HH, HE, NI, NW, RP, SL, SH | EPSG:25832 (UTM32N) |
| BE, BB, MV, SN, ST, TH | EPSG:25833 (UTM33N) |
Die API transformiert dynamisch zu WGS84 für GeoJSON-Output. COG-Sampling-Pfad nutzt das native Tile-CRS.