Report-Spezifikation — JSON-Contract

Dieses Dokument definiert den vollständigen Report-JSON-Contract von LandNutzen. Ziel: ein Entwickler kann danach die deterministische Szenario-/Cost-Engine, den LLM-Prompt und die beiden PDF-Templates (React-PDF Standard, Puppeteer Premium) bauen, ohne raten zu müssen.

Querverweise: PRODUCT.md · ARCHITECTURE.md · ADR-0015 Kostenschätzung · ADR-0013 PDF · ADR-0006 Auth/Multitenant · ADR-0016 Grundbuch · ADR-0014 HORA-Pass · DATA-SOURCES.md · POC-PLAN.md


1. Grundprinzipien

1.1 Trennung Engine ↔ LLM (verbindlich)

Konsistent mit ADR-0015:

``` [Deterministische Engine berechnet ALLE Zahlen + Ampeln + Scores] ↓ [strukturiertes Report-JSON (dieser Contract)] ↓ [LLM erhält Report-JSON + Quellenliste + Schreib-Anweisung] ↓ [LLM rendert NUR narrative Felder, zitiert Engine-Werte 1:1] ↓ [Zahlen-Konsistenz-Guard: Regex auf €/kWh/m² → Abgleich mit JSON] ```

Der LLM erfindet, rechnet oder rundet keine Zahlen. Er befüllt ausschließlich Felder, die unten als Herkunft `llm` markiert sind, und darf darin keine Zahl nennen, die nicht 1:1 aus einem `engine`-Feld stammt. Bei Diskrepanz: Auto-Retry mit härterer Anweisung, sonst Fallback auf Template-Render (statischer Satzbaustein).

1.2 Herkunfts-Klassen pro Feld

HerkunftBedeutung
`engine`Deterministische Regel-/Geo-/Cost-Engine. Reproduzierbar bei gleichem Input. Nie LLM.
`llm`LLM-narrativer Text (Sonnet 4.6 Standard / Opus 4.7 Premium). Keine neuen Zahlen.
`static`Konstante aus Konfig/Recht (Disclaimer-Boilerplate, Lizenz-Strings, Tarif-Mapping).
`external`1:1 von externer Quelle übernommen (BEV-Geometrie-Ref, HORA-Pass-PDF-Key).

1.3 Determinismus & Caching

Gleicher `(parcel_id, region, report_tier, engine_version, config_version)` → identische `engine`/`external`-Felder. `llm`-Felder dürfen variieren (Temperatur > 0), müssen aber den Zahlen-Guard bestehen. `meta.as_of` und `meta.generated_at` machen jeden Report stichtagsfähig.


2. Top-Level-Schema

```jsonc { "schema_version": "1.0.0", // SemVer dieses Contracts; static "report_id": "uuid", // engine "meta": { ... }, // §3 "parcel": { ... }, // §4 "steckbrief": [ { ... } ], // Ampel-Übersicht aller Indikatoren (Aggregat; engine) "standort_bilanz": { ... } | null,// Risiko-Rollup aus dem Steckbrief (Szenario-Kontext; engine) "widmung": { ... }, // §5 "risiko": { ... }, // §6 "bestand": { ... }, // §7 "grundbuch": { ... } | null, // §8 — nur Premium, sonst null "scenarios": [ { ... } ], // §9 — 3..5 Elemente "foerderungen": [ { ... } ], // §10 "sources": [ { ... } ], // §11 — Attribution-Pflicht "confidence": { ... }, // §12 "disclaimer": { ... }, // §13 "narrative": { ... } // §14 — die einzigen rein-llm-Blöcke } ```

Pflicht-Top-Level-Keys für alle Tiers: `schema_version`, `report_id`, `meta`, `parcel`, `widmung`, `risiko`, `bestand`, `scenarios`, `foerderungen`, `sources`, `confidence`, `disclaimer`, `narrative`. `grundbuch` ist immer vorhanden, aber `null` außerhalb des Premium-Pfads (siehe §8 und §15).

`steckbrief` ist optional und rein abgeleitet: eine Ampel-Übersicht aller vorhandenen Indikator-Layer (Widmung, Hochwasser, Altlasten, Radon, Lärm, Schutzgebiete, Denkmal, Breitband) für den schnellen Blick oben im Report. Keine eigene Datenquelle, kein Gesamt-Verdikt. Einträge: `{ schluessel, label, ampel: gruen|gelb|rot|unbekannt, kurz }`; feste Reihenfolge, fehlende Layer werden ausgelassen (Lücke steht in `meta.degraded`). Die Altlasten-Ampel wird aus der release-gebundenen Punktprüfung abgeleitet: Adresspunkt von einer veröffentlichten Altlast mit ST_Covers abgedeckt → rot, nächste veröffentlichte Altlast innerhalb 1 km → gelb, sonst grün. Fehlt der qualifizierte Quellenvertrag, darf kein grünes Ergebnis entstehen.

`standort_bilanz` ist optional/null und rein abgeleitet aus dem `steckbrief`: ein kompakter Risiko-Rollup, den die Szenario-Engine als Entscheidungs-Kontext über den Nutzungsszenarien ausweist. Form: `{ rot: [{schluessel,label}], gelb: [{schluessel,label}], gruen_count: int, hinweis: string }`. Reine Zählung/Auflistung der nicht-grünen Indikatoren — KEIN Gesamt-Verdikt (eine einzelne „Gesamtampel" wäre über-claimend). null, wenn kein Indikator vorliegt.

ÖV-Kappung (M11, Magnus 16.07.2026): Der Rollup ist der universelle „jede Nutzung"-Kontext. Eine ÖV-Erschließung ohne Güteklasse (oev.ampel == "rot") ist für die ÖV-nachrangigen Nutzungen Freiflächen-PV und Lager kein kritischer Standortfaktor und kann in diesem universellen Rollup nicht rot zählen — sie wird auf gelb (zu prüfen) gekappt. Der ÖV-Eintrag im steckbrief selbst bleibt rot (Rohsignal „keine Güteklasse"); nur sein Beitrag zur standort_bilanz wird gekappt, und sein kurz-Text weist die Nachrangigkeit aus. Die Kappung betrifft ausschließlich schluessel: "oev"; alle anderen roten Indikatoren zählen unverändert rot.


3. `meta` — Identität, Stichtag, Tier

FeldTypPflichtHerkunftBeschreibung
`meta.address.raw`stringjaexternalVom User eingegebene Adresse (roh). Wird NICHT an LLM gegeben (PII-Minimierung, ARCHITECTURE §Compliance).
`meta.address.normalized`stringjaengineNormalisierte Adresse (Geocoder-Output).
`meta.coordinate.lat`numberjaengineWGS84, Geocoding (Nominatim/BEV).
`meta.coordinate.lon`numberjaengineWGS84.
`meta.coordinate.source`enum `nominatim`|`bev`jaengineGeocoder.
`meta.region.slug`stringjaenginez. B. `at-noe` (ADR-0006 Region-Achse).
`meta.region.name`stringjastatic„Niederösterreich".
`meta.report_tier`enum `free`|`standard`|`premium`|`planer`jaengineSteuert Sektions-Sichtbarkeit (§15). `free`=anonym, `standard`=registriert, `premium`=490-€-Beratung, `planer`=Abo-Export.
`meta.org_id`int | nulljaengineOrg-Kontext (RLS, ADR-0006). `null` bei anonym (`_public`-Org).
`meta.requested_by`enum `anonymous`|`user`|`platform_admin_impersonating`jaengineAudit-Hinweis (ADR-0006/0007).
`meta.as_of`ISO-8601 datejaengineFachlicher Daten-Stichtag (max. Alter aller verwendeten Layer).
`meta.generated_at`ISO-8601 datetimejaengineGenerierungs-Zeitpunkt.
`meta.engine_version`stringjastaticVersion der Szenario-/Cost-Engine.
`meta.config_version`stringjastaticVersion `bodenwerte.json` + `herstellungskosten.json` + BPI-Stand.
`meta.degraded`object[]jaengineListe ausgefallener Layer mit Defensive-Default-Hinweis (ARCHITECTURE §Failure-Modi). Leer wenn alles ok.
`meta.timings`object[]optionalengineDiagnostische Layer- und Phasenlatenzen, absteigend sortiert. Enthält Einzel-Layer sowie `layers_total`, `scenario_engine`, tierabhängig `narrative` und `report_total`. Werte überlappen und dürfen nicht summiert werden. Nicht deterministisch — kein Teil der fachlichen Aussage.
`meta.report_id`stringoptionalenginePermalink-ID, falls der Report persistiert wurde (nur POST, ADR-0022). Fehlt bei fail-open-Persistenzfehler.
`meta.permalink`stringoptionalengineTeilbarer Pfad `/r/{report_id}`, falls persistiert.
`meta.saved`booloptionalengine`true`, wenn der Report einem Konto fest zugeordnet ist (eingeloggt erstellt oder per `?claim=1` beansprucht, Migration 0021) → kein 90-Tage-Ablauf. Fehlend/`false` = anonym (90-Tage-Retention) oder nicht persistiert. Steuert „gespeichert"-/Registrierungs-Nudge im UI.

`meta.degraded[]`-Element: `{ "layer": "geosphere", "reason": "source_not_released", "fallback": "Kein qualifizierter aktiver SPARTACUS-v3-Release verfügbar" }`. `meta.timings[]`-Element: `{ "layer": "parcel", "ms": 812 }`. Einzelne Layer laufen konkurrent; `layers_total` umfasst den gesamten Fan-out, `report_total` zusätzlich Szenario-Engine und ein gegebenenfalls erlaubtes Narrativ. Für den HTTP-Pfad liefert `/api/v1/report` außerdem den standardisierten `Server-Timing`-Header mit `guard`, `auth`, `session_tier`, `rate_limit`, `report_build`, bei POST `body_parse`/`persistence` und `total`. `X-LandNutzen-Timing` transportiert denselben Wert als namespaced Produktions-Fallback, falls ein vorgeschalteter Host den Standard-Header entfernt.


4. `parcel` — BEV-Kataster

Der qualifizierte Snapshot-Pfad liest ausschließlich den Active Release von bev-parzellen/public für public_display/point_lookup. Der erste Vertrag deckt nur bev-gaenserndorf-pilot-v1 mit der BBox [16.64,48.28,16.80,48.40] ab. Außerhalb kann ein getrennt behandelter BEV-WMS-Legacy-Pfad ausschließlich die Grundstücksidentität liefern; er erbt weder Release noch Snapshot-Geometrie. Der Neun-Bundesländer-Testkorpus belegt nur das Identitätsformat, keine österreichweite Datenabdeckung.

Neue Reports tragen die Lookup- und Provenienzfelder. Bereits gespeicherte Reports bleiben wegen der optionalen Felder lesbar.

