Empirisch gegen llm.mana.how (2026-05-27): mana-llm bedient ollama/* + google/*, KEIN gpt-4o-mini (→ 500 no_healthy_provider). google/gemini-2.5- flash ist verfügbar + vision-fähig. Default jetzt env-überschreibbar (MANA_LLM_MODEL / MANA_LLM_VISION_MODEL). Korrigiert zugleich die F1-Annahme in docs/SCREENSHOT_SUBMIT.md: der mana-auth-Service-Key war NIE der Vision-Blocker — llm.mana.how hat Auth aus (GPU_API_KEY leer). Key bleibt nur für den Crawl-Pfad relevant (research.mana.how → 401). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
9.2 KiB
Screenshot-Submit — „Tipp einreichen"
Stand: 2026-05-26. Phase σ-submit-0 (Foundation) in Arbeit.
Problem
Clubs, Bars und selbstverwaltete Häuser (Contrast, P-Club, Kula …) publizieren ihr Programm fast nur auf Instagram/Facebook-Stories — genau dort, wo der Aggregator-Crawler nicht hinkommt:
AGGREGATOR_POLICY.md §1verbietet Login-Bypass („Inhalte hinter Login werden nicht gecrawlt, Punkt") nicht-verhandelbar.- Meta-ToS verbietet automatisierten Zugriff mit eingeloggtem Account; Bann + Rechts-Exposure (DSGVO, §87b UrhG) wären die Folge.
Resultat: Von 63 curated Venues haben nur 7 Events. Alle Clubs/Bars — inkl. Contrast mit fester Dienstagsparty — sind leer. Der Crawl-Weg ist für diese Kategorie strukturell verschlossen.
Lösung
Der Mensch macht den Zugriff, die Maschine die Struktur. Eine Nutzer:in sieht einen Post in ihrem Feed, screenshottet ihn und teilt ihn an Seepuls. mana-llm-Vision extrahiert die Tatsachen (Titel, Datum, Ort), ein Mensch moderiert, dann wird der Event publiziert.
Das ist die Memoro-Logik (Input legitim vom Menschen, KI verarbeitet) — und kategorisch anders als ein Scraper: Seepuls berührt Instagram nie.
Nutzer:in sieht Post/Story ──screenshot──► Share-Sheet / Upload / Mail
│
POST /api/v1/submissions
{ image, post_url?, note? }
│
mana-llm Vision → { title, starts_at, venue_hint, … }
│ (best-effort; Bild = Input)
Venue-Matching (Fuzzy → 63 Venues)
│
event_submissions (status: pending)
│ Bild nach Entscheidung gepurged
Moderations-Queue (Admin)
│ bestätigen / korrigieren
events (live, „gemeldet · Quelle …")
Die drei nicht-verhandelbaren Regeln
Aus AGGREGATOR_POLICY.md abgeleitet. Test-pflichtig.
- Screenshot ist Input, nie Output. Wir extrahieren Tatsachen
(§5: „Tatsachen sind frei"). Das Bild, das Flyer-Artwork, der
1:1-Text werden nie re-publiziert. Der öffentliche Event zeigt
Titel + Datum + Ort + ≤200 Zeichen + Quell-Link. Der rohe Screenshot
wird nach der Moderations-Entscheidung gepurged (
imagePurgedAt). - Es ist ein Tipp, kein Claim. Wer screenshottet, ist meist nicht der Betreiber. Also: Moderations-Queue statt Direkt-Publish, Attribution „von Nutzer:in gemeldet · Quelle: instagram.com/…", nie „verifiziert vom Betreiber". Take-Down-Flow (§4b) bleibt voll.
- Quelle mit-erfassen. Submit fragt zusätzlich nach dem Post-Link (für §2-Attribution). Fehlt er, liest die Vision den @-Handle und wir verlinken aufs Profil.
DSGVO-Fußnote: Screenshots können Gesichter/Namen enthalten → schmale, zweckgebundene Verarbeitung (Fakten ziehen), Bild danach löschen, Take-Down bleibt. Kein Bild-Archiv.
Foundation-Gaps (was auf der Plattform noch nicht läuft)
| # | Gap | Ebene | Status |
|---|---|---|---|
| F1 | llm.mana.how hat Auth aus (GPU_API_KEY leer) → Vision braucht keinen Key. Der echte Blocker war das Modell: seepuls-Default gpt-4o-mini → 500 (mana-llm bedient ollama/*+google/*). Fix: Default auf google/gemini-2.5-flash (vision-fähig, env-überschreibbar). Hinweis: research.mana.how verlangt sehr wohl einen Key (401) — relevant nur für den Crawl-Pfad, nicht für Submit. |
Code | ✅ Modell-Fix; Key nur für Crawl offen |
| F2 | seepuls mana-llm-Client kann nur Text, kein Bild | Code | dieser Build |
| F3 | event_submissions-Tabelle existiert nicht |
Code | dieser Build |
| F4 | share_receive-Handler leer, accepts: [] |
Code | dieser Build (eigener /submissions-Endpoint) |
| F5 | Vision-Extraction-Service fehlt | Code | dieser Build |
| F6 | Venue-Matching fehlt | Code | dieser Build |
| F7 | Moderations-Route fehlt | Code | dieser Build |
| F8 | Transienter Bild-Speicher + Purge-Cron (mana-media) | Code/Ops | Phase 2 |
| F9 | Submit-UI (Web + PWA share_target + native Share-Extension) | Code | Phase 3 |
Graceful Degradation als Design-Prinzip: Die Vision (F1/F2/F5) ist eine Anreicherung, kein Hard-Block. Fehlt der Service-Key, landet die Submission trotzdem in der Queue — mit Notiz + Bild-Referenz, und die Moderator:in füllt die Felder manuell. So funktioniert Submit + Moderation ohne den Plattform-Onboarding-Schritt; die KI macht's nur bequemer.
Phasen
σ-submit-0 — Foundation (dieser Build, Branch feat/screenshot-submit)
event_submissions-Schema + Migration (F3)- mana-llm
extractStructuredFromImage()(F2) services/screenshot-extraction.ts— Vision→Fakten, graceful (F5)services/venue-match.ts— reine Fuzzy-Funktion, unit-getestet (F6)routes/public/submissions.ts— POST-Intake, public, IP-Hash (F4)routes/admin/submissions.ts— list / approve→event / reject (F7)- Mount in
index.ts, Manifestaccepts-Eintrag - Unit-Tests + type-check grün
σ-submit-1 — Live schalten (braucht Deploy)
- ✅ Modell-Fix (
google/gemini-2.5-flashstattgpt-4o-mini) — kein Service-Key nötig (mana-llm Auth aus). Deploy steht noch aus: Submit- Code lebt auffeat/screenshot-submit, prod fährt alten Code. - Live-Vision-Smoke gegen
llm.mana.how(nach Deploy) — incl.max_tokenshoch genug für Geminis Thinking +response_format-Verhalten verifizieren. - F8: transienter Bild-Speicher via mana-media + Purge-Cron (Bilder >7d pending → löschen)
- Rate-Limit (Token-Bucket pro IP-Hash, analog Take-Down-TODO)
σ-submit-2 — UI (F9)
- ✅ Web
/melden-Seite (Upload + Post-Link + Notiz), server-seitiger POST - ✅ PWA Web-Share-Target (
manifest.webmanifestshare_target →/melden) - ✅ Moderations-UI (Admin) —
/admin/moderation, Queue + Approve→Event / Reject. Client-seitig mit mana-auth-Bearer-Token (Admin-Routen sind JWT-gegated), noindex + robots-Disallow. Damit ist der Loop Submit→Moderation→Publish zu. - ⏳ seepuls-native Share-Extension (σ-Native) → POST
/submissions - ⏳ Service-Worker für zuverlässige PWA-Installation (Share-POST klappt nach Installation auch ohne)
Datenmodell
event_submissions — eine eingereichte Meldung, vor Moderation.
id sub_…
status pending | approved | rejected | spam
channel screenshot | share-target | federation | manual
note optionale Nutzer-Notiz
postUrl optionaler Link auf den Original-Post (§2-Attribution)
imageRef transiente Bild-Referenz (mana-media-Key o. lokal)
imagePurgedAt gesetzt, sobald Bild gelöscht
extracted jsonb { title, starts_at, ends_at, venue_hint, … }
extractionStatus pending | ok | failed | skipped
extractionError Fehlertext, falls Vision scheiterte
matchedVenueId → venues.id (Fuzzy-Treffer, von Mod bestätigt)
venueHint roher Name/@-Handle aus dem Post
resultEventId → events.id, gesetzt bei approve
reviewedByUserId Moderator:in
reviewedAt Zeitpunkt der Entscheidung
moderatorNote freier Vermerk
submitterUserId optional, wenn eingeloggt
clientIpHash Anti-Spam (sha256(IP), kein Roh-IP) — wie Take-Down
createdAt / updatedAt
Approve → erzeugt eine events-Row (Dedupe via external_id_hash,
source_url = postUrl, event_source_id = null = „gemeldet").
API
Public (kein Auth, IP-Hash + Rate-Limit)
POST /api/v1/submissions—{ image (base64/multipart), post_url?, note?, venue_hint? }→{ id, status: 'pending' }. Best-effort-Vision synchron oder als Job.
Admin (JWT, mana-auth)
GET /api/v1/admin/submissions?status=pendingPOST /api/v1/admin/submissions/:id/approve—{ venueId, title, starts_at, … (Korrekturen) }→ erzeugt EventPOST /api/v1/admin/submissions/:id/reject—{ reason }
Offene Punkte
- F1 ist der eine echte Plattform-Blocker für die KI-Stufe — eine einmalige Ops-Aktion (Service-Key bei mana-auth). Bis dahin läuft die Pipeline im Manuell-Modus (graceful degrade).
- Spam: Start anonym + Moderation + IP-Hash-Rate-Limit; Login (mana-auth) optional fürs „meine Meldungen"-Tracking. Local-First/Login-Optional-Linie.
- Bild-Speicher: MVP hält
imageRef; ob mana-media-Bucket oder kurzer lokaler Pfad entscheidet σ-submit-1. Nie öffentlich servieren. - Manifest-
accepts: vorerst seepuls-lokaler/submissions-Endpoint. Ob „Screenshot→Event" ein geteilter Typ im@mana/shared-share-protocolwird (andere Apps könnten ihn anbieten), ist eine mana-Repo-Architektur- Frage → vor σ-submit-2 mitmana-architectklären. - Venue-Matching-Schwelle: Fuzzy-Match liefert Kandidaten + Score; die finale Zuordnung trifft die Moderator:in, nie der Automat.