gwoe-antragspruefer/docs/archive/README-2026-03-28.md
Dotty Dotter 45379a2639 #62 Phase 1+3: ADRs + Doku-Struktur in webapp/docs/
Architektur-Entscheidung aus Issue #62: Diátaxis-Framework für Doku-
Pflege ohne Drift. Pflege im Repo, ADRs immutable, Stale-Snapshots
explizit als Archiv markiert.

Phase 1 — Architecture Decision Records:

- docs/README.md — Diátaxis-Index, Erklärung was wo dokumentiert wird
- docs/adr/README.md — ADR-Workflow + Index
- docs/adr/template.md — Vorlage für neue ADRs
- docs/adr/0001-llm-citation-binding.md — Issue #60 Doppel-Fix-Story
  (A=ENUM-Anker, B=server-seitige Rekonstruktion, warum Option C verworfen)
- docs/adr/0002-adapter-architecture.md — ParlamentAdapter-Basisklasse
  + Registry, Klassen vs. Strategy vs. Modul-pro-Adapter
- docs/adr/0003-citation-property-tests.md — Sub-D Strategie, warum
  Property-Test gegen echte PDFs statt Schema-Tests oder Online-Verify
- docs/adr/0004-deployment-workflow.md — Docker-Compose + Volumes
  Standard-Workflow + SN-XML-Sonderpfad + Container-UTC-Gotcha

Phase 3 — Stale Doku archiviert:

- DOKUMENTATION.md (24.März, Skript-Architektur vor Webapp-Migrate)
  → docs/archive/DOKUMENTATION-2026-03-24.md
- STATUS-2026-03-28.md (Tagesstand-Snapshot)
  → docs/archive/STATUS-2026-03-28.md
- README.md (28.März, listet nur NRW-Adapter, vor 16 weiteren BLs)
  → docs/archive/README-2026-03-28.md
- docs/archive/README.md erklärt warum die Files da sind und warum
  niemand sie überschreiben oder ersetzen sollte

Plus neue Top-Level-README.md im Project-Root (außerhalb git, da
project-root kein Repo ist) als Folder-Index für den User.

CLAUDE.md ergänzt um Doku-Sektion mit Verweis auf docs/adr/.

Phase 2 (mkdocs Setup) folgt separat — braucht eine Docker-Image-
Erweiterung, die ich nicht autark einrollen will ohne Decision.

Tests: 194/194 grün (keine Code-Änderung).

Refs: #62
2026-04-10 01:38:03 +02:00

