Report-Output: Permalink & PDF

Jeder über POST /api/v1/report erzeugte Report wird persistiert und ist teilbar — als Web-Permalink und als PDF (ADR-0022). Vierfach verfügbar (AI-Parität, ADR-0018): UI, API, MCP, Skill.

Permalink

POST /api/v1/report ergänzt im Ergebnis:

"meta": { "report_id": "…", "permalink": "/r/…" }
  • /r/{id} — öffentliche, gerenderte Ansicht (Marken-Layout, PDF-Button). noindex (kein Suchmaschinen-Index).
  • ID = CSPRNG ≥128 Bit base62 → nicht erratbar (IDOR-Schutz, ADR-0023).
  • Retention 90 Tage (expires_at) für anonyme Reports, danach 404 + Hard-Delete (täglicher Cron). Nur ip_hash gespeichert, kein Klar-IP.
  • Konto-gebundene Reports (eingeloggt erstellt oder per /r/{id}?claim=1 beansprucht, Migration 0021): expires_at = NULLlaufen nicht ab, abrufbar unter „Meine Reports" (/account/reports). Zusätzlich user_id gespeichert; meta.saved=true signalisiert den Zustand an UI/API.
  • Fail-open: scheitert die Persistenz, kommt der Report ohne report_id (Kernfunktion unberührt).

Endpunkte

MethodePfadErgebnis
POST/api/v1/reportReport persistiert + meta.permalink
GET/api/v1/report/{id}gespeichertes REPORT-SPEC-JSON (404 wenn unbekannt/abgelaufen)
GET/api/v1/report/{id}/pdfPDF (application/pdf), eigenes Tageslimit
GET/r/{id}gerenderte Web-Ansicht + PDF-Download

GET /api/v1/report?address=… (Query) bleibt flüchtig (idempotent, schreibt nicht).

PDF

Server-seitig via @react-pdf/renderer (reines JS, kein Headless-Chromium) — robust/kalt-startarm auf Vercel. Bewusst nüchternes Layout; Zahlen 1:1 aus dem gespeicherten Report. Rate-limitiert (eigener pdf:-Bucket).

Zugänge (Parität)

  • UI: /report → nach Erzeugung „Permalink" + „PDF herunterladen".
  • API: siehe Tabelle, OpenAPI unter /docs/api.
  • MCP: Tool export_report{ permalink, pdf_url }.
  • Skill: report.mjs gibt am Ende Permalink + PDF-URL aus.

Grenzen

„Wer den Link hat, sieht den Report" (Teilen-Use-Case) — Schutz = unerratbare ID + noindex + 90-Tage-Retention. Privatere Modi (Auth/Ablauf-Token) sind als Folge möglich.