Erklaert die acht groessten Veraenderungen seit 1.0 — Buerger:innen-Modus,
Tour mit Sprachausgabe, Stimmverhalten, Aktuelle-Themen-Dashboard, Programme
mit zeitpunkt-genauer Bewertung, Scorecards, Auswertungen und Quellen-Suche
— jeweils mit kurzer Intention und Umsetzungsbeschreibung.
Topbar-Link rechts oben (vor Methodik), Endpoint /was-ist-neu, Template
unter v2/screens/was-ist-neu.html. Eigene neu-* CSS-Klassen analog zu
methodik.html, daher kein neuer Inline-Style-Eintrag.
Im JS-Kommentar des Topbar-Toggle-Skripts stand wörtlich
{% include "v3/components/tour.html" %} — Jinja parst das auch
innerhalb von /* ... */-Kommentaren und renderte das include ein
zweites Mal. Folge: 4 window.gwoeTourStart-Definitionen, doppeltes
Tour-Overlay-DOM, doppeltes <audio>-Element. Fix: Kommentar
umformuliert ohne Jinja-Tag.
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.
Letzter Commit hatte die Daten-Nav für alle sichtbar gemacht, damit der
Tour-Text passte. User-Korrektur: nicht die Berechtigungen erweitern,
sondern den Tour-Text auf das anpassen, was anonyme tatsächlich sehen.
Nav zurück auf den ursprünglichen Stand (Daten-Sektion eingeloggt-only).
Tour-Station „Navigation links" jetzt zwei Varianten via {% if
is_authenticated %} im durchsuchen.html-Template:
- Anonym: erklärt Tags + Quellen (Topbar) und weist auf Login-Mehrwert
hin (Auswertungen / Stimmverhalten / Merkliste sind dann da).
- Eingeloggt: erklärt Auswertungen + Stimmverhalten + Quellen.
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).
DOMContentLoaded-Race: bei manchen Page-Loads war das Event schon
gefeuert, wenn das addEventListener-Script lief — der Listener wurde
nie aufgerufen, der Topbar-Tour-Link blieb hidden. Auf der Startseite
führte das dazu, dass nach Welcome-Banner-Dismiss kein Tour-Einstieg
mehr da war.
Fix: synchroner IIFE-Check, der Skript-Block steht ohnehin nach dem
body_scripts (STEPS sind dort schon gesetzt).
User-Feedback: Tour-Start muss auch nach dem ersten Mal möglich sein,
und die Buttons sahen "sehr 90er" aus.
Permanenter Tour-Zugang:
- Topbar-Link "🧭 Tour" neben Methodik/Quellen, sichtbar auf jeder
Page mit ``window.GWOE_TOUR_STEPS`` (Antrag-Detail + Startseite).
- Per JS in base.html nach DOMContentLoaded sichtbar geschaltet.
- Style: dezente teal-Pille, kein dominanter Button.
Button-Modernisierung:
- ``.v2-chip`` und ``.v3-action-btn`` jetzt pill-shaped (border-radius
999px statt 3px), mit transition + box-shadow on hover und subtle
transform on active. Focus-visible mit klarem outline.
- Primary-Variante: teal-solid mit weichem Drop-Shadow, nicht das alte
dark-Mode-Schwarz.
- Welcome-Banner (Startseite): scharfes ``v2-kasten outline-blue`` weg,
stattdessen weicher gradient-Hintergrund teal→blue mit border 22%
teal-Hauch und subtle box-shadow. Skip-Button als Text-Link
("Später") statt vollwertiger Chip — visuell klar nachgeordnet.
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.
Drei Korrekturen:
1. Mobile-Topbar: Auth-Widget + Bundesland-Selector + Theme-Toggle
pushten die rechte Kante über 390 px Phone-Viewport. Fix: Topbar
darf in @media (max-width: 900px) flex-wrappen, height auto,
row-gap fuer mehrzeilig.
2. Topbar-Link "Klassische Ansicht" → /classic entfernt (verlinkt auf
das alte v1-Frontend; v2 bzw. das neue v3 sind die aktiven Modi).
3. /tags-Seite hatte zwei Bugs:
- Titel wurde aus a.titel (existiert nicht) statt a.title gelesen
→ User sah nur Drucksachen-Nummern und dachte "kaum Daten".
- Kein Visual-Feedback welche Tag-Kombinationen leer wären.
Beide gefixt: title-Field korrekt, plus Tag-Greying via class
.tag-pill.disabled fuer Tags die zu 0 Treffern fuehren wuerden.
Ausserdem Score-Field gwoeScore-Fallback und HTML-Escape fuer alle
Strings (vorher XSS-anfaellig bei Title/Fraktion).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Der Stimmverhalten-Nav-Eintrag (#169) referenzierte ein
phosphor/scales.svg-Icon, das nicht im Repo liegt. Folge: Jinja-
TemplateNotFound bei jedem Render von base.html nach Auth → 500
auf jeder authenticated Page.
Fix: circle-half (existierendes Icon, semantisch passend fuer
Pro/Contra-Balance).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Neue Route /stimmverhalten rendert dieselbe auswertungen.html, aber
mit default_tab='stimmverhalten' und v2_active_nav='stimmverhalten'.
Linker Nav-Eintrag 'Stimmverhalten' (Icon scales) zwischen
Auswertungen und Aktuelle Themen.
Beim Page-Load aktiviert das DOMContentLoaded-Handler den im Context
gesetzten Tab — fuer /auswertungen ist es 'bl-partei' (Default), fuer
/stimmverhalten direkt 'stimmverhalten'. Kein Code-Duplikat im
Tab-Inhalt.
Refs: #169
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sechs zusammengehoerige UX/Performance-Erweiterungen:
**1. /v2/admin/stand — System-Stand-Dashboard**
KPI-Kacheln (Bewertungen, Plenum-Votes, Match, Vote-Orphans, News, PM-
Drafts, Bookmarks) + GWÖ-Score-Histogram + Per-BL-Tabelle + News-Source-
Tabelle. Auto-Refresh 30 s. Endpoint /api/admin/stand liefert alles in
einem Roundtrip. Nav-Eintrag "Stand" in der Admin-Sektion.
**2. /auswertungen Score-Histogram-Tab**
4. Tab "Score-Verteilung" mit Bar-Chart 0–10. Endpoint
/api/auswertungen/score-histogram liefert Buckets, optional gefiltert
nach Bundesland + Wahlperiode. Reagiert auf den globalen BL-Filter.
**3. PM-Body Markdown-Rendering**
Mini-Renderer im Modal: **bold** / __bold__ / *italic* / _italic_ /
- list-bullets / Doppel-Newline-Paragraphen. Kein externer Markdown-
Parser, keine neue Dependency. Body wird HTML-escaped, Patterns dann
zu Tags umgesetzt.
**4. Performance-Cache fuer themen_matching**
TTL-Cache (60 s) fuer aggregate_top_themen und aggregate_news_cluster.
Cache-Key inkl. aller Filter-Parameter. Automatische Invalidation in
news_aggregator.run_aggregator nach erfolgreichem Insert/Embed.
4 neue Tests fuer cache_get/set/clear-Verhalten.
**5. Stimmverhalten Banner Live-Update**
Statt setTimeout(800) jetzt pollQueueUntilDrained: alle 4 s
GET /api/queue/status, Banner zeigt pending + elapsed live. Bei
pending=0 zwei Polls in Folge: Banner + Stimmverhalten-Charts neu
laden. Max 5 Min Polling-Timeout. Bricht ab wenn Tab gewechselt wird.
**6. Antrag-Detail Cluster-Indicator**
News-Match-Box im Antrag-Detail laedt parallel /aktuelle-themen/cluster
und mappt URL → Cluster. Pro News-Card ein "🔗 Cluster (N News)"-Badge
mit Hover-Tooltip der anderen Cluster-Members. Macht thematische
Bündel sichtbar, ohne Pop-Out auf den Cluster-Tab.
Suite: 1088 → 1092 grün (4 Cache-Tests).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Topbar zeigt jetzt:
- Username (wie bisher)
- "ADMIN"-Badge (teal) wenn user.roles enthaelt 'admin' oder 'gwoe-admin'
- Tooltip mit allen Rollen beim Hover
Macht sichtbar, ob man Admin-Rechte hat — wichtig fuer Sichtbarkeit
von /v2/batch und /v2/admin/* Eintraegen.
Plus: Rolle gwoe-admin in Keycloak (Realm collaboration) angelegt
+ User tobias zugewiesen. Auth-Code prueft realm_access.roles auf
'admin' ODER 'gwoe-admin'.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Browser-Cache zeigte alte v2.css ohne v2-menu-toggle-display:none-Regel.
Mit ?v=1.0.0 wird auf Versionsspruenge sauber neu geladen.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Backend (Filter sind seit jeher da):
- /api/feed.xml?bundesland=&partei=&limit=
- /api/subscriptions GET/POST/DELETE
UI:
- /v2/feed: Form mit BL/Partei/Limit, generiert Feed-URL live, Buttons Oeffnen/
URL-Kopieren/In-Feedly. Default-BL aus Header-Selektor uebernommen
- /v2/abos: Liste eigener Abos + Form zum Anlegen/Loeschen, BL-Dropdown,
Partei-Freitext, Frequenz daily/weekly
- Sidebar 'Daten'-Gruppe um beide Eintraege erweitert (statt Direkt-Link auf
/api/feed.xml)
- Beide Routen mit Depends(require_auth) — Anonyme bekommen 401-Redirect
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Vorher: '— Pruefen' + '— Daten'-Labels waren sichtbar, aber alle Eintraege darin
hidden — nur ein verlorener Header. Jetzt: ganzer Gruppen-Container hinter
{% if is_authenticated %} → Anonymous-User sieht nur 'Lesen'-Gruppe.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Bundesland-Auswahl:
- Topbar: einziger BL-Selektor mit localStorage.gwoe.bl-Persistenz
- BL-Felder entfernt aus durchsuchen.html, landtag_suche.html, neu.html, auswertungen.html
- Screens hoeren auf v2-bl-changed CustomEvent + initial via window.v2GetGlobalBl()
Sichtbarkeit (Sidebar):
- Durchsuchen + Tags: immer
- Merkliste / Neuer Antrag / Landtag-Suche / Auswertungen / Export / Feed: nur eingeloggt
- Cluster + Batch-Analyse + Administration: nur Admin
Server-Side Schutz:
- _v2_template_context()-Helper liefert is_authenticated, is_admin, v2_bundeslaender
- HTML-Routen mit Depends(require_auth) bzw. require_admin
- 401/403-Browser-Requests redirecten auf /?login=1 statt JSON-Error
Queue-Widget (#149):
- Neues Component-Partial v2/components/queue_widget.html
- Statusbar unten links + Hover-Tooltip mit den letzten 20 Jobs
- 5s-Polling auf /api/queue/status, blendet sich aus wenn keine Jobs
Smoke-Test angepasst an neue Auth-Erwartungen (302 fuer auth-protected Routen).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>