294 lines
10 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# GWÖ-Antragsprüfer — Projektdokumentation
**Stand:** 28.03.2026, 23:58 Uhr
**Telegram-Topic:** [🌱 GWÖ-Antragsprüfer](https://t.me/c/3823618505/4247) (thread_id 4247)
## 🎯 Projektziel
Automatische Bewertung von Parlamentsanträgen nach der **Gemeinwohl-Ökonomie (GWÖ) Matrix 2.0 für Gemeinden**. Das Tool analysiert Anträge aus Landesparlamenten und bewertet sie nach GWÖ-Kriterien, vergleicht mit Wahl- und Parteiprogrammen und schlägt konkrete Textverbesserungen vor.
---
## 🌐 Live-System
| Was | URL |
|-----|-----|
| **Webapp** | https://gwoe.toppyr.de |
| **Git-Repository** | https://repo.toppyr.de/tobias/gwoe-antragspruefer |
| **Server** | VServer 152.53.119.77 |
| **Container** | `/opt/gwoe-antragspruefer/` |
---
## 🏗️ Architektur
```
┌─────────────────────────────────────────────────────────────┐
│ Frontend │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────┐ │
│ │ Durchsuchen │ │ 🏷️ Tags │ │ Prüfen │ │
│ │ (Liste) │ │ (Wolke) │ │ (Upload/Analyse) │ │
│ └─────────────┘ └─────────────┘ └─────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ FastAPI Backend │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌─────────────┐ │
│ │ /api/ │ │ /api/ │ │ /api/ │ │ /api/ │ │
│ │assessments│ │search- │ │analyze- │ │assessment/ │ │
│ │ │ │landtag │ │drucksache│ │pdf │ │
│ └──────────┘ └──────────┘ └──────────┘ └─────────────┘ │
└─────────────────────────────────────────────────────────────┘
│ │ │
▼ ▼ ▼
┌─────────────┐ ┌─────────────┐ ┌─────────────────────────┐
│ SQLite │ │ OPAL API │ │ DashScope (Qwen) │
│ gwoe-antraege│ │ (Landtag │ │ qwen-plus-latest │
│ .db │ │ NRW) │ │ (LLM Analyse) │
└─────────────┘ └─────────────┘ └─────────────────────────┘
```
---
## 📁 Projektstruktur
```
webapp/
├── app/
│ ├── main.py # FastAPI-Endpoints + Security Middleware
│ ├── analyzer.py # LLM-Analyse mit v5-Prompt + Retry-Logik
│ ├── database.py # SQLite (aiosqlite) Persistenz
│ ├── models.py # Pydantic Assessment-Model
│ ├── parlamente.py # OPAL-Adapter für NRW Landtag
│ ├── report.py # PDF-Generierung (WeasyPrint)
│ ├── config.py # Settings + Environment
│ ├── embeddings.py # Wahlprogramm-Embeddings (optional)
│ ├── kontext/
│ │ ├── gwoe-matrix-2.0.md # GWÖ-Matrix Referenz
│ │ ├── wahlprogramme-nrw-2022.md # Zusammenfassungen
│ │ ├── parteiprogramme.md # Grundsatzprogramme
│ │ └── *-nrw-2022-paged.txt # Volltext (paginiert)
│ ├── templates/
│ │ ├── index.html # Haupt-UI (Jinja2)
│ │ └── quellen.html # Quellenübersicht
│ └── static/
│ └── referenzen/ # Original-PDFs der Programme
├── data/ # SQLite-DBs (Docker Volume)
│ └── gwoe-antraege.db # Haupt-Datenbank
├── reports/ # Generierte PDFs (Docker Volume)
├── docker-compose.yml # Traefik + Let's Encrypt
├── Dockerfile # Python 3.12 + WeasyPrint
├── requirements.txt
├── .env.example
├── .gitignore
├── .dockerignore
├── LICENSE (MIT)
└── README.md
```
---
## ✨ Features (Stand 28.03.2026)
### Analyse
- [x] GWÖ-Score (0-10) mit Matrix-Zuordnung
- [x] Bewertungssymbole (++/+/○//) pro Matrix-Feld
- [x] Wahlprogrammtreue (0-10) pro Fraktion
- [x] Parteiprogrammtreue (0-10) pro Fraktion
- [x] **Verbesserungsvorschläge im Redline-Format**
- Original-Zitat aus dem Antrag
- Konkreter Verbesserungsvorschlag
- GWÖ-Begründung
- [x] Themen-Tags für Kategorisierung
- [x] Retry-Logik (3 Versuche) bei JSON-Parse-Fehlern
### UI
- [x] Score-Filter (Alle / 8-10 / 5-7 / 0-4)
- [x] **Partei-Filter** (Dropdown)
- [x] **Durchschnittswerte pro Partei** (kompakte Stats-Bar)
- [x] **Tag-Wolke** mit Multi-Select (Schnittmenge)
- [x] Landtag-Suche via OPAL-API
- [x] "Jetzt prüfen"-Button für neue Anträge
- [x] Detail-Ansicht mit allen Bewertungen
- [x] PDF-Download pro Antrag
### Security
- [x] Content-Security-Policy
- [x] X-Frame-Options: DENY
- [x] X-Content-Type-Options: nosniff
- [x] X-XSS-Protection
- [x] Referrer-Policy
- [x] Permissions-Policy
- [x] /docs, /redoc, /openapi.json deaktiviert
### Infrastruktur
- [x] Docker Compose mit Traefik Reverse Proxy
- [x] Let's Encrypt SSL
- [x] **Persistente SQLite-DB** (Volume, überlebt Container-Neustarts)
- [x] Git-Repository auf repo.toppyr.de
---
## 🔧 Konfiguration
### Environment-Variablen (.env)
```bash
DASHSCOPE_API_KEY=sk-... # Alibaba DashScope API
KEYCLOAK_URL=https://sso.toppyr.de # Optional: SSO
KEYCLOAK_REALM=collaboration
KEYCLOAK_CLIENT_ID=gwoe-antragspruefer
```
### LLM-Modelle
| Modell | Verwendung | Kosten |
|--------|------------|--------|
| `qwen-plus-latest` | Standard (Free Tier) | Kostenlos |
| `qwen-plus` | Fallback (Paid) | ~$0.80/MTok |
| `qwen-max` | Premium | ~$2.40/MTok |
---
## 📊 API-Endpoints
| Methode | Pfad | Beschreibung |
|---------|------|--------------|
| GET | `/` | Web-UI |
| GET | `/health` | Health Check |
| GET | `/quellen` | Quellenübersicht |
| GET | `/api/assessments` | Alle Bewertungen (JSON) |
| GET | `/api/assessment?drucksache=18/12345` | Einzelne Bewertung |
| GET | `/api/search?q=Klima` | Interne DB-Suche |
| GET | `/api/search-landtag?q=Klima` | Landtag OPAL-Suche |
| POST | `/api/analyze-drucksache` | Neue Analyse starten |
| GET | `/api/assessment/pdf?drucksache=18/12345` | PDF-Download |
| GET | `/api/bundeslaender` | Verfügbare Bundesländer |
| GET | `/status/{job_id}` | Job-Status abfragen |
---
## 🧠 Prompt v5 — Kern-Features
Der Analyse-Prompt fordert:
1. **GWÖ-Treue (0-10)** mit Matrix-Zuordnung:
- Matrix-Feld (z.B. "D1 Menschenwürde")
- Symbol (++/+/○//)
- Kurzbegründung
2. **Programmtreue** für Antragsteller UND Regierungsfraktionen:
- Wahlprogramm-Score (0-10)
- Parteiprogramm-Score (0-10)
- Begründungen
3. **Verbesserungsvorschläge** (max. 3):
```json
{
"original": "Zitat aus dem Antrag",
"vorschlag": "Konkret **verbesserter** Text",
"begruendung": "Stärkt GWÖ-Wert X durch Y"
}
```
4. **Themen-Tags** für Kategorisierung
---
## 🚀 Deployment
### Erstinstallation
```bash
ssh vserver
cd /opt
git clone https://repo.toppyr.de/tobias/gwoe-antragspruefer.git
cd gwoe-antragspruefer
# .env erstellen
cp .env.example .env
nano .env # DASHSCOPE_API_KEY eintragen
# Starten
docker compose up -d
```
### Update
```bash
# Lokal
cd ~/Nextcloud/dotty/projekte/2026-03-23\ GWÖ-Antragsprüfer\ _WIP_/webapp
git add . && git commit -m "Update" && git push
# Auf Server
ssh vserver 'cd /opt/gwoe-antragspruefer && git pull && docker compose up -d --build'
```
### Manuelles Deploy (ohne Git auf Server)
```bash
cd ~/Nextcloud/dotty/projekte/2026-03-23\ GWÖ-Antragsprüfer\ _WIP_/webapp
tar czf /tmp/gwoe-webapp.tar.gz --exclude='venv' --exclude='__pycache__' --exclude='data' --exclude='reports' --exclude='.env' .
scp /tmp/gwoe-webapp.tar.gz vserver:/tmp/
ssh vserver 'cd /opt/gwoe-antragspruefer && tar xzf /tmp/gwoe-webapp.tar.gz && docker compose up -d --build'
```
---
## 📈 Statistiken (28.03.2026)
| Metrik | Wert |
|--------|------|
| Analysierte Anträge | 20 |
| Ø GWÖ-Score gesamt | 4.6 |
| Ø SPD | 7.7 |
| Ø GRÜNE | 6.0 |
| Ø CDU | 6.0 |
| Ø FDP | 4.8 |
| Ø AfD | 1.5 |
---
## 🐛 Bekannte Issues / TODOs
### Offen
- [ ] Keycloak SSO-Integration aktivieren
- [ ] Weitere Bundesländer (BY, BW) anbinden
- [ ] Batch-Analyse für viele Anträge
- [ ] Wahlprogramm-Zitate mit Seitenzahlen
- [ ] Export als CSV/Excel
### Gelöst (28.03.2026)
- [x] JSON-Parse-Fehler bei LLM-Output → Retry-Logik
- [x] DB nicht persistent → Dockerfile gefixt, data/ als Volume
- [x] Alte Assessments überschreiben neue → JSON-Import deaktiviert
- [x] Partei-Filter zeigt "Suchfehler" → JS-Bug gefixt
---
## 📝 Changelog
### v1.0.0 (28.03.2026)
- Initial Release
- GWÖ-Matrix 2.0 Analyse für NRW
- Verbesserungsvorschläge im Redline-Format
- Tag-Wolke mit Multi-Select
- Partei-Filter + Durchschnittswerte
- Security Headers
- Docker Deployment
---
## 📚 Quellen
- [GWÖ-Matrix 2.0 für Gemeinden (Arbeitsbuch)](https://econgood.org)
- [ECOnGOOD Corporate Design Manual 2024](https://econgood.org)
- [NRW OPAL Parlamentsdokumentation](https://www.landtag.nrw.de)
- Wahlprogramme NRW 2022 (CDU, GRÜNE, SPD, FDP, AfD)
- Grundsatzprogramme der Parteien
---
**Entwickelt von Tobias Rödel mit Unterstützung von Dotty** 👻