FeldTypPflichtHerkunftBeschreibung
`parcel.found`booleanjaengineOb der Report eine verwendbare Parzellenidentität besitzt. Kann bei einem separaten WMS-Fallback auch dann `true` sein, wenn der qualifizierte Snapshot-Lookup `outside_coverage` oder `failed` meldet; es ist deshalb nicht mit einem Release-Treffer gleichzusetzen. `false` führt zum Teilreport.
`parcel.lookup_status`enum `hit`|`no_hit`|`outside_coverage`|`ambiguous_boundary`|`source_not_released`|`failed`optional; für neue ReportsengineÖffentliche Abbildung des release-gebundenen Lookups. Der interne Adapter bleibt fünfstufig und liefert Gate-Fehler technisch als `failed`; der Report projiziert Rechte-, Zweck-, Legacy-, Active-Release-, Freshness- und Quality-Gates auf `source_not_released`. Operative Provider-/Runtimefehler bleiben `failed`. `no_hit` ist nur innerhalb qualifizierter Coverage zulässig; Boundary-Mehrdeutigkeit wird nicht auf einen Treffer reduziert.
`parcel.lookup_failure_code`enum `rights_blocked`|`purpose_not_allowed`|`legacy_unverified`|`no_active_release`|`source_unavailable`|`freshness_rejected`|`quality_rejected`|`internal_error`bei `source_not_released` oder `failed`engineMaschinenlesbarer Grund ohne interne Rohdaten. Eine konservative Quarantäne-Envelope verhindert einen sonst ungesicherten `no_hit`; ein gültiger veröffentlichter Innentreffer hat Vorrang, ein bloßer Randtreffer neben Quarantäne bleibt `quality_rejected`/`source_not_released`. Operative Fehler werden nicht als Release-Gate umetikettiert.
`parcel.parcel_uid`stringbei qualifiziertem `hit`engineReversible interne LandNutzen-ID AT:{kg_code}:{parcel_number_normalized}; keine amtliche neue Kennung.
`parcel.source_release_id`UUIDbei release-gebundenem `hit`, `no_hit` oder `ambiguous_boundary`engineExakter qualifizierter Source Release des Snapshot-Ergebnisses. Fehlt beim getrennten WMS-Legacy-Pfad.
`parcel.match_method`enum `point_in_polygon`|`wms_getfeatureinfo`bei `found`, soweit verfügbarengineTatsächliche Matchmethode; Snapshot-Treffer verwenden `point_in_polygon`, Legacy-Fallbacks `wms_getfeatureinfo`.
`parcel.match_confidence`numberoptionalengineTechnische Matchkonfidenz 0..1; ersetzt keine Vermessungs- oder Rechtsauskunft.
`parcel.grundstuecksnummer`stringwenn `found`externalUnveränderter BEV-Quellalias der Grundstücksnummer.
`parcel.katastralgemeinde`stringwenn `found`externalKatastralgemeinde samt Nummer, soweit vom Bezugskanal geliefert.
`parcel.area_m2`number | nullnur beim qualifizierten Snapshot-TrefferengineAus der unverändert veröffentlichten DKM-Geometrie berechnete Fläche. Der WMS-Fallback liefert keine Fläche.
`parcel.area_tolerance_pct`number | nullnur beim qualifizierten Snapshot-TrefferstaticToleranzmarge DKM ≠ Grundbuch — Magnus-Entscheid 11.08.2026 (#81): Grenzkataster null (vermessungsgenau, keine Angabe), sonst ±10 % Flächenschärfe.
`parcel.source`enum `dkm_mirror`|`wms`wenn `found`engineTatsächlicher Datenweg. `dkm_mirror` bezeichnet den release-gebundenen Snapshot-Pfad; `wms` den getrennten Identitätsfallback ohne qualifizierte Geometrie.
`parcel.kataster`enum `grenzkataster`|`grundsteuerkataster`|`unbekannt`wenn `found`externalKataster-Status aus BEV-RSTATUS. Anzeige (#320): Report, Karte und PDF nutzen katasterAnzeige() (lib/report/labels.ts); unbekannt wird sichtbar ausgewiesen. Keine Rechtsauskunft.
`parcel.bev_stand`ISO-8601 datebei release-gebundenem Ergebnis; bei WMS-IdentitätengineSnapshot: fachlicher Quellenstand des Active Release. WMS: Abrufdatum, weil dieser Kanal keinen qualifizierten Snapshot-Stand liefert.
`parcel.hinweis`stringwenn kein eindeutiger qualifizierter TrefferengineSichtbarer Hinweis für Grenze, Lücke, Mehrdeutigkeit oder Fehler.
`parcel.vermessung_disclaimer`stringsobald Parzellendaten angezeigt werdenstaticFixer Pflicht-Hinweis, dass DKM-Geometrie und -Fläche keine rechtsverbindliche Vermessung ersetzen.

Ein WMS-Treffer bewahrt den Snapshot-Zustand: außerhalb der Coverage outside_coverage, bei einem Release-Gate source_not_released, bei einem operativen Fehler failed. Der Fallback macht daraus nie einen qualifizierten Snapshot-Treffer; meta.degraded führt entsprechend ausserhalb_pilot_spiegelung, source_not_released oder request_fehlgeschlagen.

Der Report-JSON-Vertrag enthält keine Rohgeometrie und keine geometry_ref. ADR-0055 trennt den öffentlichen public_display/point_lookup strikt vom Pilotkanal bev-parzellen/export. Nur ein qualifizierter Export-Release für bev-gaenserndorf-pilot-v1 darf über parcel_versions_export_current Geometrie ausgeben.

Der bestehende Public-Snapshot umfasst 29.746 veröffentlichte Originalpolygone und 15 Quarantänefälle. Sein historischer ogr2ogr -spat-Filter übernimmt auch Pilotgrenzen schneidende Originalgeometrien vollständig; der separate Export übernimmt dagegen ausschließlich unveränderte ST_CoveredBy-Polygone. outsideCoverageRowCount beträgt 1.211 und macht alle nicht vollständig umschlossenen, ausgeschlossenen Public-Parzellen nachvollziehbar; 28.535 zulässige Originalpolygone sind im separaten Export-Pointer produktiv aktiviert. Public- und Export-Mengen sowie ihre Manifeste sind unabhängig gebunden. Ein im Pilot liegender Report-Standort allein öffnet keine teilweise oder vollständig außerhalb liegende Originalgeometrie; Clipping ist ausgeschlossen.

Der bestehende, rate-limitierte /api/parcel-geojson-Pfad verwendet parcel_geojson ausschließlich als internes Kartenoverlay eines bereits gespeicherten wertschöpfenden Standortreports; er ist kein eigenständiges BEV-Datenprodukt. Die verpflichtende reportId muss einen vorhandenen Report mit exakt übereinstimmender Koordinate und mindestens einer Nicht-BEV-Datenquelle bezeichnen. Fehlende oder unbekannte IDs bleiben 404, abweichende Standorte oder fehlender Mehrwert 403. Nur ein bestätigter hit mit derselben öffentlichen Release-ID und derselben öffentlichen Pointer-Version liefert die vorhandene FeatureCollection mit BEV-Attribution, Quellen-/Lizenzlink, Quellenstand, Änderungshinweis und Vermessungsgrenze. Unsichere Zustände erhalten 503; Erfolg und Fehler bleiben private, no-store. Vorhandene Reports werden nur gelesen; diese Prüfung erzeugt weder neue Reports noch weitere personenbezogene Produktionsschreibvorgänge.

Die Report-PDF verwendet ausschließlich pdf_parcel_outline. Nur ein bestätigter hit zeichnet die Parzellenoutline; bei no_hit, outside_coverage, ambiguous_boundary, quality_rejected, source_not_released oder failed bleibt sie null. Rechte, Freshness, Quality, Pilot-Coverage, Quarantäne und erfolgreicher Importlauf werden in einem einzigen atomaren SQL-Read geprüft; es gibt keinen Legacy- oder WMS-Geometrie-Fallback und keine Eigentümerdaten.

parcel_dxf ist im qualifizierbaren Rechtevertrag enthalten, code-seitig release_bound und seit dem Produktions- und Rollback-Readback vom 26. August 2026 kontrolliert aktiviert. DXF_EXPORT_ENABLED=true öffnet die Route nur gemeinsam mit dem qualifizierten Export-Release; der jederzeitige Rollbackzustand false liefert 404 und entfernt den Pfad aus dem öffentlichen OpenAPI-Schema. Der DXF-Aufruf verwendet denselben gespeicherten Mehrwertreport, dieselbe Koordinate und dieselbe Public-/Export-Parität und gibt nur vollständige, unveränderte Originalpolygone in voller Stützpunktdichte samt BEV-Attribution aus. Die schriftliche BEV-Klärung in #77 ist erfüllt; #412 ist mit positivem, negativem, Parser- und Rollback-Readback abgeschlossen. Der Export-Pointer ist produktiv aktiviert; GeoJSON-/PDF-/DXF-Consumer sind an denselben Release gebunden. Der öffentliche BEV-Exportvertrag beschreibt die vollständigen Rechte- und Aktivierungsgrenzen.


5. `widmung` — Flächenwidmung als Ampel

Quelle: NÖGIS Widmung, wöchentlich gespiegelt, `ST_Intersects`.

FeldTypPflichtHerkunftBeschreibung
`widmung.klasse`enum `bauland`|`gruenland`|`industrie`|`sonder`|`gemischt`|`unbekannt`jaengineAggregierte Hauptklasse.
`widmung.detail`stringoptionalexternalOriginal-Widmungstext NÖGIS.
`widmung.ampel`enum `gruen`|`gelb`|`rot`jaengine`gruen`=Bauland baureif, `gelb`=eingeschränkt/aufschließungsbedürftig, `rot`=Grünland/Bauverbot.
`widmung.ampel_begruendung`stringjaengineRegelbasierter Kurztext (kein LLM), z. B. „Bauland-Wohngebiet, baureif".
`widmung.restriktionen`string[]jaengineHarte Einschränkungen aus Zusatz-Layern (NÖGIS Wasserrecht Schutz-/Schongebiet, Lärminfo-Klasse). Leer = keine.
`widmung.rechtsverbindlich`booleanjastaticImmer `false` — nur Indikation, keine rechtsverbindliche Auskunft (DATA-SOURCES §NÖGIS).
`widmung.quelle_stand`ISO-8601 datejaengineStand der Widmung (Mirror-Sync bzw. LAND_DATUM aus dem Live-Layer).
`widmung.source`enum `dkm_mirror`|`wms`optionalengineHerkunft: dkm_mirror = exakte gespiegelte Geometrie (PostGIS); wms = NÖ-weiter Live-Fallback über RRU_WI_HUELLE (WMS-GetFeatureInfo), greift bei Mirror-Lücke/DB-Ausfall — gleiche Klassifikation, keine exakte Fläche.

6. `risiko` — Naturgefahren, Altlasten, Klima

FeldTypPflichtHerkunftBeschreibung
`risiko.hochwasser.stufe`enum `keine`|`niedrig`|`mittel`|`hoch`|`unbekannt`jaenginePfad B (NÖGIS) implementiert (lib/geo/hochwasser.ts): Stufe aus der häufigsten Abflusszone — HQ30/HQ100 → hoch, HQ300 → niedrig, keine → keine. (HORA-Pfad A bleibt Lizenz-blockiert.)
`risiko.hochwasser.hq_zone`enum `HQ30`|`HQ100`|`HQ300`|nulljaengineHäufigste (ungünstigste) Abflusszone, in der der Punkt liegt (NÖ-OGD HYD_HW30/100/300ETC, PostGIS-Mirror oder WMS-GFI). null = keine kartierte Zone.
`risiko.hochwasser.jaehrlichkeiten`number[]jaengineAlle am Punkt vorhandenen Jährlichkeiten, aufsteigend (z. B. [30,100,300]). Der Quellwert 200 aus HYD_HW300ETC bleibt als 200 erhalten, klassifiziert aber nominal als HQ300.
`risiko.hochwasser.ampel`enum `gruen`|`gelb`|`rot`|`unbekannt`jaengineHQ30/HQ100 → rot; HQ300 → gelb; keine Zone → grün.
`risiko.hochwasser.hinweis`stringjastaticWortgleich mit `disclaimer.bausteine.hochwasser_indikator`.
`risiko.hochwasser.source`enum `mirror`|`wms`optionalengineTatsächlicher Datenweg. Optional für rückwärtskompatible, bereits gespeicherte Reports. Das Karten-Overlay bleibt unabhängig davon WMS.
`risiko.hochwasser.quelle_stand`ISO-8601 datejaengineMirror: amtlicher LASTUPDATE-Stand des aktiven Snapshots. WMS: Abrufdatum, falls der Punktdienst keinen belastbaren Stand liefert.
`risiko.hora_pass.r2_key`string | nulloptionalexternalR2-Key des HORA-Pass-PDF (ADR-0014). `null` wenn Layer aus = Lizenz nicht geklärt.
`risiko.hora_pass.gefahren`objectjaexternalMap der 10 HORA-Gefahren → Stufe (`keine`/`niedrig`/`mittel`/`hoch`): `hochwasser`, `oberflaechenabfluss`, `lawine`, `erdbeben`, `rutschung`, `windspitzen`, `blitzdichte`, `hagel`, `schneelast`, `hitzeepisoden`. Aus Pfad-A-Parse; leeres Objekt wenn Pass nicht abrufbar.
`risiko.altlasten.intersect`booleanjaenginetrue, wenn ST_Covers für den nach EPSG:31287 transformierten Adresspunkt und eine veröffentlichte Altlast-Geometrie gilt. Polygonkanten zählen als Treffer. Das Feld behauptet keinen Parzellen-Intersect.
`risiko.altlasten.nearby_m`number | nulljaengineMetrischer Abstand in der nativen Projektion EPSG:31287 zur nächsten veröffentlichten Altlast innerhalb 1 km; null, wenn im Radius keine liegt.
`risiko.altlasten.referenz`string | nulljaengineRückwärtskompatible quellenspezifische Referenz. Bei neuen WFS-Reports identisch mit ubaid; bei einem No-Hit null.
`risiko.altlasten.ubaid`string | nulloptionalengineKanonische eindeutige Identität der getroffenen beziehungsweise nächsten WFS-Fläche. ALTNR ist nicht eindeutig und wird nicht als Identität verwendet. Optional nur für die Lesbarkeit historisch gespeicherter Reports.
`risiko.altlasten.hinweis`stringjastaticFix, beginnt mit „Nicht-Listung garantiert keine Schadstofffreiheit." und trägt seit #317 den Rechtsstand: seit 1.1.2025 keine Verdachtsflächen (ALSAG-Novelle BGBl. I Nr. 30/2024); Erstabschätzungs-Flächen des GIS Altlasten (§ 18 Abs. 4 ALSAG) mangels offener Lizenz nicht enthalten (DATA-SOURCES §ALSAG, R-03).
`risiko.altlasten.quelle_stand`ISO-8601 date | nulljaengineHistorisches Kompatibilitätsfeld: alte INSPIRE-Reports behalten ihren damaligen Fachstand. Neue WFS-Reports setzen null, weil der Provider keinen fachlichen Stichtag liefert. Der technische Abruf darf hier nicht als Datenstand erscheinen.
`risiko.altlasten.source_release_id`UUIDbei neuem WFS-ReportengineExakter aktiver, qualifizierter Release, der Treffer, Nähe oder belastbaren No-Hit gemeinsam bindet.
`risiko.altlasten.retrieved_at`ISO-8601 timestampbei neuem WFS-ReportengineTechnischer WFS-Abrufzeitpunkt des aktiven Releases; ausdrücklich kein fachlicher Datenstand.
`risiko.altlasten.source_vintage`nullbei neuem WFS-ReportengineImmer null, solange der Umweltbundesamt-WFS keinen fachlichen Stichtag ausweist.
`risiko.altlasten.hist_nutzung`object | nulloptionalengineVisueller Indikator-Sub-Block (Issue #135). Keine algorithmische Klassifikation, kein LLM-Bilderverstehen — der Frontend-Layer zeigt nur die Karten.
`risiko.altlasten.hist_nutzung.zeitstaende[]`arrayjaengineListe der historischen Zeitstände. Wien-Pilot: 3 (Luftbildplan 1938 / 1956 / Orthofoto heute, alle WMTS `mapsneu.wien.gv.at`).
`risiko.altlasten.hist_nutzung.zeitstaende[].slug`enum `lb1938`|`lb1956`|`heute`jaengineStabile ID des Zeitstands.
`risiko.altlasten.hist_nutzung.zeitstaende[].jahr`intjaengineAufnahmejahr.
`risiko.altlasten.hist_nutzung.zeitstaende[].quelle`stringjaengineKlartext-Quelle (z. B. „data.wien.gv.at — Luftbildplan 1938").
`risiko.altlasten.hist_nutzung.zeitstaende[].verfuegbar`booleanjaengine`true` innerhalb Wien-BBox, sonst `false`.
`risiko.altlasten.hist_nutzung.zeitstaende[].layer_ref`string | nulljaengineMapLibre-Raster-Tile-URL (`{z}/{y}/{x}`); `null` wenn `verfuegbar=false`.
`risiko.altlasten.hist_nutzung.zeitstaende[].attribution`stringjaengineKurzattribution für Karten-Footer (CC BY 4.0).
`risiko.altlasten.hist_nutzung.hinweis`stringjastaticFix: „Historische Karten und Luftbilder werden als visueller Indikator angezeigt. Keine Schadstoffaussage, keine algorithmische Bewertung. Bei Verdachtsmomenten ist eine fachliche Bodenuntersuchung erforderlich."
`risiko.altlasten.hist_nutzung.coverage_hinweis`string | nulljaengineInnerhalb Coverage `null`, außerhalb Pilot-Beschränkungs-Hinweis.
`risiko.geogen.rutschung`enum `keine`|`vorbegutachtung`|`erkundung`|`unbekannt`jaengineNÖGIS Geogene Gefahren `ST_Intersects` (Hanglagen).
`risiko.radon`object | nulloptionalengineRadon-Indikator-Block (Issue #132). `null` außerhalb Österreichs oder bei API-Ausfall (→ `degraded.radon`). Gemeinde-Ebene, keine Messung.
`risiko.radon.potenzialklasse`1 | 2 | 3 | nulljaengineÖNRAP-Klassifikation (1=niedrig, 2=mittel, 3=hoch).
`risiko.radon.rnv_status`enum `kein_schutz`|`vorsorge`|`schutz`|`unbekannt`jaengineRnV-Kategorie nach BGBl. II Nr. 470/2020 (rechtlich verbindlich).
`risiko.radon.rnv_gebiet_raw`string | nulljaengineRoh-Text aus der Quelle (audit-tauglich).
`risiko.radon.gemeinde`string | nulljaengineGemeinde-Name.
`risiko.radon.bezirk`string | nulljaenginePolitischer Bezirk.
`risiko.radon.gem_nr`number | nulljaengine5-stellige Gemeindekennzahl (Statistik Austria).
`risiko.radon.ampel`enum `gruen`|`gelb`|`rot`|`unbekannt`jaengineEngine-Mapping: Klasse 3 ODER Schutzgebiet → rot; Klasse 2 ODER Vorsorgegebiet → gelb; sonst grün.
`risiko.radon.hinweis`stringjastaticWortgleich mit `disclaimer.bausteine.radon_indikator_nicht_messung`.
`risiko.radon.quelle_stand`ISO-8601 datejaengineAbrufdatum (Live-API gegen LFRZ).
`solar`object | nulloptionalengineStandortgenaues Solarpotenzial (ADR-0037). `null` bei PVGIS-Ausfall → PV-Szenario nutzt die Konfig-Pauschale.
`solar.spez_ertrag_kwh_pro_kwp`numberjaexternalPVGIS spez. Jahresertrag [kWh/kWp] bei optimaler Ausrichtung (AC); Engine-Override der Pauschale `1140`.
`solar.einstrahlung_kwh_m2` / `solar.optimale_neigung_grad` / `solar.optimaler_azimut_grad`numberjaexternalEinstrahlung [kWh/m²] + von PVGIS bestimmte optimale Neigung/Azimut (0 = Süd).
`solar.quelle` / `solar.quelle_stand`stringjaexternalStrahlungs-DB (z. B. `PVGIS-SARAH3`) + Abrufdatum.
`solar.google`object | nulloptional (Premium)externalDachgenaue Google-Anreicherung (Building Insights). DC-Werte, Live-Overlay — vor Persistenz entfernt (`stripGoogleSolar`, ToS R-07); auf Permalinks abwesend. `null` = keine Coverage / Free-Tier.
`solar.google.max_kwp` / `.max_panels` / `.roof_segments`numberwenn `google`externalGrößte berechnete Belegung: kWp, Panel-Anzahl, Dachflächen.
`solar.google.max_yearly_kwh_dc` / `.implied_spez_kwh_pro_kwp_dc`numberwenn `google`externalJahresertrag (DC) + abgeleiteter spez. Ertrag (DC, ≠ PVGIS-AC).
`solar.google.imagery_quality` / `.imagery_date` / `.region_code`stringwenn `google`externalLuftbild-Qualität (HIGH/MEDIUM/BASE) + Datum + ISO-Regioncode.
`erreichbarkeit`object | nulloptionalengineErreichbarkeits-Score (#140, ADR-0036). Pro POI-Klasse der nächste kuratierte POI + Distanz + Fahrzeit. Env-gated: ohne `OSRM_BASE_URL` Luftlinien-Schätzung (`quelle: "luftlinie"`, Phase 2.0); mit gesetztem Backend echte Auto-Fahrzeit via OSRM `/table` (`quelle: "osrm"`, Phase 2.5), fail-open zurück auf Luftlinie bei Fehler/Timeout.
`erreichbarkeit.eintraege[]`arrayjaengine4 Einträge (autobahn, bahnhof, spital, schule), je mit Pfad zum nächsten kuratierten POI.
`erreichbarkeit.eintraege[].klasse`enum `autobahn`|`bahnhof`|`spital`|`schule`jaenginePOI-Kategorie.
`erreichbarkeit.eintraege[].label`stringjastaticAnzeige-Label (DE).
`erreichbarkeit.eintraege[].poi_id`string | nulljaengineStabile POI-ID aus `lib/maps/poi-at.ts`.
`erreichbarkeit.eintraege[].poi_name`string | nulljaengineKlartext-Name des nächsten POI.
`erreichbarkeit.eintraege[].distanz_km`number | nulljaengineDistanz in km (1 Nachkommastelle). Bei `quelle: "osrm"` Straßendistanz, sonst Luftlinie.
`erreichbarkeit.eintraege[].fahrzeit_min`number | nulljaengineFahrzeit in Minuten. Bei `quelle: "osrm"` echte Routing-Fahrzeit, sonst Schätzung (Luftlinie × 1.35 / 50 km/h).
`erreichbarkeit.eintraege[].quelle`enum `luftlinie`|`osrm`|`ors`jaengineMethode: `luftlinie` ohne Routing-Backend (Default), `osrm` mit gesetztem `OSRM_BASE_URL`. Pro Klasse kann einzeln auf `luftlinie` zurückfallen, wenn OSRM den POI nicht erreicht.
`erreichbarkeit.hinweis`stringjastaticPflicht-Hinweis: „Indikator-Schätzung … keine echte Routing-Fahrzeit".
`erreichbarkeit.coverage_hinweis`stringjastaticHinweis auf kuratiertes POI-Set (Pilot-Phase).
`breitband`object | nulloptionalengineBreitband-Versorgungs-Indikator (RTR/Breitbandatlas, Festnetz). `null` außerhalb versorgter Zellen/Österreichs oder bei API-Ausfall (→ `degraded.breitband`). Summe aller Infrastruktur-Anbieter, keine Anschlusszusage. Live via WMTS-GetFeatureInfo (REST-API per 30.06.2025 eingestellt).
`breitband.max_download_mbit`number | nulljaengineMax. Download-Rate der 100×100-m-Rasterzelle (Mbit/s; `0` = „< 1").
`breitband.klasse`string | nulljaengineKlassen-Freitext der Quelle (z. B. „≥ 1 Gbit/s").
`breitband.ampel`enum `gruen`|`gelb`|`rot`|`unbekannt`jaengineEngine-Mapping: ≥ 100 → grün; ≥ 30 → gelb; < 30 → rot; kein Wert → unbekannt.
`breitband.hinweis`stringjastaticWortgleich mit `disclaimer.bausteine.breitband_indikator`.
`breitband.quelle_stand`ISO-8601 datejaengineAbrufdatum (Live WMTS-GFI gegen `breitbandatlas.gv.at`).
`breitband.foerderausbau`object | nulloptionalengine#322 (M4): Geförderter Ausbau (BBA2020/BBA2030) in derselben Zelle als Zukunftssignal — gesetzt, sobald ein Förderprojekt trifft, sonst fehlend/null. Verändert ampel/max_download_mbit nicht (Ist-Schwellen 100/30 bleiben). Eigener Layer Gefoerderter-Ausbau-Rasterzellen (WMTS-GFI), fail-soft. R-03: gefördert ≠ Anschluss-/Termin-Zusage.
`breitband.foerderausbau.programm`stringwenn gesetztengineProgramm + Netz-Modell, roh (z. B. „BBA2030: OpenNet").
`breitband.foerderausbau.technik`string | nullwenn gesetztengineAusbautechnik (z. B. „FTTP").
`breitband.foerderausbau.projektende`string | nullwenn gesetztengineGeplantes Projektende inkl. Statustext (z. B. „…2027 (Zelle gebaut)") — Plan, keine Zusage.
`breitband.foerderausbau.foerdernehmerin`string | nullwenn gesetztengineBauendes/förderndes Unternehmen.
`breitband.foerderausbau.is_connect`booleanwenn gesetztenginetrue = Connect (punktuelle Anschlussförderung, nicht zwingend Bau), sonst flächiger Rasterausbau.
`breitband.foerderausbau.meldung`stringwenn gesetztengineAnzeigefertiger R-03-Kopfsatz (Web+PDF identisch); zwei Varianten nach is_connect.
`laerm`object | nulloptionalengineUmgebungslärm-Indikator (strategische EU-Lärmkarten, Kartierungsrunde 2022, END 2002/49/EG). Der aktuelle Vertrag umfasst vier Quelltypen: Straße, Schiene, Flug sowie Industrie/IPPC; IPPC ist nur in den ausgewiesenen Ballungsräumen kartiert. Kompatibilitätsregel: Nur wenn alle acht Flug-/IPPC-Felder als unteilbares Acht-Felder-Tupel vorhanden sind, darf ein Consumer den Vier-Quellen-Scope behaupten. Fehlt auch nur eines, ist der gespeicherte Altbericht fail-closed ausschließlich als Straße/Schiene zu kennzeichnen; Flug/IPPC dürfen weder als geprüft noch als „ohne Treffer“ erscheinen. `null` nur bei nicht verfügbarem/ungeprüftem Live-Pfad (→ `degraded.laerm`); „keine Zone" ist ein gültiges Ergebnis innerhalb des ausgewiesenen Scopes (Ampel grün). Berechnete Mittelungspegel in 4 m Höhe, keine Messung und kein 10-m-Raster. Der WMS-Pfad ist an einen qualifizierten Source-Release mit Live-Checks für Report, Karte und Legende gebunden. Quelle: www.laerminfo.at, Lizenz: CC BY 4.0, Attribution exakt „Datenquelle: www.laerminfo.at“.
`laerm.strasse_lden_db`number | nulljaengineUntergrenze des Straßen-Lden-Bandes in dB (z. B. 65 für 65–69); `null` = keine Zone.
`laerm.strasse_lden_klasse`string | nulljaengineRoh-Klassenbezeichner der Quelle (z. B. „Lden6569").
`laerm.strasse_lnight_db`number | nulljaengineUntergrenze des Straßen-Lnight-Bandes (Nacht).
`laerm.strasse_lnight_klasse`string | nulljaengineRoh-Klassenbezeichner Straße Nacht.
`laerm.schiene_lden_db`number | nulljaengineUntergrenze des Schienen-Lden-Bandes.
`laerm.schiene_lden_klasse`string | nulljaengineRoh-Klassenbezeichner Schiene Tag-Abend-Nacht.
`laerm.schiene_lnight_db`number | nulljaengineUntergrenze des Schienen-Lnight-Bandes (Nacht).
`laerm.schiene_lnight_klasse`string | nulljaengineRoh-Klassenbezeichner Schiene Nacht.
`laerm.flug_lden_db`number | nulloptional (Altberichte)engineUntergrenze des Flug-Lden-Bandes; `null` = keine kartierte Fluglärm-Zone.
`laerm.flug_lden_klasse`string | nulloptional (Altberichte)engineRoh-Klassenbezeichner Flug Tag-Abend-Nacht.
`laerm.flug_lnight_db`number | nulloptional (Altberichte)engineUntergrenze des Flug-Lnight-Bandes (Nacht).
`laerm.flug_lnight_klasse`string | nulloptional (Altberichte)engineRoh-Klassenbezeichner Flug Nacht.
`laerm.industrie_lden_db`number | nulloptional (Altberichte)engineUntergrenze des Industrie-/IPPC-Lden-Bandes; IPPC-Zonen sind nur in ausgewiesenen Ballungsräumen verfügbar.
`laerm.industrie_lden_klasse`string | nulloptional (Altberichte)engineRoh-Klassenbezeichner Industrie/IPPC Tag-Abend-Nacht.
`laerm.industrie_lnight_db`number | nulloptional (Altberichte)engineUntergrenze des Industrie-/IPPC-Lnight-Bandes (Nacht).
`laerm.industrie_lnight_klasse`string | nulloptional (Altberichte)engineRoh-Klassenbezeichner Industrie/IPPC Nacht.
`laerm.max_lden_db`number | nulljaengineHöchste Lden-Untergrenze über den beim Erstellen geprüften Scope (aktuell Straße, Schiene, Flug und Industrie/IPPC; in Altberichten ausschließlich Straße/Schiene); `null` = keine Zone innerhalb dieses Scopes.
`laerm.ampel`enum `gruen`|`gelb`|`rot`|`unbekannt`jaengineEngine-Mapping: Lden ≥ 70 ODER Lnight ≥ 60 → rot; sonst kartierte Zone → gelb; keine Zone → grün.
`laerm.hinweis`stringjastaticNeue Reports sind wortgleich mit `disclaimer.bausteine.laerm_indikator` und enthalten verbindlich: „Die Ampel ist ein Screening auf Basis der EU-Lärmkarten und ersetzt kein schalltechnisches Gutachten; Ansprüche auf Schallschutzmaßnahmen richten sich nach eigenen, teils niedrigeren Grenzwerten.“ Gespeicherte Altberichte können einen historischen Freitext enthalten (unter anderem die überholte „10-m-Raster“-Behauptung). Sichtbare Consumer dürfen diesen Text nicht ungeprüft wiedergeben: Sie normalisieren ihn auf einen aktuellen, Straße/Schiene-spezifischen Altbericht-Hinweis mit genau diesem R-03-Satz; Messwerte und Ampel des Snapshots bleiben unverändert.
`laerm.quelle_stand`ISO-8601 datejaengineAbrufdatum des release-gebundenen Live-WMS-GFI gegen `inspire.lfrz.gv.at`; ausdrücklich nicht Datenjahr oder Kartierungsstand (der ist 2022).
`oev`object | nulloptionalengineÖV-Güteklassen-Indikator (ÖROK/BMIMI-Modell, #101 Phase 2). Nur PostGIS-Mirror (Pilot-bbox, jährliche Datei-Lieferung über AustriaTech — kein amtlicher WMS/WFS): außerhalb der Spiegelung `null` (→ `degraded.oev`, reason `ausserhalb_pilot_spiegelung`). „Keine Güteklasse" am Punkt ist ein gültiges Ergebnis (Ampel rot).
`oev.gueteklasse`string | nulljaengineGüteklasse `A` (beste) … `G`; `null` = keine Klasse am Punkt. Klassen-Polygone überlappen — die beste Klasse gewinnt.
`oev.ampel`enum `gruen`|`gelb`|`rot`jaengineDeterministisch (`classifyOev`): A–C → grün, D–G → gelb, keine Klasse → rot. Schwellen am 16.07.2026 von Magnus bestätigt (M11); offene Rot-Differenzierung bei Bedarfsverkehr in #341.
`oev.ampel_begruendung`stringjaengineKlartext-Begründung der Ampel (deterministisch, kein LLM).
`oev.hinweis`stringjastaticWortgleich mit `disclaimer.bausteine.oev_indikator`.
`oev.quelle_stand`ISO-8601 date | nulljaengineFahrplan-Referenzdatum der Lieferung (aus der Spiegelung; nie das Report-Datum).
`oev.source`const `mirror`jaengineHerkunfts-Transparenz (analog `parcel.source`).
`schutzgebiete`object | nulloptionalengineSchutzgebiete-Indikator (NÖ-OGD Natur- + Wasserschutz). null außerhalb NÖ oder bei API-Ausfall (→ `degraded.schutzgebiete`). „Kein Treffer" ist ein gültiges Ergebnis (grün). Keine Rechtsauskunft. Live via WMS-GetFeatureInfo.
`schutzgebiete.treffer[]`arrayjaengineAlle zutreffenden Designationen (überlappende möglich).
`schutzgebiete.treffer[].kategorie`stringjaengineStabile ID (z. B. naturschutzgebiet, europaschutz_ffh, landschaftsschutzgebiet, nationalpark, naturpark, wasserschutzgebiet, wasserschongebiet).
`schutzgebiete.treffer[].label`stringjaengineAnzeige-Label (DE).
`schutzgebiete.treffer[].name`string | nulljaengineGebietsname aus der Quelle.
`schutzgebiete.treffer[].schwere`enum `gelb`|`rot`jaenginerot = streng (Naturschutz-/Europaschutz-/Nationalpark-/Wasserschutzgebiet); gelb = milder (Landschaftsschutz/Naturpark/Wasserschongebiet).
`schutzgebiete.ampel`enum `gruen`|`gelb`|`rot`|`unbekannt`jaengineUngünstigste Schwere über alle Treffer; grün wenn keiner.
`schutzgebiete.hinweis`stringjastaticWortgleich mit `disclaimer.bausteine.schutzgebiete_indikator`.
`schutzgebiete.quelle_stand`ISO-8601 datejaengineAbrufdatum (Live WMS-GFI gegen sdi.noe.gv.at).
`denkmal`object | nulloptionalengineDenkmalschutz (BDA-Denkmalverzeichnis §3 DMSG, NÖ). null, wenn keine Parzelle (KG+GstNr) aufgelöst wurde. Parzellenscharfer Match gegen vorgenerierte Liste (kein Netz/DB). Keine Rechtsauskunft; Ensembles/Umgebungsschutz nicht erfasst.
`denkmal.gelistet`booleanjaengineLiegt das Grundstück (KG-Code + GstNr) direkt im Denkmalverzeichnis?
`denkmal.objekte[]`arrayjaengineAuf der Parzelle gelistete Objekte (titel, schutzart).
`denkmal.gemeinde`string | nulljaengineGemeinde (aus KG-Code abgeleitet).
`denkmal.gemeinde_count`number | nulljaengineAnzahl denkmalgeschützter Objekte in der Gemeinde (Kontext).
`denkmal.ampel`enum `gruen`|`gelb`|`rot`|`unbekannt`jaenginegelistet → gelb; sonst grün. M8 (16.07.2026): Denkmalschutz ist ein Bewilligungsvorbehalt (Veränderung/Restaurierung/Abbruch BDA-pflichtig), kein Standort-Risiko — „Auflagen, aber Nutzung möglich". Für ein Reaktivierungs-Tool sind Denkmäler oft Zielobjekte; deshalb nie rot.
`denkmal.nachbarn[]`arrayjaengineDenkmalgeschützte Nachbarparzellen im 14-m-Umkreis (Rand-zu-Rand; Magnus-Entscheid 11.08.2026, #326: Nachbarbegriff baubehördlicher Verfahren/Parteistellung). Je Eintrag kg, gnr, distanz_m (0 = direkt angrenzend), objekte[]. Release-gebundener Mirror-Lookup (lookupParcelNeighborsMirror, Capability point_lookup) + In-Memory-BDA-Match. Rein informativ, keine Wirkung auf ampel (M8). Nur aussagekräftig bei nachbarn_geprueft=true.
`denkmal.nachbarn_geprueft`booleanjaenginefalse = Prüfung nicht möglich (Parzelle außerhalb des release-gebundenen Pilot-Spiegels oder Lookup nicht verfügbar) — dann ist nachbarn: [] keine Aussage und wird als „nicht geprüft“ angezeigt, nie als „keine Denkmäler in der Nachbarschaft“.
`denkmal.hinweis`stringjastaticWortgleich mit `disclaimer.bausteine.denkmal_indikator`.
`denkmal.quelle_stand`ISO-8601 datejaengineAbrufdatum (Lookup gegen die committete BDA-Liste).
`wlv`object | nulloptionalengineGefahrenzonenplan Wildbach & Lawine (WLV/BML, LFRZ WMS-GFI). null bei API-Ausfall (→ `degraded.wlv`); „keine Zone" ist ein gültiges Ergebnis (grün). Nur Gemeinden mit Plan (alpiner Raum). Keine rechtsverbindliche Zonen-Auskunft.
`wlv.zonen[]`string[]jaengineDistinkte Objektart-Werte am Punkt (z. B. „Rote Zone Wildbach", „Summenzone - Gelbe Zone Wildbach", „Raumrelevanter Bereich").
`wlv.ampel`enum `gruen`|`gelb`|`rot`jaengineRote Zone → rot; echte erhobene Zone (Gelbe/Summen-/Blaue/Braune) → gelb; keine Zone oder ausschließlich Raumrelevanter Bereich → grün. M10 (16.07.2026): Der Raumrelevante Bereich ist keine erhobene Gefahrenzone, sondern ein Planungs-Hinweis → keine Warnfarbe.
`wlv.raumrelevanter_bereich`booleanjaengineM10: Punkt liegt in einem Raumrelevanten Bereich der WLV. Treibt in UI/PDF einen eigenen ℹ️-Hinweis statt einer Warnfarbe; unabhängig von `ampel` (liegt zusätzlich eine echte Zone vor, führt diese die Ampel, der Hinweis bleibt Kontext).
`wlv.gemeinde`string | nulljaengineHauptgemeindename des Gefahrenzonenplans.
`wlv.revisionsjahr`number | nulljaengineRevisionsjahr des Plans (Daten-Vintage).
`wlv.hinweis`stringjastaticWortgleich mit `disclaimer.bausteine.wlv_indikator`.
`wlv.quelle_stand`ISO-8601 datejaengineAbrufdatum (Live WMS-GFI gegen inspire.lfrz.gv.at/000901).
`pendeln`object | nulloptionalenginePendler-/Arbeitsplatzindikator der GEMEINDE (#363; Statistik Austria, Abgestimmte Erwerbsstatistik + Arbeitsstättenzählung, Neon-Mirror stat_aest_gemeinde). Neutraler Info-Block ohne Ampel (Klima-Präzedenz): reine Statistik, kein Steckbrief-/Bilanz-Eintrag. null ohne Gemeindebezug (gem_nr aus dem Radon-Layer fehlt → `degraded.pendeln`, reason `keine_gemeinde`) oder wenn die Gemeinde nicht im Datenstand liegt (reason `gemeinde_nicht_im_datenstand`; Wien ist nach Gemeindebezirken codiert).
`pendeln.gemeinde` / `pendeln.gem_nr`string / numberjaengineGemeindename + 5-stellige Statistik-Austria-GKZ.
`pendeln.jahr`intjaengineBerichtsjahr der AEST (Stichtag 31.10.; ~1,5 Jahre Publikations-Lag).
`pendeln.auspendler_pct`number | nulljaengineAuspendler:innenanteil an den Erwerbstätigen am Wohnort (%).
`pendeln.erwerbstaetigenquote_pct` / `pendeln.arbeitslosenquote_pct`number | nulljaengineErwerbstätigenquote 15–64 / Arbeitslosenquote 15+ (%).
`pendeln.arbeitsstaetten` / `pendeln.besch_am_arbeitsort` / `pendeln.unternehmen` / `pendeln.bev_gemeinde`number | nulljaengineArbeitsort-Kennzahlen der Gemeinde (Arbeitsplatzdichte-Kontext).
`pendeln.hinweis`stringjastaticWortgleich mit `disclaimer.bausteine.pendeln_indikator`.
`pendeln.source`const `mirror`jaengineDatenweg-Kennung (Neon-Mirror, kein Live-Call).
`pendeln.quelle_stand`ISO-8601 datejaengineDaten-Vintage des Mirrors (max(stand) der Tabelle) — nie das Abfragedatum.
`demografie`object | nulloptionalengineBevölkerungsdynamik der GEMEINDE (#364; Statistik Austria, Bevölkerungsstand zum 1.1. + Wanderungsstatistik, Neon-Mirror stat_bev_gemeinde/stat_wanderung_gemeinde). Neutraler Info-Block ohne Ampel. Eine Geburten-/Sterbebilanz je Gemeinde existiert als OGD nicht und wird bewusst nicht ausgewiesen (Discovery #364, R-03). null-/degraded-Semantik wie `pendeln`.
`demografie.gemeinde` / `demografie.gem_nr`string / numberjaengineGemeindename + 5-stellige Statistik-Austria-GKZ.
`demografie.stichtag` / `demografie.bev`ISO-8601 date / numberjaengineAktuellster Bevölkerungsstand zum 1.1.
`demografie.bev_vor_1j` / `demografie.bev_vor_5j` / `demografie.delta_1j` / `demografie.delta_5j_pct`number | nulljaengineVergleichsbestände + Deltas; null, wenn das Vergleichsjahr nicht im Mirror liegt (kein erfundener Trend).
`demografie.wanderung`object | nulljaengineJüngstes Jahr mit vollständigem Saldo: `{ jahr, binnen_saldo, aussen_saldo, gesamt_saldo }` — Zu-/Wegzüge über die Gemeindegrenze (gemeindeinterne Umzüge ausgenommen); Außenwanderung liegt als OGD erst ab 2015 vor.
`demografie.hinweis`stringjastaticWortgleich mit `disclaimer.bausteine.demografie_indikator`.
`demografie.quelle_stand`ISO-8601 datejaengineDaten-Vintage des Mirrors — nie das Abfragedatum.
`demografie.source`const `mirror`jaengineDatenweg-Kennung (Neon-Mirror, kein Live-Call).
`boden`object | nulloptionalengineBFW-Bodenkarte eBOD am Punkt (#360; Gründigkeit + Wasserverhältnisse, PostGIS-Pilot-Mirror boden, Migrationen 0031 + 0033). Beide Themen gehören zu genau einem qualifizierten, unveränderlichen Erfolgs-Snapshot und werden atomar gemeinsam veröffentlicht. Neutraler Info-Block ohne Ampel. EHRLICHKEITS-REGEL: `kartiert=false` ist eine Abdeckungslücke (die eBOD erfasst nur landwirtschaftlich genutzte Flächen — typisch bebautes Gebiet), KEIN Befund über den Boden; der Block wird dann trotzdem gerendert. `null` außerhalb der Pilot-Spiegelung (→ `degraded.boden`, reason `ausserhalb_pilot_spiegelung`).
`boden.kartiert`booleanjaengineLiegt am Punkt ein eBOD-Polygon (mind. ein Thema)?
`boden.gruendigkeit` / `boden.wasserverhaeltnisse`string | nulljaengineKlartext-Klassen der BFW-Kartierung (z. B. „mittelgründig“, „trocken“). Treffen am randinklusiven Punkt mehrere unterschiedliche Klassen, enthält der String alle Werte mit dem Präfix „Mehrdeutig an Kartengrenze“; keine Klasse wird bevorzugt.
`boden.hinweis`stringjastaticWortgleich mit `disclaimer.bausteine.boden_indikator` (Landwirtschafts-Abdeckung, historisches Erhebungsalter, kein Bodengutachten).
`boden.quelle_stand`ISO-8601 datejaengineAtom-Feed-Stand der eBOD-Lieferung aus dem Mirror — nie das Abfragedatum.
`boden.source`const `mirror`jaengineDatenweg-Kennung (PostGIS-Mirror, kein Live-Call).
`bahn`object | nulloptionalengineBahnanbindung aus dem ÖBB-GTFS-Soll-Fahrplan (#380; CC BY 4.0, österreichweiter Snapshot gtfs_halt, Migration 0036): nächste Station im 5-km-Umkreis mit der GEMESSENEN Bedienung. Neutraler Info-Block ohne Ampel — ergänzt `oev` (ÖROK-Güteklasse = Modellwert mit Ampel), ersetzt ihn nicht. ⚠ Nur Schienenverkehr: Regionalbusse und Verbundlinien sind im Feed nicht enthalten. null, wenn keine Station im Umkreis liegt (→ `degraded.bahn`, reason `keine_station_im_umkreis`).
`bahn.station` / `bahn.distanz_m`string / numberjaengineStationsname + Luftlinie in Metern (kein Gehweg) — wird immer mit ausgewiesen.
`bahn.halte_werktag` / `bahn.halte_samstag` / `bahn.halte_sonntag`numberjaengineGeplante Halte an je einem Referenztag (Median-Tag des Fahrplanjahres nach aktiven Services), beide Richtungen, alle Bahnsteige der Station. Der ÖBB-Feed steuert den Betriebstag über calendar_dates.txt; eine reine calendar.txt-Summe ergäbe Werte, die an keinem Tag zutreffen (#380).
`bahn.spitzenstunde` / `bahn.spitzenstunde_halte`number | nulljaengineStunde (0–23) mit den meisten Werktags-Halten und deren Anzahl.
`bahn.top_ziele`arrayjaengineHäufigste Fahrtziele ab dieser Station als `{ ziel, halte }[]`; Züge, die AN dieser Station enden, sind ausgenommen.
`bahn.hinweis`stringjastaticWortgleich mit `disclaimer.bausteine.bahn_indikator` (Bus-Lücke, Regelfahrplan, Luftlinie).
`bahn.quelle_stand`ISO-8601 datejaengineFahrplanjahr-Start der Lieferung — nie das Abfragedatum.
`bahn.source`const `mirror`jaengineDatenweg-Kennung (Snapshot-Mirror, kein Live-Call).
`erdbeben`object | nulloptionalengineErdbebenzone nach ÖNORM B 1998-1 (#427; GeoSphere Austria, CC BY 4.0, österreichweiter Snapshot erdbeben_ort, Migration 0045, release-gebunden nach FND-03). Ampel per Magnus-Entscheid 11.08.2026 (#453): ampel + ampel_begruendung, Zone 0–1 grün · 2–3 gelb · 4 rot (classifyErdbeben); ausdrücklich keine Kostenwirkung auf die Szenarien; kein Steckbrief-/Bilanz-Eintrag (Bilanz-Einbindung nicht entschieden, Präzedenz M11). null außerhalb der Abdeckung (→ `degraded.erdbeben`, reason `ausserhalb_abdeckung`).
`erdbeben.zone`number (0–4)jaengineGefahrenzone nach ÖNORM B 1998-1. Zone 0 ist ein gültiger Wert (niedrigste Stufe), kein Leerwert.
`erdbeben.ort` / `erdbeben.plz` / `erdbeben.distanz_m`string / number / numberjaengineDer Ort, dem die Norm diese Zone zuordnet, samt Luftlinie in Metern. Steht IMMER dabei: Die ÖNORM ordnet je Ort zu, nicht je Grundstück — das Ortsnetz hat einen Median-Nachbarabstand von 3,3 km.
`erdbeben.ega` / `erdbeben.pga`numberjaengineReferenzwerte der Quelle, bewusst uninterpretiert und mit Feldnamen ausgewiesen. Was sie fachlich genau bezeichnen, ist aus der Quelle nicht dokumentiert (offener Punkt im Rechte-Review); beobachtet gilt durchgängig PGA = EGA × √2.
`erdbeben.hinweis`stringjastaticWortgleich mit `disclaimer.bausteine.erdbeben_indikator` (Ortsbezug, 2-km-Kartengenauigkeit, Zuständigkeit des Tragwerksplaners).
`erdbeben.quelle_stand`ISO-8601 datejaengineVeröffentlichungsstand des Quell-Items — nie das Abfragedatum.
`erdbeben.source`const `mirror`jaengineDatenweg-Kennung (Snapshot-Mirror, kein Live-Call).
`lcz`object | nulloptionalengineUmgebungsstruktur nach Local Climate Zones (#454; Demuzere et al. 2022, CC BY 4.0, 5×5-Zellen-Aggregat lcz_umgebung (~500 m N-S × ~335 m O-W), Migration 0046, release-gebunden nach FND-03): modale LCZ-Klasse eines 5×5-Zellen-Fensters um die Adresse (Gradraster: rund 500 m Nord-Süd × 335 m Ost-West). Neutraler Info-Block ohne Ampel — Strukturbeschreibung der NACHBARSCHAFT (Stewart & Oke: „local“ = Nachbarschaftsskala), keine Parzellenaussage, keine Klimamessung; kein Steckbrief-/Bilanz-Eintrag. null außerhalb des Österreich-Fensters (→ `degraded.lcz`, reason `ausserhalb_abdeckung`).
`lcz.klasse`number (1–17)jaengineModale LCZ-Klasse des Fensters (Stewart & Oke 2012). Web/PDF zeigen die neutral-deskriptive deutsche Beschreibung IMMER zusammen mit dem offiziellen englischen Klassennamen (LCZ_KLASSEN in labels.ts — redaktionelle Setzung, es existiert kein etabliertes Laienvokabular).
`lcz.anteil` / `lcz.n_valid`number / numberjaengineEinhelligkeit des Fensters: Zellen der Modalklasse von maximal 25 gültigen Rasterpixeln (~100 m N-S × ~67 m O-W). Ein heterogenes Fenster (z. B. 11/25) wird sichtbar ausgewiesen, nie geglättet.
`lcz.konfidenz`number (0–100)jaengineMittlere ML-Modell-Konfidenz (%) der Modal-Pixel aus dem Probability-Layer der Quelle — die Aggregations-Entscheidung (#454): Einzelpixel-Konfidenz streut 38–100 %, das Fenster-Mittel ist die ehrliche Angabe.
`lcz.distanz_m`numberjaengineLuftlinie zum Mittelpunkt der Gitterzelle (max. ~304 m konstruktionsbedingt — die Zellen sind anisotrop).
`lcz.hinweis`stringjastaticWortgleich mit `disclaimer.bausteine.lcz_indikator` (ehrliche Fenstergeometrie ~500 × 335 m, Nachbarschaftsaussage, ML-Herkunft, Nominaljahr 2018).
`lcz.quelle_stand`ISO-8601 datejaengineNominaljahr der Karte (2018-01-01) — nie das Abrufdatum; Darstellung zeigt das Jahr.
`lcz.source`const `mirror`jaengineDatenweg-Kennung (Snapshot-Mirror, kein Live-Call).

6.1 `risiko.klima` — release-gebundener SPARTACUS-v3-Snapshot

Sichtbarer Titel: „SPARTACUS v3 · Datenstand 2025 · 1-km-Raster". Die Attribution wird wortgleich als „Datenquelle: GeoSphere Austria - https://data.hub.geosphere.at" ausgegeben. Der Pflicht-Hinweis lautet: „Das 1-km-Raster ist ein regionaler Klimaindikator und weder Messung noch Prognose für eine einzelne Parzelle."

Neue Reports liefern den Klimawert ausschließlich aus dem aktiven, qualifizierten Release geosphere-spartacus-v3 und befüllen alle unten aufgeführten Provenienzfelder. Diese zusätzlichen Felder bleiben im JSON-Contract optional, damit bereits gespeicherte Reports ohne v3-Provenienz weiterhin lesbar sind. Im API-Schema gelten sie als unteilbares Alles-oder- Nichts-Tupel: Fehlt auch nur eines, ist der Block kein gültiger v3-Report und ein Client darf weder SPARTACUS v3 noch einen konkreten Release nachträglich behaupten.

FeldTypPflichtHerkunftBeschreibung
`risiko.klima.jahresmittel_temp_c`numberjaengineSPARTACUS-Jahresmittel der Lufttemperatur in °C.
`risiko.klima.jahresniederschlag_mm`numberjaengineSPARTACUS-Jahressumme des Niederschlags in mm.
`risiko.klima.sonnenstunden_jahr`numberjaengineSPARTACUS-Jahressumme der Sonnenscheindauer in Stunden; keine Einstrahlung und keine Grundlage für eine PV-Eignungs- oder Ertragsentscheidung.
`risiko.klima.referenzjahr`intjaengineAbgeschlossenes Kalenderjahr des Rasterwerts. Der qualifizierte v3-Snapshot verwendet 2025; gespeicherte Alt-Reports behalten ihr ursprüngliches Jahr.
`risiko.klima.quelle_stand`ISO-8601 datejaengineRückwärtskompatibler Anzeige-Stichtag. Die belastbare Snapshot-Provenienz steht zusätzlich in source_vintage und retrieved_at.
`risiko.klima.source_slug`const `geosphere-spartacus-v3`optionalengineRegistry-Schlüssel der tatsächlich gelesenen Quelle.
`risiko.klima.source_release_id`UUIDoptionalengineID des beim atomaren Lookup aktiven, qualifizierten Releases.
`risiko.klima.release_key`UUIDoptionalengineDeterministischer fachlicher Release-Schlüssel.
`risiko.klima.dataset_version`const `3`optionalengineSPARTACUS-Hauptversion; als String serialisiert.
`risiko.klima.transform_version`const `spartacus-v3-snapshot-v1`optionalengineVersion der deterministischen Artefakt-Transformation.
`risiko.klima.source_vintage`stringoptionalengineFachlicher Datenstand des qualifizierten Snapshots, aktuell 2025.
`risiko.klima.retrieved_at`ISO-8601 date-timeoptionalengineAbrufzeitpunkt des unveränderlich nachgewiesenen Quellartefakts.
`risiko.klima.resolution_m`const `1000`optionalengineNative Rasterauflösung in Metern.
`risiko.klima.native_crs`const `EPSG:3416`optionalengineKoordinatenreferenzsystem der Rasterzentren.
`risiko.klima.easting_m` / `risiko.klima.northing_m`int / intoptionalengineZentrum der tatsächlich verwendeten 1-km-Rasterzelle in EPSG:3416.
`risiko.klima.attribution`stringoptionalengineWortgleiche sichtbare Attribution: „Datenquelle: GeoSphere Austria - https://data.hub.geosphere.at".
`risiko.klima.attribution_url`URLoptionalengineSichtbarer Quellenlink https://data.hub.geosphere.at.
`risiko.klima.license`const `CC-BY-4.0`optionalengineLizenzkennung des aktiven Releases.
`risiko.klima.license_url`URLoptionalengineLink zur GeoSphere-Lizenzinformation.
`risiko.klima.terms_url`URLoptionalengineSichtbarer Link zu den GeoSphere-Nutzungsbedingungen.
`risiko.klima.boundary`stringoptionalstaticWortgleicher Pflicht-Hinweis zur regionalen Aussagegrenze des 1-km-Rasters.

6.2 `risiko.hitzebelastung` — historische GeoSphere-HORA-Schwellentage

Der optionale Block ist nur bei einer eigenständigen qualifizierten Freigabe der Quelle geosphere-hora-hitzelayer zulässig. Sein Ursprung ist ausschließlich die CC-BY-4.0-Distribution hora_hitzelayer-v1-1km für die historische Klimaperiode 1991–2020; HORA 3.0, HORA-Pass und LFRZ bleiben gesperrt.

Der aktive Quellenrelease ist im Produktionsnachweis rückgelesen. Derselbe Nachweis dokumentiert außerdem den später deployten Report-Consumer: Ein nicht persistierender öffentlicher GET auf Merge-Commit 08d55c3 lieferte den vollständigen optionalen Block für den versionierten Referenzpunkt. Ein fehlender Block bleibt bei fehlender Rasterabdeckung oder einem fail-closed Release-/Rechte-Gate weiterhin vertragskonform.

  • hitzetage_30c_jahr, extreme_hitzetage_35c_jahr, tropennaechte_20c_jahr und hitzewellentage_kysely_jahr sind historische mittlere Tage pro Jahr, nicht Werte eines aktuellen Kalenderjahres.
  • periodenbeginn ist 1991, periodenende ist 2020, source_vintage ist 1991-2020, dataset_version ist 1.
  • source_slug, source_release_id, release_key, transform_version, retrieved_at und quelle_stand binden den konkreten aktiven Release.
  • resolution_m: 1000, native_crs: EPSG:3416, easting_m und northing_m beschreiben die tatsächlich genutzte regionale Rasterzelle.
  • attribution, attribution_url, license: CC-BY-4.0, license_url: https://creativecommons.org/licenses/by/4.0/legalcode, terms_url und boundary sind untrennbare Pflichtprovenienz.

Fehlt eine Freigabe, ein Wert oder ein Herkunftsfeld, bleibt der gesamte Block unsichtbar; ältere Reports ohne diesen additiven Block bleiben gültig. Die Darstellung enthält keine Ampel, keine Prognose, keinen Trend und keine parzellenscharfe Messung. Der Klima-Block daneben bezeichnet weiterhin das abgeschlossene Referenzjahr 2025. Details: öffentlicher HORA-Hitzebelastungs-Vertrag.


7. `bestand` — Gebäude-Footprint

Quelle: Microsoft Building Footprints (Bulk, statisch) + optional Copernicus Versiegelung / Sentinel-2 NDVI (Phase 2).

FeldTypPflichtHerkunftBeschreibung
`bestand.bebaut`booleanjaengineOb ein Footprint die Parzelle schneidet.
`bestand.gebaeude_anzahl`intjaengineAnzahl geschnittener Footprints.
`bestand.footprint_flaeche_m2`numberjaengineSumme Footprint-Fläche auf der Parzelle.
`bestand.versiegelungsgrad_pct`number | nulloptionalengineCopernicus (Phase 2), sonst `null`.
`bestand.ndvi_index`number | nulloptionalengineSentinel-2 „überwuchert?" (Phase 2), sonst `null`.
`bestand.footprint_stand`ISO-8601 datejaengineDatensatz-Stand (statischer Bulk).

8. `grundbuch` — nur Premium (ADR-0016)

`null` für `free`/`standard`. Nur befüllt im `premium`-Pfad nach explizitem User-Trigger („Eigentumsverhältnisse abfragen") oder durch Magnus' Beratungsvorbereitung. Alle Personen pseudonymisiert — Klarnamen nie im Report-JSON, nie an LLM (ADR-0016 §Pseudonymisierung).

FeldTypPflichtHerkunftBeschreibung
`grundbuch.bezirksgericht`stringjaexternalBG aus JustizOnline-Auszug.
`grundbuch.katastralgemeinde`stringjaexternalKG-Code + Name.
`grundbuch.einlagezahl`stringjaexternalEZ.
`grundbuch.as_of`ISO-8601 datetimejaexternalStichtag des Auszugs (max. 90 Tage Cache, ADR-0016).
`grundbuch.eigentum.art`stringjaexternalz. B. „Schlichtes Miteigentum".
`grundbuch.eigentum.personen[]`object[]jaengine`{ anteil, name:"[PSEUDONYMISIERT]", wohnort_grob }` — `wohnort_grob` nur Land/Bundesland-Granularität.
`grundbuch.eigentum.aktivierungs_komplexitaet`enum `gering`|`mittel`|`hoch`jaengineAus B-Blatt abgeleitet.
`grundbuch.belastungen[]`object[]jaengine`{ art, berechtigter:"[PSEUDONYMISIERT]", impact }` — C-Blatt.
`grundbuch.dienstbarkeiten_zugunsten[]`object[]jaexternalC-Blatt, GSt-Referenzen (keine Personen).
`grundbuch.dienstbarkeiten_zulasten[]`object[]jaexternalC-Blatt.
`grundbuch.score.aktivierungs_faehigkeit`enum `einfach`|`mittel`|`schwierig`|`sehr_schwierig`jaengineDeterministische Score-Tabelle (ADR-0016, Magnus-kalibrierte Gewichte). Kein LLM.
`grundbuch.score.punktwert`numberjaengineRoh-Score (Bandbreiten: +5..+3 einfach … <−3 sehr_schwierig).
`grundbuch.score.kommentar`stringjaengineRegelbasierter Kurztext (z. B. realistischer Vorbereitungszeitraum).
`grundbuch.original_r2_key`stringjaexternalR2-Key des Original-PDF (Zugriff nur Auftraggeber, separater Auth-Check).
`grundbuch.disclaimer`stringjastatic„Stand: {as_of}. Spätere Änderungen können bestehen. Verbindliche Auskunft nur via aktuellem Auszug."

Offene Frage / Annahme: ADR-0016 fragt, ob eine eigene Rolle „Auftraggeber-mit-Namenseinsicht" nötig ist. Annahme dieses Specs: Klarnamen werden NIE in den Report-JSON-Contract aufgenommen; ein separater, nicht hier spezifizierter Endpoint liefert das Original-PDF an den authentifizierten Auftraggeber. Der Report bleibt damit durchgehend pseudonym → für Magnus' Workshop zu bestätigen.


9. `scenarios[]` — 3 bis 5 Nutzungsszenarien

Mindestens 3, maximal 5 Elemente (PRODUCT §User-Flow Punkt 3). Die Ampel-Bewertung und der gesamte `cost`-Block sind deterministisch (ADR-0015). Der `cost`-Block übernimmt das Schema aus ADR-0015 exakt und unverändert (`scenario`, `cost`, `cost_components`, `methodology`, `as_of_date`, `disclaimer`).

FeldTypPflichtHerkunftBeschreibung
`scenario_id`stringjaengineStabiler Slug, z. B. `pv-freiflaeche`.
`nutzungsklasse`enum `wohnen`|`gewerbe`|`pv_anlage`|`co_working`|`lager`|`tourismus`jaengineNutzungsklasse (ADR-0015 Säule 3).
`titel`stringjaengineAnzeige-Titel (Konfig-Template, kein LLM).
`ampel`enum `gruen`|`gelb`|`rot`jaengineEignung: harte Ausschlusskriterien (rot) / weiche Faktoren (gelb/grün).
`ampel_faktoren`object[]jaengine`{ faktor, bewertung:"+/-/0", quelle_ref }` — nachvollziehbare Regel-Treffer (Widmung, Fläche, Altlast sowie die Risiko-Layer Hochwasser HQ30/HQ100, Denkmalschutz, strenge Schutzgebiete → je -, stufen grün auf gelb).
`ausschluss_grund`string | nullwenn `rot`engineHarte Mindestanforderung verletzt (z. B. Mindestfläche, Schutzgebiet).
`kennzahlen`objectoptionalengineSzenario-spezifische deterministische Kennzahlen. PV-Beispiel: `{ "kwp": 20, "ertrag_kwh_jahr": 22800, "ertrag_eur_jahr": 6100, "strompreis_ct_kwh": 26.8 }`. Alle aus Engine, nie LLM.
`cost`objectjaengineExakt ADR-0015-Schema: `{ low, expected, high, unit:"EUR", bandwidth_pct }`.
`cost_components`object[]jaengineExakt ADR-0015: `[{ label, amount, source }]` — `source` zitiert Tabelle/Faktor.
`methodology`stringjastaticExakt ADR-0015: „ÖNORM B 1802-1:2022 + Heft 3/2025 + BPI Q-aktuell".
`as_of_date`ISO-8601 datejaengineADR-0015 — Cost-Stichtag (Config-Stand).
`disclaimer`stringjastaticADR-0015 — „Grob-Kostenschätzung, ersetzt keine Detailkalkulation durch Sachverständigen/Planer".
`foerder_trigger`string[]jaengineIDs förderfähiger Bausteine → join auf `foerderungen[]` (z. B. `kpc-flaechenrecycling`, `kpc-waermepumpe`).
`narrativ`stringnur `standard`/`premium`llm1–3 Absätze Erklärung. Darf nur Zahlen aus `cost`/`kennzahlen` 1:1 zitieren. In `free` vollständig weggelassen; `planer` bleibt laut §15 tabellarisch.

Offene Frage / Annahme: ADR-0015 listet Nutzungsklassen Wohnen/Gewerbe/PV/Co-Working/Lager/Tourismus, die exakten harten Mindestanforderungen + Cost-Bausteine pro Klasse liefert Magnus' POC- Woche-3-Workshop. Dieser Spec fixiert nur Struktur, nicht die Werte → Workshop-Input erforderlich.


10. `foerderungen[]` — RAG-Matching

Quelle: Förder-RAG (KPC/LEADER/KMU.DIGITAL/aws-Richtlinien als PDFs in pgvector). Das Matching (welche Förderung passt) ist `classification`-LLM (gpt-4o-mini/gemini-flash) mit striktem Tool-Output — Beträge/Sätze sind NICHT generiert, sondern aus dem kuratierten Förder-Katalog (Konfig) gezogen.

FeldTypPflichtHerkunftBeschreibung
`foerder_id`stringjaengineStabiler Slug, referenziert von `scenarios[].foerder_trigger`.
`programm`stringjastaticz. B. „KPC Flächenrecycling".
`traeger`stringjastaticKPC / LEADER / KMU.DIGITAL / aws.
`max_betrag_eur`number | nulljastaticAus Förder-Katalog (z. B. 60000). Nie LLM.
`max_satz_pct`number | nulljastaticz. B. 75.
`bedingung`stringjastaticFörderbedingung aus Katalog.
`match_score`numberjaengineRAG-Relevanz 0..1.
`match_begruendung`stringnur `standard`+llmWarum passend — nur qualitativ, keine neuen Zahlen.
`quelle`stringjastaticRichtlinien-Dokument + Stand (quartalsweise validiert).

11. `sources[]` — Attribution-Pflicht (POC-Kriterium)

Pro tatsächlich verwendetem Layer genau ein Eintrag. Erfüllt das POC-Akzeptanzkriterium „Quellen-Block … Datenquelle + Lizenz + Stand" und die Attribution-Pflicht aus DATA-SOURCES §Attribution-Maintenance.

FeldTypPflichtHerkunftBeschreibung
`layer`stringjaengineStabile Report-Sektion, z. B. `parcel`, `widmung`, `klima` oder `altlasten`.
`quelle`stringjastaticSichtbarer Quellenname beziehungsweise vorgeschriebener Attributionstext.
`lizenz`stringjastaticSichtbare Lizenzbezeichnung, z. B. „CC BY 4.0".
`stand`stringjaengineFachlicher Quellenstand. Fehlt ein Vintage, muss ein technischer Abruf ausdrücklich als solcher etikettiert werden, z. B. Techn. Abruf 2026-08-26.
`source_release_id`UUIDoptionalengineExakter qualifizierter Release bei release-gebundenen Quellen. Für den FND-03-BEV-Snapshot bei `hit`, `no_hit` und `ambiguous_boundary` Pflicht.
`quelle_url`URLoptionalstaticÖffentliche Primärquelle; niemals interner Artefakt- oder Storage-Pfad.
`lizenz_url`URLoptionalstaticMaschinenlesbarer Lizenzlink für Web und PDF.
`aenderungshinweis`stringoptionalstatic/engineSichtbarer Hinweis auf LandNutzen-Normalisierung oder Ableitung. Beim FND-03-BEV-Snapshot Pflicht.
`non_endorsement_hinweis`stringoptionalstaticSichtbarer Hinweis, dass die Quelle die LandNutzen-Auswertung nicht bestätigt oder unterstützt. Beim FND-03-BEV-Snapshot Pflicht.
`modellhinweis`stringoptionalstaticSichtbare fachliche Grenze eines Modells oder einer Ableitung.

Für den qualifizierten BEV-Snapshot müssen Quelle, CC-BY-4.0-Lizenz, Primär- und Lizenzlink, fachlicher Stand, source_release_id, Änderungshinweis und Non-Endorsement sowohl im Web als auch im PDF sichtbar bleiben. Ein WMS-Legacy-Treffer darf keine Snapshot-Release-ID übernehmen.

Für den Altlasten-WFS müssen quelle exakt „Datenquelle: Umweltbundesamt", die bedingte UBA-Weiterverwendung, Primär-/Bestätigungslink, der als technisch etikettierte Abruf und source_release_id in Web und PDF sichtbar bleiben. Die UBA-Bestätigung ist keine OGD-/CC-Lizenz. Ein fehlender oder abgelaufener Pointer sowie Rechte-, Qualitäts-, Frische- oder Scope-Drift erzeugen meta.degraded und niemals einen grünen Altlasten-No-Hit.

Ein Report muss ≥ 4 `sources` (BEV, NÖGIS-Widmung, GeoSphere, ALSAG) enthalten, sonst gilt das POC-Mindest-Datenlayer-Kriterium als verfehlt → `confidence.poc_min_layers_met = false`.


12. `confidence` — Unsicherheitshinweise

FeldTypPflichtHerkunftBeschreibung
`confidence.overall`enum `hoch`|`mittel`|`niedrig`jaengineAggregierte Konfidenz (fehlende Layer / Cache-Alter / `degraded`).
`confidence.notes`string[]jaengineKonkrete Hinweise (z. B. „SPARTACUS v3 · Datenstand 2025 · 1-km-Raster", „HORA-Layer aus — Lizenz nicht geklärt").
`confidence.poc_min_layers_met`booleanjaengine≥ 4 Pflicht-Datenlayer sichtbar verknüpft (POC-Kriterium A).
`confidence.cost_bandwidth_default_pct`numberjastaticStandard-Unsicherheit Cost (±20 %, ADR-0015 Säule 1).

13. `disclaimer` — Haftung & Opt-in

FeldTypPflichtHerkunftBeschreibung
`disclaimer.text`stringjastaticVoller Haftungsausschluss-Text (ADR-0007/POC-Kriterium B).
`disclaimer.opt_in_required`booleanjastaticImmer `true` — Checkbox vor Report-Anzeige (POC-Kriterium B).
`disclaimer.opt_in_recorded_at`ISO-8601 datetime | nulljaengineWann der User die Checkbox bestätigt hat (Audit). `null` = noch nicht bestätigt → Report bleibt verdeckt.
`disclaimer.bausteine`objectjastaticQuellen-spezifische Pflicht-Hinweise: `widmung_nicht_rechtsverbindlich`, `alsag_keine_freiheitsgarantie`, `bev_keine_vermessung`, `cost_keine_sachverstaendigenbewertung`, `radon_indikator_nicht_messung` (nur wenn `risiko.radon` gesetzt), `breitband_indikator` (nur wenn `breitband` gesetzt), `laerm_indikator` (nur wenn `laerm` gesetzt), `oev_indikator` (nur wenn `oev` gesetzt), `hochwasser_indikator` (nur wenn `risiko.hochwasser` gesetzt), `schutzgebiete_indikator` (nur wenn `schutzgebiete` gesetzt), `denkmal_indikator` (nur wenn `denkmal` gesetzt), `wlv_indikator` (nur wenn `wlv` gesetzt), `pendeln_indikator` (nur wenn `pendeln` gesetzt), `demografie_indikator` (nur wenn `demografie` gesetzt), `boden_indikator` (nur wenn `boden` gesetzt), `bahn_indikator` (nur wenn `bahn` gesetzt), `erdbeben_indikator` (nur wenn `erdbeben` gesetzt), `lcz_indikator` (nur wenn `lcz` gesetzt), `grundbuch_stichtag` (nur Premium).

14. `narrative` — die einzigen reinen LLM-Blöcke

FeldTypPflichtHerkunftBeschreibung
`narrative.summary`stringnur `standard`+llmExecutive-Summary (3–5 Sätze). Keine Zahl, die nicht in `engine`-Feldern steht.
`narrative.empfehlung`stringnur `premium`/`planer`llmHandlungsempfehlung (Opus 4.7).
`narrative.modell`stringjaengineWelches Modell den Narrativ erzeugt hat (`anthropic/claude-sonnet-4.6` etc.). Audit/Cost.
`narrative.guard_passed`booleanjaengineZahlen-Konsistenz-Guard bestanden (ADR-0015). `false` → Fallback-Template wurde gerendert.

Im `free`-Tier ist `narrative.summary` ein gekürzter Template-Satz (kein LLM-Call → Cost-Cap, POC LLM-Sub-Ziel < $0,10/Report), `narrative.modell = "template"`.


15. Free/anonym vs. Premium 490 € — Sektions-Matrix

Sektion`free` (anonym)`standard` (registriert)`premium` (490 €)`planer` (Abo)
`meta`, `parcel`, `widmung`
`risiko` (Klima/ALSAG/Hochwasser-Stufe)✅ Kurz✅ Voll✅ Voll✅ Voll
`risiko.hora_pass.r2_key` (PDF-Beilage)
`bestand`✅ Basis✅ + Versiegelung/NDVI✅ + Versiegelung/NDVI
`scenarios[]`6, ohne `narrativ`6 + `narrativ`6 + `narrativ` + Empfehlung6, tabellarisch
`scenarios[].cost_components`nur Summe✅ Detail✅ Detail✅ Detail
`foerderungen[]`Top 1, ohne Begründung✅ + Begründung✅ + Begründung
`grundbuch``null``null`✅ (nach Trigger)`null` (es sei denn explizit)
`narrative.summary`TemplateLLM (Sonnet)LLM (Opus)LLM (Sonnet)
`narrative.empfehlung`✅ (Opus)
`sources`, `confidence`, `disclaimer`

Die Report-Quota ist vom dargestellten Produkttier getrennt (Report-Quota-Vertrag):

  • anonym: 10 Reports/Tag pro pseudonymem Request-IP-Bucket;
  • bestehende, sicher aufgelöste Kontositzung: 10 Reports/Tag pro pseudonymem Account-Bucket — unabhängig von anderen Konten hinter derselben IP;
  • API-Key: das eigene in api_keys.daily_limit hinterlegte Tageslimit.

Ein angebotener ungültiger oder widerrufener API-Key bleibt 401 und darf nicht auf Sitzung oder anonym zurückfallen. Kann die bestehende Sitzung nicht sicher aufgelöst werden oder wurde der User gelöscht, gilt der anonyme IP-Bucket. X-Auth-Mode weist anon, session oder key aus; die beiden Rate-Limit-Header beschreiben den tatsächlich gewählten Bucket. Der Account-Bucket ersetzt nicht reports.ip_hash: Dort bleibt das Pseudonym der tatsächlichen Request-IP gespeichert.

Tier-Bestimmung erfolgt serverseitig aus Auth-Kontext (ADR-0006), nie client-seitig — Feld-Stripping passiert im Backend, bevor das JSON den Server verlässt. Die bestehende Browser-Sitzung eröffnet kein neues headless Cookie-Auth-Verfahren; Maschinenclients verwenden weiterhin API-Keys.


16. PDF-Mapping (ADR-0013)

TierPDF-PfadToolSektionen im PDF
`free` / `standard`Standard-Report-PDF`@react-pdf/renderer``meta`, Karte (pre-rendered PNG), `parcel`, `widmung`, `risiko` (kompakt), `bestand`, `scenarios` (Karten-Layout, Cost-Summe), Top-`foerderungen`, `sources`, `disclaimer`. Map als `(parcel_id, zoom, layer_preset)`-PNG-Cache.
`planer`Planer-Export-PDF`@react-pdf/renderer`Wie Standard, aber tabellen-lastig, alle `cost_components`, weniger Narrativ, hohe Volumina.
`premium` (490 €)Beratungs-Report-PDFPuppeteer (Fluid Compute)Alle Sektionen inkl. `grundbuch`, `narrative.empfehlung`, volle `cost_components`, interaktiv gerenderte MapLibre-Karte. HORA-Pass-PDF (`risiko.hora_pass.r2_key`) als letzte 2 Seiten angehängt (ADR-0014 Variante α — Attribution via BMLUK-Footer automatisch erfüllt).

Felder mit Herkunft `external`/`engine` werden in beide Templates 1:1 übernommen; `llm`-Felder nur wenn `narrative.guard_passed = true`, sonst Template-Fallback.


17. Vollständiges Beispiel-JSON (fiktive NÖ-Adresse, `premium`)

Fiktive Liegenschaft, Pilotregion NÖ. Enthält das POC-PV-Szenario mit konkreter Euro-Zahl. Der Klimablock verwendet den separat rückgelesenen SPARTACUS-v3-Referenzwert für die angeführte Gänserndorf-Rasterzelle; die übrigen Felder bleiben illustrative Beispieldaten.

```json { "schema_version": "1.0.0", "report_id": "9f2c1e7a-0b44-4d21-9c3e-7a1b6f0e2d55", "meta": { "address": { "raw": "Hauptstraße 12, 2230 Gänserndorf", "normalized": "Hauptstraße 12, 2230 Gänserndorf, Niederösterreich, AT" }, "coordinate": { "lat": 48.3417, "lon": 16.7192, "source": "bev" }, "region": { "slug": "at-noe", "name": "Niederösterreich" }, "report_tier": "premium", "org_id": 42, "requested_by": "user", "as_of": "2026-05-16", "generated_at": "2026-05-16T09:14:02Z", "engine_version": "0.3.0", "config_version": "bodenwerte@2025.4+herstellungskosten@heft3-2025+bpi@2025Q2", "degraded": [] }, "parcel": { "found": true, "lookup_status": "hit", "parcel_uid": "AT:08221:1247/3", "source_release_id": "cb735e6f-6c32-5de0-87fd-594aa34a1903", "match_method": "point_in_polygon", "match_confidence": 1, "grundstuecksnummer": "1247/3", "katastralgemeinde": "08221 Gänserndorf", "area_m2": 1840, "area_tolerance_pct": 10, "source": "dkm_mirror", "kataster": "grundsteuerkataster", "bev_stand": "2026-04-01", "vermessung_disclaimer": "Grundstücksgeometrie und -fläche stammen aus der BEV-Digitalen Katastralmappe (DKM) und ersetzen keine rechtsverbindliche Vermessung. Verbindliche Grenzen und Flächen ergeben sich nur aus Grundbuch bzw. behördlicher Vermessung (Grenzkataster)." }, "widmung": { "klasse": "bauland", "detail": "Bauland-Wohngebiet (BW)", "ampel": "gruen", "ampel_begruendung": "Bauland-Wohngebiet, baureif, keine harten Restriktionen", "restriktionen": [], "rechtsverbindlich": false, "quelle_stand": "2026-05-12" }, "risiko": { "hochwasser": { "stufe": "niedrig", "hq_zone": null }, "hora_pass": { "r2_key": "hora-pass/48.3417-16.7192.pdf", "gefahren": { "hochwasser": "niedrig", "oberflaechenabfluss": "niedrig", "lawine": "keine", "erdbeben": "mittel", "rutschung": "keine", "windspitzen": "mittel", "blitzdichte": "niedrig", "hagel": "mittel", "schneelast": "niedrig", "hitzeepisoden": "mittel" } }, "altlasten": { "intersect": false, "nearby_m": null, "referenz": null, "ubaid": null, "hinweis": "Nicht-Listung garantiert keine Schadstofffreiheit. Enthalten sind ausschließlich veröffentlichte Altlasten des Altlastenportal-WFS; der Status „Altlast vorgeschlagen“ ist ausgeschlossen. Punktprüfung, keine rechtsverbindliche Auskunft.", "quelle_stand": null, "source_release_id": "8ed8d136-f3f8-5a78-946b-4b419a050269", "retrieved_at": "2026-08-26T03:16:54.083Z", "source_vintage": null }, "geogen": { "rutschung": "keine" }, "klima": { "jahresmittel_temp_c": 11.9, "jahresniederschlag_mm": 467.7, "sonnenstunden_jahr": 2121.7, "referenzjahr": 2025, "quelle_stand": "2026-08-04", "source_slug": "geosphere-spartacus-v3", "source_release_id": "81ef8803-2d64-5d30-9d7f-cd526ce57e69", "release_key": "74f23173-4256-5296-b4e3-d93aa1f70a5c", "dataset_version": "3", "transform_version": "spartacus-v3-snapshot-v1", "source_vintage": "2025", "retrieved_at": "2026-08-04T23:16:02.000Z", "resolution_m": 1000, "native_crs": "EPSG:3416", "easting_m": 650500, "northing_m": 498500, "attribution": "Datenquelle: GeoSphere Austria - https://data.hub.geosphere.at", "attribution_url": "https://data.hub.geosphere.at", "license": "CC-BY-4.0", "license_url": "https://dataset.api.hub.geosphere.at/v1/docs/user-guide/license.html", "terms_url": "https://data.hub.geosphere.at/de/legal?lang=de", "boundary": "Das 1-km-Raster ist ein regionaler Klimaindikator und weder Messung noch Prognose für eine einzelne Parzelle." } }, "bestand": { "bebaut": true, "gebaeude_anzahl": 1, "footprint_flaeche_m2": 142, "versiegelungsgrad_pct": 31, "ndvi_index": 0.42, "footprint_stand": "2025-09-01" }, "grundbuch": { "bezirksgericht": "Gänserndorf", "katastralgemeinde": "08221 Gänserndorf", "einlagezahl": "612", "as_of": "2026-04-02T07:51:10Z", "eigentum": { "art": "Schlichtes Miteigentum", "personen": [ { "anteil": "1/2", "name": "[PSEUDONYMISIERT]", "wohnort_grob": "AT, NÖ" }, { "anteil": "1/2", "name": "[PSEUDONYMISIERT]", "wohnort_grob": "AT, Wien" } ], "aktivierungs_komplexitaet": "mittel" }, "belastungen": [ { "art": "Hypothek", "berechtigter": "[PSEUDONYMISIERT]", "impact": "lösbar mit Refinanzierung" } ], "dienstbarkeiten_zugunsten": [], "dienstbarkeiten_zulasten": [ { "art": "Wegerecht", "ueber": "GSt 1247/3", "zugunsten": "GSt 1247/4" } ], "score": { "aktivierungs_faehigkeit": "mittel", "punktwert": 1, "kommentar": "Zwei Miteigentümer, eine lösbare Hypothek. Aktivierung mit überschaubarem Koordinationsaufwand realistisch, Vorbereitung 3–6 Monate." }, "original_r2_key": "grundbuch/3f9a...c1.pdf", "disclaimer": "Stand: 2026-04-02. Spätere Änderungen können bestehen. Verbindliche Auskunft nur via aktuellem Auszug." }, "scenarios": [ { "scenario_id": "pv-freiflaeche", "nutzungsklasse": "pv_anlage", "titel": "PV-Freiflächen-Anlage 20 kWp", "ampel": "gelb", "ampel_faktoren": [], "ausschluss_grund": null, "kennzahlen": { "kwp": 20, "ertrag_kwh_jahr": 22800, "ertrag_eur_jahr": 6100, "strompreis_ct_kwh": 26.8 }, "cost": { "low": 26000, "expected": 30000, "high": 34500, "unit": "EUR", "bandwidth_pct": 20 }, "cost_components": [ { "label": "PV-Module + Wechselrichter (20 kWp)", "amount": 26000, "source": "Konfig: PV 1.300 EUR/kWp installiert (ADR-0015 Säule 3)" }, { "label": "Montage Freifläche + Unterkonstruktion", "amount": 3000, "source": "Konfig: Freiflächen-Aufschlag" }, { "label": "Netzanschluss + Zählertausch", "amount": 1000, "source": "Konfig: Standard-Netzanschluss NÖ" } ], "methodology": "ÖNORM B 1802-1:2022 + Heft 3/2025 + BPI Q-aktuell", "as_of_date": "2026-05-14", "disclaimer": "Grob-Kostenschätzung, ersetzt keine Detailkalkulation durch Sachverständigen/Planer", "foerder_trigger": ["kpc-pv"], "narrativ": "PVGIS liefert für die Beispielkonfiguration einen rechnerischen Jahresertrag von etwa 22.800 kWh. Daraus folgt keine Eignungsentscheidung; Verschattung, Dach- beziehungsweise Flächennutzung, Netzanschluss und Genehmigungen sind gesondert zu prüfen. Die Investitionskosten liegen bei etwa 30.000 EUR (±20 %)." }, { "scenario_id": "wohnen-sanierung", "nutzungsklasse": "wohnen", "titel": "Sanierung Bestandsgebäude für Wohnnutzung", "ampel": "gelb", "ampel_faktoren": [ { "faktor": "Widmung Bauland-Wohngebiet", "bewertung": "+", "quelle_ref": "noegis-widmung" }, { "faktor": "Bestand vorhanden", "bewertung": "+", "quelle_ref": "ms-footprints" }, { "faktor": "Erdbeben mittel (HORA)", "bewertung": "-", "quelle_ref": "hora-pass" } ], "ausschluss_grund": null, "kennzahlen": { "wohnnutzflaeche_m2": 110 }, "cost": { "low": 232000, "expected": 290000, "high": 348000, "unit": "EUR", "bandwidth_pct": 20 }, "cost_components": [ { "label": "Gebäude-Bestand-Sanierung", "amount": 255000, "source": "Heft 3/2025 NÖ gehoben 3.200 EUR/m² × 110 m² × 0.72 (Sanierungs-Faktor)" }, { "label": "Heizungstausch (KPC-förderfähig)", "amount": 25000, "source": "Konfig: HVAC-Wärmepumpe Standard" }, { "label": "Außenanlagen-Aufschlag", "amount": 10000, "source": "Heft 3/2025: ~2 % Aufschlag (einfach)" } ], "methodology": "ÖNORM B 1802-1:2022 + Heft 3/2025 + BPI Q-aktuell", "as_of_date": "2026-05-14", "disclaimer": "Grob-Kostenschätzung, ersetzt keine Detailkalkulation durch Sachverständigen/Planer", "foerder_trigger": ["kpc-waermepumpe", "kpc-flaechenrecycling"], "narrativ": "Das Bestandsgebäude lässt sich für Wohnnutzung sanieren. Der Sanierungsaufwand wird auf rund 290.000 EUR geschätzt (±20 %), basierend auf dem Heft-3/2025-Wert für NÖ gehobene Ausstattung und einem Sanierungs-Faktor. Der Heizungstausch ist KPC-förderfähig." }, { "scenario_id": "lager-logistik", "nutzungsklasse": "lager", "titel": "Lager-/Logistiknutzung", "ampel": "rot", "ampel_faktoren": [ { "faktor": "Widmung Wohngebiet schließt Lager aus", "bewertung": "-", "quelle_ref": "noegis-widmung" } ], "ausschluss_grund": "Harte Ausschlussregel: Widmung Bauland-Wohngebiet lässt gewerbliche Lagernutzung nicht zu.", "kennzahlen": {}, "cost": { "low": 0, "expected": 0, "high": 0, "unit": "EUR", "bandwidth_pct": 0 }, "cost_components": [], "methodology": "ÖNORM B 1802-1:2022 + Heft 3/2025 + BPI Q-aktuell", "as_of_date": "2026-05-14", "disclaimer": "Grob-Kostenschätzung, ersetzt keine Detailkalkulation durch Sachverständigen/Planer", "foerder_trigger": [], "narrativ": "Eine Lager-/Logistiknutzung ist an diesem Standort aufgrund der Widmung Bauland-Wohngebiet rechtlich ausgeschlossen." } ], "foerderungen": [ { "foerder_id": "kpc-pv", "programm": "KPC Photovoltaik", "traeger": "KPC", "max_betrag_eur": null, "max_satz_pct": 30, "bedingung": "Investitionszuschuss für Photovoltaik-Anlagen, Antrag vor Umsetzung", "match_score": 0.88, "match_begruendung": "Das PV-Freiflächen-Szenario fällt in den förderfähigen Anlagentyp der KPC-Photovoltaik-Richtlinie.", "quelle": "KPC-Richtlinie PV, Stand Q1/2026 (quartalsweise validiert)" }, { "foerder_id": "kpc-flaechenrecycling", "programm": "KPC Flächenrecycling", "traeger": "KPC", "max_betrag_eur": 60000, "max_satz_pct": 75, "bedingung": "Bis 75 % bzw. max. 60.000 EUR für Konzept, 50.000 EUR Detailuntersuchung", "match_score": 0.71, "match_begruendung": "Reaktivierung einer untergenutzten Baufläche — passt zum Flächenrecycling-Zweck.", "quelle": "KPC-Richtlinie Flächenrecycling, Stand Q1/2026" } ], "sources": [ { "layer": "parcel", "quelle": "Datenquelle: BEV – Bundesamt für Eich- und Vermessungswesen (data.bev.gv.at), CC BY 4.0", "lizenz": "CC BY 4.0", "stand": "2026-04-01", "source_release_id": "cb735e6f-6c32-5de0-87fd-594aa34a1903", "quelle_url": "https://data.bev.gv.at/geonetwork/srv/api/records/ac633f87-19f4-4f78-9052-74c63ff88331", "lizenz_url": "https://creativecommons.org/licenses/by/4.0/", "aenderungshinweis": "LandNutzen normalisiert BEV-KG und Grundstücksnummer zu einer stabilen internen Parzellen-ID und berechnet den Punkt-in-Polygon-Treffer.", "non_endorsement_hinweis": "Das BEV bestätigt oder unterstützt diese LandNutzen-Auswertung nicht." }, { "layer": "widmung", "quelle": "Land NÖ — Widmungsumhüllende (OGD, gespiegelt nach PostGIS)", "lizenz": "CC BY 4.0", "stand": "2026-05-12" }, { "layer": "klima", "quelle": "Datenquelle: GeoSphere Austria - https://data.hub.geosphere.at", "lizenz": "CC-BY-4.0", "stand": "2025", "source_release_id": "81ef8803-2d64-5d30-9d7f-cd526ce57e69", "quelle_url": "https://data.hub.geosphere.at/en/dataset/spartacus-v3-1y-1km", "lizenz_url": "https://dataset.api.hub.geosphere.at/v1/docs/user-guide/license.html", "aenderungshinweis": "LandNutzen hat die gelieferten Integer-Skalierungen ausschließlich für die Anzeige umgerechnet: TM durch 10 in °C, RR durch 10 in mm und SA durch 3600 in Stunden.", "non_endorsement_hinweis": "GeoSphere Austria bestätigt oder unterstützt diese LandNutzen-Auswertung nicht.", "modellhinweis": "Das 1-km-Raster ist ein regionaler Klimaindikator und weder Messung noch Prognose für eine einzelne Parzelle." }, { "layer": "altlasten", "quelle": "Datenquelle: Umweltbundesamt", "lizenz": "Weiterverwendung gemäß UBA-Bestätigung vom 11.08.2026", "stand": "Techn. Abruf 2026-08-26", "source_release_id": "8ed8d136-f3f8-5a78-946b-4b419a050269", "quelle_url": "https://www.altlasten.gv.at/atlas/altlasten-gis.html", "lizenz_url": "https://github.com/ostheimer/landnutzen/issues/351#issuecomment-5249657094", "aenderungshinweis": "LandNutzen beschränkt den WFS auf veröffentlichte Altlasten, schließt den Status „Altlast vorgeschlagen“ aus und prüft nur den Adresspunkt.", "modellhinweis": "Der technische Abrufzeitpunkt ist kein fachlicher Datenstand. Die Punktprüfung ist ein Screening und keine Altlastenfreiheitsbestätigung." } ], "confidence": { "overall": "hoch", "notes": ["SPARTACUS v3 · Datenstand 2025 · 1-km-Raster (regionaler Klimaindikator)"], "poc_min_layers_met": true, "cost_bandwidth_default_pct": 20 }, "disclaimer": { "text": "Dieser Report ist eine unverbindliche Erst­einschätzung des Nutzungs-Potenzials. Er ersetzt keine rechtsverbindliche Vermessung, keine Sachverständigen­bewertung und keine Detailkalkulation. Alle Werte sind Grob-Schätzungen mit angegebener Bandbreite.", "opt_in_required": true, "opt_in_recorded_at": "2026-05-16T09:13:55Z", "bausteine": { "widmung_nicht_rechtsverbindlich": "Widmungs­angaben sind nur Indikation, keine rechtsverbindliche Auskunft der Gemeinde.", "alsag_keine_freiheitsgarantie": "Nicht-Listung im Altlastenkataster garantiert keine Schadstofffreiheit.", "bev_keine_vermessung": "Errechnete Flächen/Szenarien ersetzen keine rechtsverbindliche Vermessung.", "cost_keine_sachverstaendigenbewertung": "Grob-Kostenschätzung nach ÖNORM B 1802-1, keine Sachverständigen­bewertung im Sinne der GewO.", "grundbuch_stichtag": "Grundbuch-Daten Stand 2026-04-02. Spätere Änderungen können bestehen." } }, "narrative": { "summary": "Die Liegenschaft in 2230 Gänserndorf liegt in Bauland-Wohngebiet ohne harte Restriktionen. Drei Nutzungsszenarien wurden geprüft: eine PV-Freiflächen-Anlage (empfohlen, ca. 6.100 EUR Jahresertrag), eine Wohn-Sanierung des Bestands (rund 290.000 EUR) sowie eine Lagernutzung (widmungsrechtlich ausgeschlossen). Die Eigentumsverhältnisse (zwei Miteigentümer) erlauben eine Aktivierung mit überschaubarem Koordinationsaufwand.", "empfehlung": "Kurzfristig größter Hebel: PV-Freiflächen-Anlage mit KPC-Photovoltaik-Förderung als niederschwelliger Einstieg, parallel Klärung der Hypothek für ein späteres Sanierungs­szenario.", "modell": "anthropic/claude-opus-4.7", "guard_passed": true } } ```


18. Offene Fragen für Magnus' Domain-Workshop

  • Harte Mindestanforderungen + Cost-Bausteine pro Nutzungsklasse (Wohnen/Gewerbe/PV/Co-Working/Lager/Tourismus) — dieser Spec fixiert nur die Struktur (ADR-0015 Säule 3, POC Woche 3).
  • Ampel-Schwellen: Welche weichen Faktoren kippen `gruen`→`gelb`, welche sind harte `rot`-Ausschlüsse je Klasse?
  • Grundbuch-Klarnamen-Auth: Bestätigung der Annahme in §8 — Klarnamen nie im Report-JSON, separater Auftraggeber-Endpoint (ADR-0016 offene Frage).
  • Förder-Katalog-Pflege: Welche Programme im MVP-Katalog, wer validiert quartalsweise die Beträge/Sätze (DATA-SOURCES §Förder).
  • PV-Referenz-Annahmen: kWp→kWh-Faktor und Strompreis für die POC-Euro-Zahl — Engine-Konstante oder regionsabhängig?