ADR-0061: Produktnaher Vier-Tier-Report-Vertrag im PDF/UA-Preview-Shadow

  • Status: angenommen; Preview und Produktionstrennung verifiziert, Produktrollout offen
  • Datum: 28. August 2026
  • Issue: #333 bleibt offen
  • Vorgänger: ADR-0060

Kontext

Slice B belegt einen reinen Node.js-PDF/UA-1-Shadow mit vier direkt für den Renderer definierten synthetischen View-Fixtures. Der Pfad ist in Preview laufzeitverifiziert und bleibt in Produktion verborgen. Er beweist jedoch nicht, dass sich der deployte Report-Vertrag kontrolliert auf dieselbe semantische Ausgabe abbilden lässt.

Ein unmittelbarer Zugriff auf gespeicherte Reports wäre für diesen Schritt zu früh: Er würde Datenbank-, Retention-, Adress- und Kontogrenzen in einen noch nicht freigegebenen Renderer ziehen. Slice C benötigt stattdessen einen produktnahen, reproduzierbaren Eingang, der die tatsächlichen Feldnamen und Tiergates verwendet, ohne reale Daten oder einen neuen öffentlichen Pfad zu eröffnen.

Entscheidung

  1. Slice C definiert für free, standard, premium und planer je ein vollständig repository-fixiertes Objekt des deployten TypeScript-Typs Report. Alle Werte sind erfunden. Die Meta-Adresse bezeichnet sich ausdrücklich als nicht reale Adresse, die Koordinate ist null, der Report ist nicht gespeichert und besitzt weder Konto- noch Permalink-ID.

  2. Ein expliziter Mapper reduziert den Report-Eingang auf die bereits validierte PDF/UA-View. Nur folgende Bindungen sind erlaubt:

    Report-FeldPDF/UA-View
    meta.report_tier, generated_at, as_ofTier und Zeitstand
    parcel.area_m2synthetischer Standort-Steckbrief
    erste drei steckbrief-EinträgeRisiko-Tabelle
    scenarios[]Szenario-, Status-, Kosten- und Narrativdarstellung
    foerderungen[].programmFörderhinweis-Liste
    solar.googleausschließlich drei fest erwartete numerische Solarwerte

    Adresse, Koordinate, Katasterbezeichnungen, Disclaimer-Rohobjekte, imagery_quality, imagery_date, Quellenobjekte und andere nicht aufgeführte Felder gelangen nicht in die Renderer-View.

  3. Der Mapper schließt fail-closed, wenn Fläche, Zeitstand, Zahl der Szenarien oder Förderhinweise, Risikostatus oder die drei Solarwerte vom festen Vertrag abweichen. So kann eine spätere Fixture-Mutation nicht still den validierten Layout- und Strukturvertrag verändern.

  4. Die vorhandenen Tiergates bleiben maßgeblich: Nur standard und premium enthalten scenarios[].narrativ; nur premium und planer enthalten den synthetischen solar.google-Block. Der Mapper leitet diese Unterschiede aus den tatsächlichen Reportfeldern ab und berechnet sie nicht ein zweites Mal.

  5. Der HTTP-Zugang bleibt unverändert eng: POST /api/internal/pdf-ua-shadow/[tier], ausschließlich VERCEL_ENV=preview, ohne Query oder Body und hinter Vercel Deployment Protection. Produktion, Development, Nicht-POST-Methoden und ungültige Tiers bleiben geschlossen. Die Antwort kennzeichnet Slice C mit X-LandNutzen-PDF-UA-Shadow: slice-c-1.

  6. Renderer, Finalizer, fünfseitiger Strukturvertrag, zwei informative Figuren, zwei Links, PDF/UA-1-/veraPDF-Gate, Poppler-Gates, 4-MB-Limit, kooperativer 50-Sekunden-Timer und instanzlokale Ein-Render-Sperre bleiben bestehen. Weder Runtime noch Prüfpfad führen Netzwerkzugriffe aus oder veröffentlichen PDFs als CI-Artefakte.

  7. Der öffentliche Endpunkt GET /api/v1/report/{id}/pdf bleibt unverändert bei React-PDF und weiterhin nicht als PDF/UA getaggt. Slice C liest keine Datenbank und keine gespeicherten Reports, bewirbt keine neue Produktfunktion und ist keine Freigabe des PDF/UA-Produktpfads.

  8. Issue #333 bleibt offen. Noch nicht belegt sind die vollständige Abbildung aller real vorkommenden Reportsektionen, echte Karten-Alternativtexte und Umbrüche, vorhandene Mehrseiten-Viewergates für den neuen Renderer, ein kontrollierter Produktrollout, der PDF/UA-Live-Readback eines neu erzeugten Produktreports und die manuelle Screenreader-Abnahme.

Konsequenzen

  • Der Shadow prüft nun den echten Report-Vertrag und dessen Tierfelder, bleibt aber deterministisch, nicht personenbezogen und netzwerkfrei.
  • Der mapperseitige Datenminimierungsvertrag ist separat testbar: Dass die repository-fixierte Report-Fixture eine künstliche Adresse und providerförmige Felder besitzt, bedeutet nicht, dass diese in der PDF-View oder HTTP-Antwort erscheinen.
  • Ein grüner Slice-C-Lauf ist ein Integrationsbeleg für produktnahe Reportobjekte, nicht für gespeicherte oder reale Reports.
  • Die historische Slice-B-Evidenz bleibt unverändert an ihren damaligen Commit und PDF-UA-SLICE-B-1 gebunden. Der aktuelle Preview-Shadow trägt PDF-UA-SLICE-C-1.

Referenzen