diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000..549f4bf
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,100 @@
+# Changelog
+
+Alle markanten Änderungen pro Release. Format an [Keep a Changelog](https://keepachangelog.com/de/1.1.0/) angelehnt, semantisches Versioning.
+
+## [1.0.0] — 2026-04-21
+
+Erstes konsolidiertes Release nach längerer 0.x-Entwicklungsphase. Live unter
+.
+
+### Hinzugefügt — Frontend (v2)
+
+- **Komplettes Redesign** auf das ECOnGOOD Corporate Design (Manual Juni 2024) — Tokens-Datei, Avenir/Nunito-Sans-Stack, Phosphor-Icon-Set, Dark-Mode mit `data-theme`-Attribut (#114, #139)
+- **AppShell** mit zwei-Spalten-Layout (Sidebar 230 px, Main), Drawer auf Mobile, Navigation in vier Gruppen LESEN/PRÜFEN/DATEN/ADMINISTRATION
+- **Server-Side-Routing** für Antragsdetail (`/antrag/{drucksache}`), keine reine Client-Seite mehr
+- **Login-Modal** in der Topbar mit Tabs Anmelden/Registrieren via Direct-Access-Grant — kein Keycloak-Redirect mehr (#129)
+- **Keyboard-Shortcuts** j/k/Enter/Esc/?/⏎ im Listenmodus mit Help-Modal
+- **Sort-Dropdown** mit acht Optionen (Score/Datum/Drs.-Nr./Titel je asc/desc), localStorage-persistiert
+- **Antragsdetail vollständig** mit ScoreHero, Matrix-Mini 5×5 (klickbar mit Erklärungs-Modal), Programm-Treue-Tabelle pro Fraktion (auch ohne Zitate), §INS§/§DEL§-Redline-Parser, Versionshistorie, namentlichem Abstimmungsverhalten als Balken pro Fraktion (#106 Phase 1)
+- **Bookmarks/Voting/Kommentare/Share/Re-Analyze** alle in v2-Detail integriert mit Auth-Modal-Fallback
+- **Live-Landtag-Suche** als eigener Screen `/v2/landtag-suche`
+- **Admin-Panel** mit drei Screens (Freischaltungen, Queue mit 5 s Auto-Refresh, Abos für alle User)
+- **Open-Graph-Bilder** pro Antrag (1200×630 PNG, Playwright-gerendert, SHA-Cache) (#141)
+
+### Hinzugefügt — Backend
+
+- **16 Landesparlamente + Bundestag** als Adapter (BUND, NRW, BE, HH, BW, RP, LSA, MV, HB, HE, BY, SL, TH, BB, SN, SH; NI deferred wegen Login)
+- **abgeordnetenwatch.de-Integration** Phase 1 für strukturierte Roll-Call-Votes — 28 977 BT-Votes in DB, Drucksachen-Match via 9 BL-spezifische URL-Patterns + Datum/Titel-Fallback (#106)
+- **Drucksachen-Typen-Normalisierung** filtert Anträge/Gesetzentwürfe von Kleinen Anfragen etc. (#127)
+- **Embeddings v3 → v4** Modell-Migration mit WRITE/READ-Pattern (ADR 0006)
+- **DDD-Lightweight-Migration** Tag 1-4: `LlmBewerter`-Port, `QwenBewerter`-Adapter, drei Repositories (Antrag/Bewertung/Abonnement), Domain-Verhalten auf Pydantic-Modellen (ADR 0008, #136)
+- **Mail-Digest** mit täglichem Cron 07:00, BL/Partei-Filter pro User-Abo (#124)
+- **Monitoring-Scan** aller Adapter mit Kosten-Schätzung — Beobachtung ohne Auto-Fetch, Mail-Report mit „0-Kontext"-Hinweis (#135)
+- **Merkliste server-seitig** mit Migration aus localStorage (#140)
+- **Wahlprogramm-Auto-Download** halbautomatisch mit SHA-Gate, kuratierte URL-Liste, Admin-UI (#138)
+- **Fehlende Wahlprogramme** automatisch im Assessment markiert + UI-Hinweis (#128)
+- **Clustering** via Embedding-Nähe-Graph mit Bubble-Chart (#105)
+- **Background-Queue** mit drei parallelen Workern, Graceful Shutdown 15 min, Job-Persistenz (#99)
+- **Voting + Kommentare** mit Visibility-Modi (öffentlich/angemeldet/nur ich) (#94)
+- **RSS/Atom-Feed** für neue Bewertungen (#125)
+
+### Hinzugefügt — Tests & Doku
+
+- **574 Tests, 13 skipped** — Unit-Suite < 2 s, plus Integration/E2E unter Markern
+- **Bug-Regression-Tests** für fünf historische Fixes (PRAGMA-Cursor, JWT-azp, CDU-PDF, PFLICHT-FRAKTIONEN, NRW-Titel)
+- **Live-Adapter-Tests** + Frontend-Cross-Validation + Citation-Substring-Tests (`pytest -m integration`)
+- **Playwright-E2E-Tests** (`pytest -m e2e`)
+- **Smoke-Test-Script** `scripts/smoke-test.sh` für Gesamt-Funktionsprüfung gegen Live-System
+- **8 ADRs** dokumentiert, plus DDD-Bewertung (1 237 LOC) und Protokoll-Parser-v6-Machbarkeit (418 LOC)
+- **Zugriffsrechte-Doc** mit 63 Routes × User-Status-Matrix
+- **Doppel-Lizenz** Code MIT + Daten/Bewertungen CC-BY-4.0
+
+### Geändert
+
+- `/` zeigt jetzt v2-Frontend, classic unter `/classic` weiterhin erreichbar
+- Auswertungen mit BL-Filter (#137 fix)
+- Direkt-Verlinkbarkeit (`/antrag/{drs}`) als Permalinks ersetzen Query-Parameter (#132)
+- Social-Media-Texte werden vom LLM erzeugt und in DB gespeichert (#133)
+- v5-Prompt mit PFLICHT-FRAKTIONEN aller LT-Fraktionen, nicht nur Antragsteller+Regierung
+- Citation-Binding server-seitig: Quellen-Label der Zitate werden gegen die tatsächlich abgerufenen Chunks rekonstruiert (ADR 0001)
+- Mail-Digest-Template mit „0-Kontext"-Hinweis falls keine neuen Drucksachen seit letztem Scan
+- Login als HttpOnly-Cookie + separate `rt`-Cookie für Refresh-Token (`/api/auth/logout`-Route für sauberen Cookie-Reset)
+
+### Bekannte Einschränkungen
+
+- **NI (Niedersachsen)** im Monitoring-Scan geskippt — NILAS-Portal ist Login-protected, HAR-Capture nötig (#22)
+- **Saarland-Adapter** swallowt manche httpx-Exceptions tiefer im Code als der erste Fix-Layer (#142)
+- **Drucksachen-Match in MV/BY/BB/TH/HH/SL** für abgeordnetenwatch-Polls noch lückenhaft — deren `field_intro`-HTML enthält keine PDF-Links, der Datum+Titel-Fallback hängt von vorheriger Indexierung ab
+- **Plenarprotokoll-Parser v6** für nicht-namentliche Abstimmungen ist Phase 2, nicht in 1.0 (#106 follow-up)
+- **DDD-Callsite-Migration** in `main.py` (~21 direkte Database-Aufrufe → Repository-Dependency-Injection) als Folge-PR offen (#136 follow-up)
+
+### Sicherheit
+
+- **Security-Headers** (CSP, X-Frame-Options, X-Content-Type-Options, Referrer-Policy, Permissions-Policy)
+- **Rate-Limiting** auf teuren POST-Endpoints (10/min auf `/api/analyze-drucksache`)
+- **Eingabe-Validatoren** (Drucksachen-Format-Regex, Such-Query-Längen-Cap)
+- **JWT-Validation** über Keycloak JWKS, `azp`-Check statt `aud` für Public Clients (49c1b92)
+
+### Statistik
+
+- 11 789 LOC Python in `app/`
+- 23 Module, 8 Templates-Verzeichnisse
+- 71 produktive Bewertungen in der Live-DB
+- 85 Wahlprogramme indexiert (Embeddings v4, ~50 000 Chunks)
+- 28 977 abgeordnetenwatch-Votes
+- 574 Tests, 0 Regressions
+
+---
+
+## [0.x] — Pre-Release-Phase
+
+Frühere Iterationen. Siehe `git log` für Detail-Historie. Wesentliche Meilensteine:
+
+- v3 → v4 Embedding-Migration (#123)
+- Clustering + Force-Graph (#105, #108)
+- Bookmarks + Kommentare (#94)
+- Methodik-/Transparenz-Seite (#96)
+- Keycloak SSO (#43)
+- Multi-BL-Adapter (#22 Reihe, #72-#87)
+
+[1.0.0]: https://repo.toppyr.de/tobias/gwoe-antragspruefer/releases/tag/v1.0.0
diff --git a/DATA-LICENSE b/DATA-LICENSE
new file mode 100644
index 0000000..0b0f778
--- /dev/null
+++ b/DATA-LICENSE
@@ -0,0 +1,57 @@
+Datenrechte für GWÖ-Antragsprüfer
+================================================================================
+
+Copyright (c) 2026 Tobias Rödel und Mitwirkende
+
+Dieses Werk umfasst alle vom GWÖ-Antragsprüfer **erzeugten** Inhalte:
+ - Bewertungen (Assessments) im JSON-Format
+ - GWÖ-Score-Werte und Matrix-Zuordnungen
+ - Begründungstexte und Empfehlungen
+ - Verbesserungsvorschläge im Redline-Format
+ - Themen-Tags, Stärken/Schwächen-Listen
+ - Aggregations-Tabellen und Auswertungs-Daten
+ - Generierte PDF-Berichte
+
+Diese Inhalte sind lizenziert unter der
+
+ Creative Commons Attribution 4.0 International License (CC BY 4.0)
+
+ https://creativecommons.org/licenses/by/4.0/deed.de
+
+Du darfst:
+ - Teilen — das Material in jedwedem Format oder Medium vervielfältigen und
+ weiterverbreiten
+ - Bearbeiten — das Material remixen, verändern und darauf aufbauen
+ und zwar für beliebige Zwecke, auch kommerziell.
+
+Unter folgenden Bedingungen:
+ - Namensnennung — Du musst angemessene Urheber- und Rechteangaben machen,
+ einen Link zur Lizenz beifügen und angeben, ob Änderungen vorgenommen
+ wurden. Empfohlene Quellangabe:
+
+ "GWÖ-Antragsprüfer · gwoe.toppyr.de · CC BY 4.0"
+
+ - Keine weiteren Einschränkungen — Du darfst keine zusätzlichen Klauseln
+ oder technische Verfahren einsetzen, die anderen rechtlich irgendetwas
+ untersagen, was die Lizenz erlaubt.
+
+================================================================================
+NICHT von dieser Lizenz gedeckt:
+
+ - Quellcode des GWÖ-Antragsprüfers selbst — siehe LICENSE (MIT).
+
+ - Original-Antrags-PDFs und Plenarprotokolle der Landesparlamente und des
+ Bundestags — diese unterliegen den jeweiligen Veröffentlichungs-
+ Bedingungen ihrer Quellen. Sie werden vom Antragsprüfer ausschließlich
+ zur Bewertung referenziert, nicht weiterverbreitet.
+
+ - Wahlprogramme und Grundsatzprogramme der politischen Parteien — diese
+ sind urheberrechtlich geschützt und gehören den jeweiligen Parteien.
+ Indexierte Snippets werden im Rahmen des Zitatrechts (§ 51 UrhG)
+ zur Verifikation der Bewertungen genutzt.
+
+ - Logos und CD-Elemente der Gemeinwohl-Ökonomie / ECOnGOOD — diese
+ unterliegen den Markenrichtlinien der ECOnGOOD-Föderation.
+
+================================================================================
+Kontakt für Lizenzfragen: mail@tobiasroedel.de
diff --git a/README.md b/README.md
index 4b0a082..c5127c3 100644
--- a/README.md
+++ b/README.md
@@ -4,145 +4,144 @@


-
+
+
+
-## 🎯 Was ist das?
+Live unter .
-Der GWÖ-Antragsprüfer analysiert Anträge aus Landesparlamenten (aktuell NRW) und bewertet sie nach den Kriterien der **Gemeinwohl-Ökonomie (GWÖ)**:
+## Was macht das Tool?
-- **GWÖ-Score (0-10)**: Wie gut entspricht der Antrag den GWÖ-Werten?
-- **Matrix-Zuordnung**: Welche Felder der GWÖ-Matrix werden adressiert?
-- **Programmtreue**: Passt der Antrag zu Wahl- und Parteiprogrammen?
-- **Verbesserungsvorschläge**: Konkrete Textänderungen mit GWÖ-Begründung
+Der GWÖ-Antragsprüfer analysiert Anträge aus deutschen Landesparlamenten und dem Bundestag und bewertet sie nach den Kriterien der **Gemeinwohl-Ökonomie (GWÖ)**:
-## ✨ Features
+- **GWÖ-Score (0–10)** — Wie gut entspricht der Antrag den GWÖ-Werten?
+- **Matrix-Zuordnung** — Welche der 25 Felder der GWÖ-Matrix für Gemeinden werden adressiert?
+- **Programm-Treue** — Passt der Antrag zum Wahl- und Grundsatzprogramm jeder Fraktion?
+- **Verbesserungsvorschläge** — Konkrete Textänderungen mit GWÖ-Begründung im Redline-Format
+- **Zitate mit Verifikation** — Belege aus den Wahl-/Grundsatzprogrammen, server-seitig gegen Original-Chunks geprüft (siehe ADR 0001)
-- 🔍 **Landtag-Suche**: Direkte Anbindung an OPAL (NRW Parlamentsdokumentation)
-- 📊 **GWÖ-Matrix-Visualisierung**: 5×5-Tabelle mit Bewertungssymbolen
-- 🏷️ **Tag-Wolke**: Filter nach Themen mit Multi-Select
-- 🎯 **Partei-Filter**: Durchschnittswerte pro Fraktion
-- 📄 **PDF-Export**: Professionelle Berichte im GWÖ-Design
-- 🔒 **Security**: CSP, CORS, Rate Limiting
+## Aktive Datenquellen (Stand Release 1.0)
-## 🚀 Schnellstart
+**16 Bundesländer + Bundestag** — alle aktiven Adapter:
+
+| BL | Wahlperiode | Quelle |
+|---|---|---|
+| BUND | 21 (2025–2029) | bundestag.de DIP |
+| BW | 17 (2021–2026) | PARLIS |
+| BY | 19 (2023–2028) | Bayern Landtag |
+| BE | 19 (2023–2026) | Berlin AGH |
+| BB | 8 (2024–2029) | StarWeb |
+| HB | 21 (2023–2027) | ParlDok |
+| HH | 23 (2025–2029) | ParlDok |
+| HE | 21 (2024–2029) | Hessen Landtag |
+| MV | 8 (2021–2026) | ParlDok |
+| NI | — | NILAS (login-protected, deferred) |
+| NRW | 18 (2022–2027) | OPAL |
+| RP | 18 (2021–2026) | StarWeb |
+| LSA | 8 (2021–2026) | StarWeb |
+| SL | 17 (2022–2027) | Umbraco |
+| SN | 8 (2024–2029) | XML-Export |
+| SH | 20 (2022–2027) | Schleswig-Holstein |
+| TH | 8 (2024–2029) | StarWeb |
+
+Plus **abgeordnetenwatch.de**-Integration für strukturierte namentliche Abstimmungen (alle 16 BL + BT).
+
+## Features
+
+### Frontend (v2, ECOnGOOD-CD)
+
+- **Listenansicht** mit Score-Band-Filter, BL-Chip-Filter, Sort-Dropdown (8 Optionen), Live-Suche
+- **Antragsdetail** mit ScoreHero, Matrix 5×5, Zitaten, Redline-Diff, Programm-Treue pro Fraktion, Versionshistorie, namentlichem Abstimmungsverhalten (wenn vorhanden)
+- **Bookmark-Liste** (server-seitig pro User), **Kommentare**, **Voting**, **Share-Buttons** (Threads/X/Mastodon mit LLM-Texten), **Re-Analyze**
+- **Auswertungen** mit BL×Partei-Matrix, Themen×Fraktion-Heatmap, Cluster-Bubble-Chart
+- **Tag-Cloud**, **Cluster-Liste**, **Landtag-Live-Suche**, **Methodik**, **Quellen**
+- **Admin-Panel** Freischaltungen / Queue / Abos / Wahlprogramme
+- **Dark-Mode**, **Phosphor-Icons**, Avenir/Nunito-Sans, **Keyboard-Shortcuts** (j/k/Enter/Esc/?/⏎)
+
+### Backend
+
+- **FastAPI** + Jinja2 + Vanilla JS (kein Build-Tool)
+- **SQLite** mit aiosqlite (Source of Truth)
+- **Qwen-Plus** (DashScope) für die LLM-Bewertung — austauschbar via `LlmBewerter`-Port (ADR 0008)
+- **Embeddings v4** für die Zitat-Verifikation (ADR 0006)
+- **Keycloak SSO** mit Direct-Access-Grant (Login-Modal in der App, kein Redirect)
+- **Background-Queue** mit 3 parallelen Workern + Graceful Shutdown
+- **Daily-Digest-Mail** für Abonnent:innen
+- **Monitoring-Scan** aller Adapter mit Kosten-Schätzung — Beobachtung ohne Auto-Fetch
+- **OG-Cards** (Open-Graph-Bilder pro Antrag, Playwright-gerendert)
+- **WeasyPrint** für PDF-Reports
+
+### Tests
+
+- **574 Tests, 13 skipped** — Unit + Integration + Property + Bug-Regression + DDD
+- Live-Adapter-Tests gegen alle 17 Quellen (`pytest -m integration`)
+- Citation-Substring-Verification gegen Original-PDFs
+- E2E-Browser-Tests via Playwright (`pytest -m e2e`)
+
+## Architektur
+
+Detailliert in [`docs/`](docs/):
+
+- [`docs/adr/`](docs/adr/) — Architecture Decision Records (8 ADRs)
+- [`docs/analysen/ddd-bewertung.md`](docs/analysen/ddd-bewertung.md) — DDD-Analyse + Migrations-Roadmap
+- [`docs/reference/zugriffsrechte.md`](docs/reference/zugriffsrechte.md) — 63 Routes × User-Status-Matrix
+- [`docs/reference/api.md`](docs/reference/api.md) — API-Reference
+
+DDD-Lightweight-Migration ist **Tag 1-4 abgeschlossen** (Ports, Adapter, Repositories, Domain-Verhalten — siehe ADR 0008). Callsite-Migration in `main.py` ist Folge-PR.
+
+## Schnellstart
### Voraussetzungen
-- Python 3.12+
-- Docker & Docker Compose
-- DashScope API-Key (Qwen LLM)
+- Docker + Docker Compose
+- Python 3.12 (für lokale Tests)
+- DashScope API-Key (Qwen)
+- Keycloak (optional, für Login)
### Installation
```bash
-# Repository klonen
-git clone https://github.com/tobiasroedel/gwoe-antragspruefer.git
-cd gwoe-antragspruefer
-
-# Environment-Variablen
-cp .env.example .env
-# DASHSCOPE_API_KEY eintragen
-
-# Mit Docker starten
-docker compose up -d
-
-# Oder lokal entwickeln
-python -m venv venv
-source venv/bin/activate
-pip install -r requirements.txt
-uvicorn app.main:app --reload
+git clone https://repo.toppyr.de/tobias/gwoe-antragspruefer
+cd gwoe-antragspruefer/webapp
+cp .env.example .env # API-Keys eintragen
+docker compose up -d --build
```
-Die App läuft auf http://localhost:8000
+App auf .
-## 📁 Projektstruktur
-
-```
-webapp/
-├── app/
-│ ├── main.py # FastAPI-Endpoints
-│ ├── analyzer.py # LLM-Analyse-Logik
-│ ├── database.py # SQLite-Persistenz
-│ ├── models.py # Pydantic-Modelle
-│ ├── parlamente.py # Landtag-Adapter (OPAL)
-│ ├── report.py # PDF-Generierung
-│ ├── config.py # Settings
-│ ├── kontext/ # GWÖ-Matrix, Wahlprogramme
-│ ├── templates/ # Jinja2-HTML
-│ └── static/ # CSS, JS, Assets
-├── data/ # SQLite-DBs (Volume)
-├── reports/ # Generierte PDFs (Volume)
-├── docker-compose.yml
-├── Dockerfile
-└── requirements.txt
-```
-
-## 🔧 Konfiguration
-
-### Environment-Variablen
-
-| Variable | Beschreibung | Default |
-|----------|--------------|---------|
-| `DASHSCOPE_API_KEY` | Alibaba DashScope API-Key | (required) |
-| `LLM_MODEL_DEFAULT` | Standard-Modell | `qwen-plus-latest` |
-| `LLM_MODEL_PREMIUM` | Premium-Modell | `qwen-max` |
-
-### Unterstützte Bundesländer
-
-| Code | Name | Status |
-|------|------|--------|
-| NRW | Nordrhein-Westfalen | ✅ Aktiv |
-| BY | Bayern | 🔜 Geplant |
-| BW | Baden-Württemberg | 🔜 Geplant |
-
-## 📊 API-Endpoints
-
-| Methode | Pfad | Beschreibung |
-|---------|------|--------------|
-| GET | `/` | Web-UI |
-| GET | `/api/assessments` | Alle Bewertungen |
-| GET | `/api/assessment?drucksache=18/12345` | Einzelne Bewertung |
-| POST | `/api/analyze-drucksache` | Neue Analyse starten |
-| GET | `/api/search?q=Klima` | Interne Suche |
-| GET | `/api/search-landtag?q=Klima` | Landtag-Suche |
-| GET | `/api/assessment/pdf?drucksache=18/12345` | PDF-Download |
-
-## 🧠 GWÖ-Prompt (v5)
-
-Der Analyse-Prompt basiert auf:
-- **GWÖ-Matrix 2.0 für Gemeinden** (Arbeitsbuch)
-- **ECOnGOOD Corporate Design Manual 2024**
-- **Wahlprogramme** der NRW-Landtagsparteien 2022
-
-Ausgabe-Format:
-- GWÖ-Score mit Matrix-Feldern und Symbolen (++/+/○/−/−−)
-- Wahlprogramm- und Parteiprogrammtreue
-- **Verbesserungsvorschläge im Redline-Format** (Original → Vorschlag → Begründung)
-- Themen-Tags für Kategorisierung
-
-## 🛠️ Entwicklung
+### Tests
```bash
-# Tests ausführen
-pytest
-
-# Linting
-ruff check app/
-
-# Type-Checking
-mypy app/
+python3 -m pytest tests/ -q # Unit-Suite (574 Tests, < 2 s)
+python3 -m pytest tests/ -m integration # Live-Adapter-Tests (langsam)
+./scripts/smoke-test.sh # Gesamt-Funktionsprüfung gegen Live
```
-## 📝 Lizenz
+### Deploy (Server)
-MIT License - siehe [LICENSE](LICENSE)
+```bash
+./scripts/deploy.sh # mit Uptime-Kuma-Wartungsmodus
+./scripts/run-digest.sh # Daily-Mail-Digest (Cron 07:00)
+./scripts/run-monitoring-scan.sh # Monitoring-Scan (manuell oder Cron)
+```
-## 🙏 Credits
+## Lizenz
-- [Gemeinwohl-Ökonomie](https://econgood.org) - Matrix und Arbeitsbücher
-- [Alibaba DashScope](https://dashscope.aliyuncs.com) - Qwen LLM API
-- [Landtag NRW](https://www.landtag.nrw.de) - OPAL-Dokumentation
+Zwei getrennte Lizenzen:
----
+- **Quellcode** — [MIT](LICENSE)
+- **Bewertungs-Daten und -Berichte** (Assessments, Matrix-Zuordnungen, Verbesserungsvorschläge, Themen-Tags etc.) — [CC BY 4.0](DATA-LICENSE)
-**Entwickelt von Tobias Rödel** · [tobiasroedel.de](https://tobiasroedel.de)
+Wahlprogramme und Antrags-PDFs der Parlamente unterliegen der jeweiligen Urheber-Lizenz der Quelle und werden hier nur zur Verifikation referenziert.
+
+## Mitwirken
+
+Issues unter . Pull Requests willkommen — beachte ADR 0004 (Deployment-Workflow) und die Test-Konventionen in `pytest.ini`.
+
+## Statistiken (Stand Release 1.0)
+
+- 16 BL + Bundestag aktiv
+- 85 Wahlprogramme indexiert (Embeddings v4)
+- 71 produktive Bewertungen in der Live-DB
+- 28 977 abgeordnetenwatch-Votes (BUND)
+- 11 789 LOC Python in `app/`