Zwei Bugs:
1) Audio kam nicht durch — die Content-Security-Policy hatte kein
media-src und fiel auf default-src 'self' zurück. data:- (silent-WAV
zum Element-Unlock) und blob:-URLs (ElevenLabs-MP3-Cache) wurden
geblockt. Browser-Fehlermeldung im Console: „Loading media from
‚data:audio/wav;base64,…' violates the following Content Security
Policy directive". Fix: ``media-src 'self' data: blob:;`` ergänzt.
2) Tour war nur auf Startseite + Antrag-Detail eingebunden. User-Wunsch:
auf jeder Page außer Administration. Lösung: Tour-Engine-Include in
v2/base.html, mit ``{% if v2_active_nav not in [admin_*] %}``-Guard.
Pages ohne eigene ``window.GWOE_TOUR_STEPS`` bekommen einen Fallback
mit drei Stationen (Logo+Konzept, Topbar, Sidebar).
Topbar-Tour-Link sichtbar wenn ``window.gwoeTourStart`` existiert
(Engine geladen) — nicht mehr abhängig von Page-eigenen Steps.
Aufräumen: redundante Tour-Includes aus durchsuchen.html und
antrag_detail.html entfernt — die Engine kommt jetzt nur einmal aus
base.html.
Drei zusammenhängende UI-Bugs:
1) Audio kam nicht — Browser-Auto-Play-Block. ``new Audio(blobUrl).play()``
nach einem await zählt nicht mehr als User-Gesture; Safari/Chrome
kassieren mit NotAllowedError. Fix: persistentes <audio>-Element wird
einmal beim Tour-Start (im Click-Handler, synchron) mit einer
1×1-silent-WAV entsperrt. Folgende src-Updates spielen ohne Block.
2) Tour-Bubble „Weiter"-Button sah 90er aus — der lokale CSS-Override
``.gwoe-tour-bubble .v3-action-btn.primary`` hat den modernen
pill-shaped Style ausgehebelt. Override entfernt; nutzt jetzt das
globale ``.v3-action-btn.primary`` (teal-solid, runde Ecken,
weicher Drop-Shadow).
3) Tour erzählt anonymen User:innen über „Auswertungen" und
„Stimmverhalten", die in der linken Nav für Anonyme nicht sichtbar
waren. Aggregierte Daten sind öffentlich — Daten-Nav-Gruppe jetzt für
alle sichtbar (Auswertungen, Stimmverhalten, Aktuelle Themen,
Export-API, Atom-Feed). Persönliche Items (Merkliste, Abos, Neuer
Antrag, Batch) bleiben eingeloggt. Cluster + Landtag-Suche bleiben
eingeloggt/admin (Backend-Routen sind ohnehin require_auth).
Audio-Backend:
- ``app/tour_audio.py`` ruft ElevenLabs-TTS mit voice_id=Domi
(AZnzlk1XvdvUeBnXmlld) und model=eleven_multilingual_v2. ENV-konfiguriert
via ``ELEVENLABS_API_KEY``, ``ELEVENLABS_VOICE_ID``, ``ELEVENLABS_MODEL_ID``.
- Voice-Settings: stability 0.55, similarity_boost 0.7 (warm, klar, natürlich).
- Caching: SHA-256(text|voice|model) → ``data/tour_audio/<hash>.mp3``.
Folgeabrufe gehen aus dem Datei-Cache, kein API-Quota-Verbrauch.
Endpoint: ``GET /api/tour/voice?text=...`` rate-limited 30/min,
liefert audio/mpeg mit Cache-Control 30 Tage. Bei fehlendem
API-Key 503 — Frontend fällt dann auf ``speechSynthesis`` zurück
(Browser-eingebaute Stimme).
Frontend (tour.html):
- ``speak()`` versucht erst Server-Audio (ElevenLabs), bei 503/Fehler
Fallback auf Web Speech API.
- Session-Cache via Blob-URL: Vor/Zurück-Navigation in der Tour zieht
nicht jedes Mal eine neue Network-Roundtrip.
- ``stopSpeak()`` stoppt beide Audio-Pfade sauber.
Konfiguration für dev: ``ELEVENLABS_API_KEY`` und (optional)
``ELEVENLABS_VOICE_ID`` in ``/opt/gwoe-antragspruefer-dev/.env`` setzen,
dann Container restart.
Drei zusammenhängende UI-Bausteine:
1) Tour-Engine ist jetzt page-agnostisch — sie liest die Stationen aus
``window.GWOE_TOUR_STEPS`` (pro Page hinterlegt), nicht mehr aus einem
eingebauten Konstanten. Tour-Komponente wird per ``{% include %}``
eingehängt; das Page-Template definiert vorher seine eigenen Steps.
Antrag-Detail-Tour wurde entsprechend in das eigene Template gezogen.
2) Startseite (v2/screens/durchsuchen.html): „Du bist neu hier?"-Banner
oben mit zwei Buttons — „🧭 Tour starten" und „Nein, danke". Banner
bleibt sichtbar, bis explizit weggeklickt wird (localStorage-Flag),
oder die Tour gestartet wird. Fünf Stationen für die Startseite:
Marken-Block, Suche, Score-Filter + Sortierung, Antrags-Liste,
linke Navigation.
3) Logo-Klick führt jetzt zur Startseite — sowohl in v2/base.html als
auch in components/appshell.html. ``v2-brand`` und ``v2-brand-sub``
sind in einen ``<a href="/">`` mit Hover-Highlight gewickelt
(``.v2-brand-link``).
Phase 2 (ElevenLabs-Voice) ist der nächste Schritt — bisher läuft das
Audio über die Web Speech API.
Schaltfläche „🧭 Tour" in der userrow neben „Merken". Klick öffnet ein
Spotlight-Overlay mit vier Stationen, ermächtigend statt vereinfachend
formuliert:
1. Die Gemeinwohl-Note (was die Zahl 0–10 sagt, was die Empfehlung ist)
2. Die GWÖ-Matrix (5 Werte × 5 Berührungsgruppen, Farbcodierung)
3. Programm-Treue pro Fraktion (Score + Belege)
4. Stimmverhalten + Marker (Heuchelei ⚠ und Opportunismus !)
Audio: Web Speech API (Browser-eingebaute Stimme), de-DE, möglichst
weibliche Stimme. „Stimme an / aus"-Toggle in der Bubble. Bei
ESC oder Klick auf Overlay-Hintergrund: Tour-Ende, Audio stoppt.
Phase 2 (separate Iteration) wird das Audio-Backend gegen ElevenLabs
tauschen — Tour-Skript + UI bleiben gleich, nur ``speak()`` ruft dann
einen Server-Endpoint, der eine vorgenerierte und gecachte MP3 liefert.
Komponente in ``app/templates/v3/components/tour.html``, included am
Ende von antrag_detail.html. CSS inline in der Komponente (1 ``<style>``-
Block, keine ``style=""``-Attribute — Anti-Regression-Wache aus #184
respektiert).