gwoe-antragspruefer/site/archive/README-2026-03-28/index.html

1323 lines
38 KiB
HTML
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.

<!doctype html>
<html lang="de" class="no-js">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<link rel="canonical" href="https://docs.gwoe.toppyr.de/archive/README-2026-03-28/">
<link rel="icon" href="../../assets/images/favicon.png">
<meta name="generator" content="mkdocs-1.6.1, mkdocs-material-9.7.6">
<title>GWÖ-Antragsprüfer — Projektdokumentation - GWÖ-Antragsprüfer Docs</title>
<link rel="stylesheet" href="../../assets/stylesheets/main.484c7ddc.min.css">
<link rel="stylesheet" href="../../assets/stylesheets/palette.ab4e12ef.min.css">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,300i,400,400i,700,700i%7CRoboto+Mono:400,400i,700,700i&display=fallback">
<style>:root{--md-text-font:"Roboto";--md-code-font:"Roboto Mono"}</style>
<script>__md_scope=new URL("../..",location),__md_hash=e=>[...e].reduce(((e,_)=>(e<<5)-e+_.charCodeAt(0)),0),__md_get=(e,_=localStorage,t=__md_scope)=>JSON.parse(_.getItem(t.pathname+"."+e)),__md_set=(e,_,t=localStorage,a=__md_scope)=>{try{t.setItem(a.pathname+"."+e,JSON.stringify(_))}catch(e){}}</script>
</head>
<body dir="ltr" data-md-color-scheme="default" data-md-color-primary="teal" data-md-color-accent="light-green">
<input class="md-toggle" data-md-toggle="drawer" type="checkbox" id="__drawer" autocomplete="off">
<input class="md-toggle" data-md-toggle="search" type="checkbox" id="__search" autocomplete="off">
<label class="md-overlay" for="__drawer"></label>
<div data-md-component="skip">
<a href="#gwo-antragsprufer-projektdokumentation" class="md-skip">
Zum Inhalt
</a>
</div>
<div data-md-component="announce">
</div>
<header class="md-header md-header--shadow" data-md-component="header">
<nav class="md-header__inner md-grid" aria-label="Kopfzeile">
<a href="../.." title="GWÖ-Antragsprüfer Docs" class="md-header__button md-logo" aria-label="GWÖ-Antragsprüfer Docs" data-md-component="logo">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 8a3 3 0 0 0 3-3 3 3 0 0 0-3-3 3 3 0 0 0-3 3 3 3 0 0 0 3 3m0 3.54C9.64 9.35 6.5 8 3 8v11c3.5 0 6.64 1.35 9 3.54 2.36-2.19 5.5-3.54 9-3.54V8c-3.5 0-6.64 1.35-9 3.54"/></svg>
</a>
<label class="md-header__button md-icon" for="__drawer">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M3 6h18v2H3zm0 5h18v2H3zm0 5h18v2H3z"/></svg>
</label>
<div class="md-header__title" data-md-component="header-title">
<div class="md-header__ellipsis">
<div class="md-header__topic">
<span class="md-ellipsis">
GWÖ-Antragsprüfer Docs
</span>
</div>
<div class="md-header__topic" data-md-component="header-topic">
<span class="md-ellipsis">
GWÖ-Antragsprüfer — Projektdokumentation
</span>
</div>
</div>
</div>
<label class="md-header__button md-icon" for="__search">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.52 6.52 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5"/></svg>
</label>
<div class="md-search" data-md-component="search" role="dialog">
<label class="md-search__overlay" for="__search"></label>
<div class="md-search__inner" role="search">
<form class="md-search__form" name="search">
<input type="text" class="md-search__input" name="query" aria-label="Suche" placeholder="Suche" autocapitalize="off" autocorrect="off" autocomplete="off" spellcheck="false" data-md-component="search-query" required>
<label class="md-search__icon md-icon" for="__search">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.52 6.52 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M20 11v2H8l5.5 5.5-1.42 1.42L4.16 12l7.92-7.92L13.5 5.5 8 11z"/></svg>
</label>
<nav class="md-search__options" aria-label="Suche">
<button type="reset" class="md-search__icon md-icon" title="Zurücksetzen" aria-label="Zurücksetzen" tabindex="-1">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/></svg>
</button>
</nav>
</form>
<div class="md-search__output">
<div class="md-search__scrollwrap" tabindex="0" data-md-scrollfix>
<div class="md-search-result" data-md-component="search-result">
<div class="md-search-result__meta">
Suche wird initialisiert
</div>
<ol class="md-search-result__list" role="presentation"></ol>
</div>
</div>
</div>
</div>
</div>
<div class="md-header__source">
<a href="https://repo.toppyr.de/tobias/gwoe-antragspruefer" title="Zum Repository" class="md-source" data-md-component="source">
<div class="md-source__icon md-icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Free 7.1.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2025 Fonticons, Inc.--><path d="M439.6 236.1 244 40.5c-5.4-5.5-12.8-8.5-20.4-8.5s-15 3-20.4 8.4L162.5 81l51.5 51.5c27.1-9.1 52.7 16.8 43.4 43.7l49.7 49.7c34.2-11.8 61.2 31 35.5 56.7-26.5 26.5-70.2-2.9-56-37.3L240.3 199v121.9c25.3 12.5 22.3 41.8 9.1 55-6.4 6.4-15.2 10.1-24.3 10.1s-17.8-3.6-24.3-10.1c-17.6-17.6-11.1-46.9 11.2-56v-123c-20.8-8.5-24.6-30.7-18.6-45L142.6 101 8.5 235.1C3 240.6 0 247.9 0 255.5s3 15 8.5 20.4l195.6 195.7c5.4 5.4 12.7 8.4 20.4 8.4s15-3 20.4-8.4l194.7-194.7c5.4-5.4 8.4-12.8 8.4-20.4s-3-15-8.4-20.4"/></svg>
</div>
<div class="md-source__repository">
tobias/gwoe-antragspruefer
</div>
</a>
</div>
</nav>
</header>
<div class="md-container" data-md-component="container">
<main class="md-main" data-md-component="main">
<div class="md-main__inner md-grid">
<div class="md-sidebar md-sidebar--primary" data-md-component="sidebar" data-md-type="navigation" >
<div class="md-sidebar__scrollwrap">
<div class="md-sidebar__inner">
<nav class="md-nav md-nav--primary" aria-label="Navigation" data-md-level="0">
<label class="md-nav__title" for="__drawer">
<a href="../.." title="GWÖ-Antragsprüfer Docs" class="md-nav__button md-logo" aria-label="GWÖ-Antragsprüfer Docs" data-md-component="logo">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 8a3 3 0 0 0 3-3 3 3 0 0 0-3-3 3 3 0 0 0-3 3 3 3 0 0 0 3 3m0 3.54C9.64 9.35 6.5 8 3 8v11c3.5 0 6.64 1.35 9 3.54 2.36-2.19 5.5-3.54 9-3.54V8c-3.5 0-6.64 1.35-9 3.54"/></svg>
</a>
GWÖ-Antragsprüfer Docs
</label>
<div class="md-nav__source">
<a href="https://repo.toppyr.de/tobias/gwoe-antragspruefer" title="Zum Repository" class="md-source" data-md-component="source">
<div class="md-source__icon md-icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Free 7.1.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2025 Fonticons, Inc.--><path d="M439.6 236.1 244 40.5c-5.4-5.5-12.8-8.5-20.4-8.5s-15 3-20.4 8.4L162.5 81l51.5 51.5c27.1-9.1 52.7 16.8 43.4 43.7l49.7 49.7c34.2-11.8 61.2 31 35.5 56.7-26.5 26.5-70.2-2.9-56-37.3L240.3 199v121.9c25.3 12.5 22.3 41.8 9.1 55-6.4 6.4-15.2 10.1-24.3 10.1s-17.8-3.6-24.3-10.1c-17.6-17.6-11.1-46.9 11.2-56v-123c-20.8-8.5-24.6-30.7-18.6-45L142.6 101 8.5 235.1C3 240.6 0 247.9 0 255.5s3 15 8.5 20.4l195.6 195.7c5.4 5.4 12.7 8.4 20.4 8.4s15-3 20.4-8.4l194.7-194.7c5.4-5.4 8.4-12.8 8.4-20.4s-3-15-8.4-20.4"/></svg>
</div>
<div class="md-source__repository">
tobias/gwoe-antragspruefer
</div>
</a>
</div>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../.." class="md-nav__link">
<span class="md-ellipsis">
Start
</span>
</a>
</li>
<li class="md-nav__item md-nav__item--section md-nav__item--nested">
<input class="md-nav__toggle md-toggle md-toggle--indeterminate" type="checkbox" id="__nav_2" >
<label class="md-nav__link" for="__nav_2" id="__nav_2_label" tabindex="">
<span class="md-ellipsis">
Architecture Decision Records
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="1" aria-labelledby="__nav_2_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_2">
<span class="md-nav__icon md-icon"></span>
Architecture Decision Records
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../adr/" class="md-nav__link">
<span class="md-ellipsis">
Übersicht
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../adr/0001-llm-citation-binding/" class="md-nav__link">
<span class="md-ellipsis">
0001 LLM-Citation-Binding
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../adr/0002-adapter-architecture/" class="md-nav__link">
<span class="md-ellipsis">
0002 Adapter-Architektur
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../adr/0003-citation-property-tests/" class="md-nav__link">
<span class="md-ellipsis">
0003 Citation-Property-Tests
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../adr/0004-deployment-workflow/" class="md-nav__link">
<span class="md-ellipsis">
0004 Deployment-Workflow
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--section md-nav__item--nested">
<input class="md-nav__toggle md-toggle md-toggle--indeterminate" type="checkbox" id="__nav_3" >
<label class="md-nav__link" for="__nav_3" id="__nav_3_label" tabindex="">
<span class="md-ellipsis">
Archiv
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="1" aria-labelledby="__nav_3_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_3">
<span class="md-nav__icon md-icon"></span>
Archiv
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../" class="md-nav__link">
<span class="md-ellipsis">
Übersicht
</span>
</a>
</li>
</ul>
</nav>
</li>
</ul>
</nav>
</div>
</div>
</div>
<div class="md-sidebar md-sidebar--secondary" data-md-component="sidebar" data-md-type="toc" >
<div class="md-sidebar__scrollwrap">
<div class="md-sidebar__inner">
<nav class="md-nav md-nav--secondary" aria-label="Inhaltsverzeichnis">
<label class="md-nav__title" for="__toc">
<span class="md-nav__icon md-icon"></span>
Inhaltsverzeichnis
</label>
<ul class="md-nav__list" data-md-component="toc" data-md-scrollfix>
<li class="md-nav__item">
<a href="#projektziel" class="md-nav__link">
<span class="md-ellipsis">
🎯 Projektziel
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#live-system" class="md-nav__link">
<span class="md-ellipsis">
🌐 Live-System
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#architektur" class="md-nav__link">
<span class="md-ellipsis">
🏗️ Architektur
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#projektstruktur" class="md-nav__link">
<span class="md-ellipsis">
📁 Projektstruktur
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#features-stand-28032026" class="md-nav__link">
<span class="md-ellipsis">
✨ Features (Stand 28.03.2026)
</span>
</a>
<nav class="md-nav" aria-label="✨ Features (Stand 28.03.2026)">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#analyse" class="md-nav__link">
<span class="md-ellipsis">
Analyse
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#ui" class="md-nav__link">
<span class="md-ellipsis">
UI
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#security" class="md-nav__link">
<span class="md-ellipsis">
Security
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#infrastruktur" class="md-nav__link">
<span class="md-ellipsis">
Infrastruktur
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#konfiguration" class="md-nav__link">
<span class="md-ellipsis">
🔧 Konfiguration
</span>
</a>
<nav class="md-nav" aria-label="🔧 Konfiguration">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#environment-variablen-env" class="md-nav__link">
<span class="md-ellipsis">
Environment-Variablen (.env)
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#llm-modelle" class="md-nav__link">
<span class="md-ellipsis">
LLM-Modelle
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#api-endpoints" class="md-nav__link">
<span class="md-ellipsis">
📊 API-Endpoints
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#prompt-v5-kern-features" class="md-nav__link">
<span class="md-ellipsis">
🧠 Prompt v5 — Kern-Features
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#deployment" class="md-nav__link">
<span class="md-ellipsis">
🚀 Deployment
</span>
</a>
<nav class="md-nav" aria-label="🚀 Deployment">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#erstinstallation" class="md-nav__link">
<span class="md-ellipsis">
Erstinstallation
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#update" class="md-nav__link">
<span class="md-ellipsis">
Update
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#manuelles-deploy-ohne-git-auf-server" class="md-nav__link">
<span class="md-ellipsis">
Manuelles Deploy (ohne Git auf Server)
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#statistiken-28032026" class="md-nav__link">
<span class="md-ellipsis">
📈 Statistiken (28.03.2026)
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#bekannte-issues-todos" class="md-nav__link">
<span class="md-ellipsis">
🐛 Bekannte Issues / TODOs
</span>
</a>
<nav class="md-nav" aria-label="🐛 Bekannte Issues / TODOs">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#offen" class="md-nav__link">
<span class="md-ellipsis">
Offen
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#gelost-28032026" class="md-nav__link">
<span class="md-ellipsis">
Gelöst (28.03.2026)
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#changelog" class="md-nav__link">
<span class="md-ellipsis">
📝 Changelog
</span>
</a>
<nav class="md-nav" aria-label="📝 Changelog">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#v100-28032026" class="md-nav__link">
<span class="md-ellipsis">
v1.0.0 (28.03.2026)
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#quellen" class="md-nav__link">
<span class="md-ellipsis">
📚 Quellen
</span>
</a>
</li>
</ul>
</nav>
</div>
</div>
</div>
<div class="md-content" data-md-component="content">
<article class="md-content__inner md-typeset">
<h1 id="gwo-antragsprufer-projektdokumentation">GWÖ-Antragsprüfer — Projektdokumentation<a class="headerlink" href="#gwo-antragsprufer-projektdokumentation" title="Permanent link">&para;</a></h1>
<p><strong>Stand:</strong> 28.03.2026, 23:58 Uhr
<strong>Telegram-Topic:</strong> <a href="https://t.me/c/3823618505/4247">🌱 GWÖ-Antragsprüfer</a> (thread_id 4247)</p>
<h2 id="projektziel">🎯 Projektziel<a class="headerlink" href="#projektziel" title="Permanent link">&para;</a></h2>
<p>Automatische Bewertung von Parlamentsanträgen nach der <strong>Gemeinwohl-Ökonomie (GWÖ) Matrix 2.0 für Gemeinden</strong>. Das Tool analysiert Anträge aus Landesparlamenten und bewertet sie nach GWÖ-Kriterien, vergleicht mit Wahl- und Parteiprogrammen und schlägt konkrete Textverbesserungen vor.</p>
<hr />
<h2 id="live-system">🌐 Live-System<a class="headerlink" href="#live-system" title="Permanent link">&para;</a></h2>
<table>
<thead>
<tr>
<th>Was</th>
<th>URL</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Webapp</strong></td>
<td>https://gwoe.toppyr.de</td>
</tr>
<tr>
<td><strong>Git-Repository</strong></td>
<td>https://repo.toppyr.de/tobias/gwoe-antragspruefer</td>
</tr>
<tr>
<td><strong>Server</strong></td>
<td>VServer 152.53.119.77</td>
</tr>
<tr>
<td><strong>Container</strong></td>
<td><code>/opt/gwoe-antragspruefer/</code></td>
</tr>
</tbody>
</table>
<hr />
<h2 id="architektur">🏗️ Architektur<a class="headerlink" href="#architektur" title="Permanent link">&para;</a></h2>
<div class="highlight"><pre><span></span><code>┌─────────────────────────────────────────────────────────────┐
│ 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) │
└─────────────┘ └─────────────┘ └─────────────────────────┘
</code></pre></div>
<hr />
<h2 id="projektstruktur">📁 Projektstruktur<a class="headerlink" href="#projektstruktur" title="Permanent link">&para;</a></h2>
<div class="highlight"><pre><span></span><code>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&#39;s Encrypt
├── Dockerfile # Python 3.12 + WeasyPrint
├── requirements.txt
├── .env.example
├── .gitignore
├── .dockerignore
├── LICENSE (MIT)
└── README.md
</code></pre></div>
<hr />
<h2 id="features-stand-28032026">✨ Features (Stand 28.03.2026)<a class="headerlink" href="#features-stand-28032026" title="Permanent link">&para;</a></h2>
<h3 id="analyse">Analyse<a class="headerlink" href="#analyse" title="Permanent link">&para;</a></h3>
<ul>
<li>[x] GWÖ-Score (0-10) mit Matrix-Zuordnung</li>
<li>[x] Bewertungssymbole (++/+/○//) pro Matrix-Feld</li>
<li>[x] Wahlprogrammtreue (0-10) pro Fraktion</li>
<li>[x] Parteiprogrammtreue (0-10) pro Fraktion</li>
<li>[x] <strong>Verbesserungsvorschläge im Redline-Format</strong></li>
<li>Original-Zitat aus dem Antrag</li>
<li>Konkreter Verbesserungsvorschlag</li>
<li>GWÖ-Begründung</li>
<li>[x] Themen-Tags für Kategorisierung</li>
<li>[x] Retry-Logik (3 Versuche) bei JSON-Parse-Fehlern</li>
</ul>
<h3 id="ui">UI<a class="headerlink" href="#ui" title="Permanent link">&para;</a></h3>
<ul>
<li>[x] Score-Filter (Alle / 8-10 / 5-7 / 0-4)</li>
<li>[x] <strong>Partei-Filter</strong> (Dropdown)</li>
<li>[x] <strong>Durchschnittswerte pro Partei</strong> (kompakte Stats-Bar)</li>
<li>[x] <strong>Tag-Wolke</strong> mit Multi-Select (Schnittmenge)</li>
<li>[x] Landtag-Suche via OPAL-API</li>
<li>[x] "Jetzt prüfen"-Button für neue Anträge</li>
<li>[x] Detail-Ansicht mit allen Bewertungen</li>
<li>[x] PDF-Download pro Antrag</li>
</ul>
<h3 id="security">Security<a class="headerlink" href="#security" title="Permanent link">&para;</a></h3>
<ul>
<li>[x] Content-Security-Policy</li>
<li>[x] X-Frame-Options: DENY</li>
<li>[x] X-Content-Type-Options: nosniff</li>
<li>[x] X-XSS-Protection</li>
<li>[x] Referrer-Policy</li>
<li>[x] Permissions-Policy</li>
<li>[x] /docs, /redoc, /openapi.json deaktiviert</li>
</ul>
<h3 id="infrastruktur">Infrastruktur<a class="headerlink" href="#infrastruktur" title="Permanent link">&para;</a></h3>
<ul>
<li>[x] Docker Compose mit Traefik Reverse Proxy</li>
<li>[x] Let's Encrypt SSL</li>
<li>[x] <strong>Persistente SQLite-DB</strong> (Volume, überlebt Container-Neustarts)</li>
<li>[x] Git-Repository auf repo.toppyr.de</li>
</ul>
<hr />
<h2 id="konfiguration">🔧 Konfiguration<a class="headerlink" href="#konfiguration" title="Permanent link">&para;</a></h2>
<h3 id="environment-variablen-env">Environment-Variablen (.env)<a class="headerlink" href="#environment-variablen-env" title="Permanent link">&para;</a></h3>
<div class="highlight"><pre><span></span><code><span class="nv">DASHSCOPE_API_KEY</span><span class="o">=</span>sk-...<span class="w"> </span><span class="c1"># Alibaba DashScope API</span>
<span class="nv">KEYCLOAK_URL</span><span class="o">=</span>https://sso.toppyr.de<span class="w"> </span><span class="c1"># Optional: SSO</span>
<span class="nv">KEYCLOAK_REALM</span><span class="o">=</span>collaboration
<span class="nv">KEYCLOAK_CLIENT_ID</span><span class="o">=</span>gwoe-antragspruefer
</code></pre></div>
<h3 id="llm-modelle">LLM-Modelle<a class="headerlink" href="#llm-modelle" title="Permanent link">&para;</a></h3>
<table>
<thead>
<tr>
<th>Modell</th>
<th>Verwendung</th>
<th>Kosten</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>qwen-plus-latest</code></td>
<td>Standard (Free Tier)</td>
<td>Kostenlos</td>
</tr>
<tr>
<td><code>qwen-plus</code></td>
<td>Fallback (Paid)</td>
<td>~$0.80/MTok</td>
</tr>
<tr>
<td><code>qwen-max</code></td>
<td>Premium</td>
<td>~$2.40/MTok</td>
</tr>
</tbody>
</table>
<hr />
<h2 id="api-endpoints">📊 API-Endpoints<a class="headerlink" href="#api-endpoints" title="Permanent link">&para;</a></h2>
<table>
<thead>
<tr>
<th>Methode</th>
<th>Pfad</th>
<th>Beschreibung</th>
</tr>
</thead>
<tbody>
<tr>
<td>GET</td>
<td><code>/</code></td>
<td>Web-UI</td>
</tr>
<tr>
<td>GET</td>
<td><code>/health</code></td>
<td>Health Check</td>
</tr>
<tr>
<td>GET</td>
<td><code>/quellen</code></td>
<td>Quellenübersicht</td>
</tr>
<tr>
<td>GET</td>
<td><code>/api/assessments</code></td>
<td>Alle Bewertungen (JSON)</td>
</tr>
<tr>
<td>GET</td>
<td><code>/api/assessment?drucksache=18/12345</code></td>
<td>Einzelne Bewertung</td>
</tr>
<tr>
<td>GET</td>
<td><code>/api/search?q=Klima</code></td>
<td>Interne DB-Suche</td>
</tr>
<tr>
<td>GET</td>
<td><code>/api/search-landtag?q=Klima</code></td>
<td>Landtag OPAL-Suche</td>
</tr>
<tr>
<td>POST</td>
<td><code>/api/analyze-drucksache</code></td>
<td>Neue Analyse starten</td>
</tr>
<tr>
<td>GET</td>
<td><code>/api/assessment/pdf?drucksache=18/12345</code></td>
<td>PDF-Download</td>
</tr>
<tr>
<td>GET</td>
<td><code>/api/bundeslaender</code></td>
<td>Verfügbare Bundesländer</td>
</tr>
<tr>
<td>GET</td>
<td><code>/status/{job_id}</code></td>
<td>Job-Status abfragen</td>
</tr>
</tbody>
</table>
<hr />
<h2 id="prompt-v5-kern-features">🧠 Prompt v5 — Kern-Features<a class="headerlink" href="#prompt-v5-kern-features" title="Permanent link">&para;</a></h2>
<p>Der Analyse-Prompt fordert:</p>
<ol>
<li><strong>GWÖ-Treue (0-10)</strong> mit Matrix-Zuordnung:</li>
<li>Matrix-Feld (z.B. "D1 Menschenwürde")</li>
<li>Symbol (++/+/○//)</li>
<li>
<p>Kurzbegründung</p>
</li>
<li>
<p><strong>Programmtreue</strong> für Antragsteller UND Regierungsfraktionen:</p>
</li>
<li>Wahlprogramm-Score (0-10)</li>
<li>Parteiprogramm-Score (0-10)</li>
<li>
<p>Begründungen</p>
</li>
<li>
<p><strong>Verbesserungsvorschläge</strong> (max. 3):
<div class="highlight"><pre><span></span><code><span class="p">{</span>
<span class="w"> </span><span class="nt">&quot;original&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;Zitat aus dem Antrag&quot;</span><span class="p">,</span>
<span class="w"> </span><span class="nt">&quot;vorschlag&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;Konkret **verbesserter** Text&quot;</span><span class="p">,</span>
<span class="w"> </span><span class="nt">&quot;begruendung&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;Stärkt GWÖ-Wert X durch Y&quot;</span>
<span class="p">}</span>
</code></pre></div></p>
</li>
<li>
<p><strong>Themen-Tags</strong> für Kategorisierung</p>
</li>
</ol>
<hr />
<h2 id="deployment">🚀 Deployment<a class="headerlink" href="#deployment" title="Permanent link">&para;</a></h2>
<h3 id="erstinstallation">Erstinstallation<a class="headerlink" href="#erstinstallation" title="Permanent link">&para;</a></h3>
<div class="highlight"><pre><span></span><code>ssh<span class="w"> </span>vserver
<span class="nb">cd</span><span class="w"> </span>/opt
git<span class="w"> </span>clone<span class="w"> </span>https://repo.toppyr.de/tobias/gwoe-antragspruefer.git
<span class="nb">cd</span><span class="w"> </span>gwoe-antragspruefer
<span class="c1"># .env erstellen</span>
cp<span class="w"> </span>.env.example<span class="w"> </span>.env
nano<span class="w"> </span>.env<span class="w"> </span><span class="c1"># DASHSCOPE_API_KEY eintragen</span>
<span class="c1"># Starten</span>
docker<span class="w"> </span>compose<span class="w"> </span>up<span class="w"> </span>-d
</code></pre></div>
<h3 id="update">Update<a class="headerlink" href="#update" title="Permanent link">&para;</a></h3>
<div class="highlight"><pre><span></span><code><span class="c1"># Lokal</span>
<span class="nb">cd</span><span class="w"> </span>~/Nextcloud/dotty/projekte/2026-03-23<span class="se">\ </span>GWÖ-Antragsprüfer<span class="se">\ </span>_WIP_/webapp
git<span class="w"> </span>add<span class="w"> </span>.<span class="w"> </span><span class="o">&amp;&amp;</span><span class="w"> </span>git<span class="w"> </span>commit<span class="w"> </span>-m<span class="w"> </span><span class="s2">&quot;Update&quot;</span><span class="w"> </span><span class="o">&amp;&amp;</span><span class="w"> </span>git<span class="w"> </span>push
<span class="c1"># Auf Server</span>
ssh<span class="w"> </span>vserver<span class="w"> </span><span class="s1">&#39;cd /opt/gwoe-antragspruefer &amp;&amp; git pull &amp;&amp; docker compose up -d --build&#39;</span>
</code></pre></div>
<h3 id="manuelles-deploy-ohne-git-auf-server">Manuelles Deploy (ohne Git auf Server)<a class="headerlink" href="#manuelles-deploy-ohne-git-auf-server" title="Permanent link">&para;</a></h3>
<div class="highlight"><pre><span></span><code><span class="nb">cd</span><span class="w"> </span>~/Nextcloud/dotty/projekte/2026-03-23<span class="se">\ </span>GWÖ-Antragsprüfer<span class="se">\ </span>_WIP_/webapp
tar<span class="w"> </span>czf<span class="w"> </span>/tmp/gwoe-webapp.tar.gz<span class="w"> </span>--exclude<span class="o">=</span><span class="s1">&#39;venv&#39;</span><span class="w"> </span>--exclude<span class="o">=</span><span class="s1">&#39;__pycache__&#39;</span><span class="w"> </span>--exclude<span class="o">=</span><span class="s1">&#39;data&#39;</span><span class="w"> </span>--exclude<span class="o">=</span><span class="s1">&#39;reports&#39;</span><span class="w"> </span>--exclude<span class="o">=</span><span class="s1">&#39;.env&#39;</span><span class="w"> </span>.
scp<span class="w"> </span>/tmp/gwoe-webapp.tar.gz<span class="w"> </span>vserver:/tmp/
ssh<span class="w"> </span>vserver<span class="w"> </span><span class="s1">&#39;cd /opt/gwoe-antragspruefer &amp;&amp; tar xzf /tmp/gwoe-webapp.tar.gz &amp;&amp; docker compose up -d --build&#39;</span>
</code></pre></div>
<hr />
<h2 id="statistiken-28032026">📈 Statistiken (28.03.2026)<a class="headerlink" href="#statistiken-28032026" title="Permanent link">&para;</a></h2>
<table>
<thead>
<tr>
<th>Metrik</th>
<th>Wert</th>
</tr>
</thead>
<tbody>
<tr>
<td>Analysierte Anträge</td>
<td>20</td>
</tr>
<tr>
<td>Ø GWÖ-Score gesamt</td>
<td>4.6</td>
</tr>
<tr>
<td>Ø SPD</td>
<td>7.7</td>
</tr>
<tr>
<td>Ø GRÜNE</td>
<td>6.0</td>
</tr>
<tr>
<td>Ø CDU</td>
<td>6.0</td>
</tr>
<tr>
<td>Ø FDP</td>
<td>4.8</td>
</tr>
<tr>
<td>Ø AfD</td>
<td>1.5</td>
</tr>
</tbody>
</table>
<hr />
<h2 id="bekannte-issues-todos">🐛 Bekannte Issues / TODOs<a class="headerlink" href="#bekannte-issues-todos" title="Permanent link">&para;</a></h2>
<h3 id="offen">Offen<a class="headerlink" href="#offen" title="Permanent link">&para;</a></h3>
<ul>
<li>[ ] Keycloak SSO-Integration aktivieren</li>
<li>[ ] Weitere Bundesländer (BY, BW) anbinden</li>
<li>[ ] Batch-Analyse für viele Anträge</li>
<li>[ ] Wahlprogramm-Zitate mit Seitenzahlen</li>
<li>[ ] Export als CSV/Excel</li>
</ul>
<h3 id="gelost-28032026">Gelöst (28.03.2026)<a class="headerlink" href="#gelost-28032026" title="Permanent link">&para;</a></h3>
<ul>
<li>[x] JSON-Parse-Fehler bei LLM-Output → Retry-Logik</li>
<li>[x] DB nicht persistent → Dockerfile gefixt, data/ als Volume</li>
<li>[x] Alte Assessments überschreiben neue → JSON-Import deaktiviert</li>
<li>[x] Partei-Filter zeigt "Suchfehler" → JS-Bug gefixt</li>
</ul>
<hr />
<h2 id="changelog">📝 Changelog<a class="headerlink" href="#changelog" title="Permanent link">&para;</a></h2>
<h3 id="v100-28032026">v1.0.0 (28.03.2026)<a class="headerlink" href="#v100-28032026" title="Permanent link">&para;</a></h3>
<ul>
<li>Initial Release</li>
<li>GWÖ-Matrix 2.0 Analyse für NRW</li>
<li>Verbesserungsvorschläge im Redline-Format</li>
<li>Tag-Wolke mit Multi-Select</li>
<li>Partei-Filter + Durchschnittswerte</li>
<li>Security Headers</li>
<li>Docker Deployment</li>
</ul>
<hr />
<h2 id="quellen">📚 Quellen<a class="headerlink" href="#quellen" title="Permanent link">&para;</a></h2>
<ul>
<li><a href="https://econgood.org">GWÖ-Matrix 2.0 für Gemeinden (Arbeitsbuch)</a></li>
<li><a href="https://econgood.org">ECOnGOOD Corporate Design Manual 2024</a></li>
<li><a href="https://www.landtag.nrw.de">NRW OPAL Parlamentsdokumentation</a></li>
<li>Wahlprogramme NRW 2022 (CDU, GRÜNE, SPD, FDP, AfD)</li>
<li>Grundsatzprogramme der Parteien</li>
</ul>
<hr />
<p><strong>Entwickelt von Tobias Rödel mit Unterstützung von Dotty</strong> 👻</p>
</article>
</div>
<script>var target=document.getElementById(location.hash.slice(1));target&&target.name&&(target.checked=target.name.startsWith("__tabbed_"))</script>
</div>
</main>
<footer class="md-footer">
<div class="md-footer-meta md-typeset">
<div class="md-footer-meta__inner md-grid">
<div class="md-copyright">
Made with
<a href="https://squidfunk.github.io/mkdocs-material/" target="_blank" rel="noopener">
Material for MkDocs
</a>
</div>
</div>
</div>
</footer>
</div>
<div class="md-dialog" data-md-component="dialog">
<div class="md-dialog__inner md-typeset"></div>
</div>
<script id="__config" type="application/json">{"annotate": null, "base": "../..", "features": ["navigation.sections", "navigation.expand", "search.highlight"], "search": "../../assets/javascripts/workers/search.2c215733.min.js", "tags": null, "translations": {"clipboard.copied": "In Zwischenablage kopiert", "clipboard.copy": "In Zwischenablage kopieren", "search.result.more.one": "1 weiteres Suchergebnis auf dieser Seite", "search.result.more.other": "# weitere Suchergebnisse auf dieser Seite", "search.result.none": "Keine Suchergebnisse", "search.result.one": "1 Suchergebnis", "search.result.other": "# Suchergebnisse", "search.result.placeholder": "Suchbegriff eingeben", "search.result.term.missing": "Es fehlt", "select.version": "Version ausw\u00e4hlen"}, "version": null}</script>
<script src="../../assets/javascripts/bundle.79ae519e.min.js"></script>
</body>
</html>