# Adapter-Capabilities: Vergleichsmatrix

Stand: 2026-04-10. Automatisch aus `parlamente.py` + `bundeslaender.py` extrahiert.

## Übersicht

16 Bundesländer + Bundestag, alle aktiv.

| BL | Adapter | WP | Suche | Fuzzy | Typ-Filter | API |
|---|---|---|---|---|---|---|
| **BUND** | BundestagAdapter | 21 | Server (DIP REST) + Title-Filter | Nein | Server (`f.drucksachetyp`) | REST JSON |
| **NRW** | NRWAdapter | 18 | Server (HTML-Form) + AND-Filter | Nein | Server (`dokTyp`) | HTML POST |
| **LSA** | PortalaAdapter | 8 | Server (eUI) + Title-Filter | Nein | Server (`ETYPF=Antrag`) | eUI 2-Step |
| **BE** | PortalaAdapter | 19 | Server (eUI, 730d-Fenster) + Title-Filter | Nein | Client-only | eUI 2-Step |
| **BB** | PortalaAdapter | 8 | Server (eUI) + Title-Filter | Nein | Server (`ETYPF=Antrag`) | eUI 2-Step |
| **RP** | PortalaAdapter | 18 | Server (eUI) + Title-Filter | Nein | Server (`ETYPF=Antrag`) | eUI 2-Step |
| **MV** | ParLDokAdapter | 8 | Server (ParlDok JSON) + Typ-Filter | Nein | Client (`type=="Antrag"`) | REST JSON |
| **HH** | ParLDokAdapter | 23 | Server (ParlDok JSON) + Typ-Filter | Nein | Client (`type=="Antrag"`) | REST JSON |
| **TH** | ParLDokAdapter | 8 | Server (ParlDok JSON) + Typ-Filter | Nein | Client (Substring `"Antrag"` in type) | REST JSON |
| **SH** | StarFinderCGI | 20 | Server (CGI, `dtyp=antrag`) + Title-Filter | Nein | Server (`dtyp`) | Legacy CGI |
| **HE** | StarWebHEAdapter | 21 | Server (eUI, VTDRS) + Title+Typ-Filter | Nein | Client (`"antrag"` in typ) | eUI 2-Step |
| **HB** | PARiSHBAdapter | 21 | Server (PARiS-Servlet) + Typ-Filter | Nein (Thesaurus only) | Client (`"antrag"` in typ) | HTML POST |
| **BW** | PARLISAdapter | 17 | Server (eUI, async Polling) + Title-Filter | Nein | Server (`lines.l4=Antrag`) | eUI async |
| **BY** | BayernAdapter | 19 | **Server-Volltext (Solr)** + Typ-Filter | **Ja (Solr)** | Client (`typ=="antrag"`) | HTML Scraping |
| **SL** | SaarlandAdapter | 17 | **Server-Volltext (Umbraco)** + Typ-Filter | Umbraco-Relevanz | Client (`DocumentType`) | REST JSON |
| **SN** | SNEdasXmlAdapter | 8 | Statisch (manueller XML-Export) + Title-Filter | Nein | N/A | XML Import |

## Such-Architekturen

### Volltext-Suche server-seitig

Nur **BY** (TYPO3-Solr) und **SL** (Umbraco) bieten echte Volltextsuche
über den gesamten Dokumentkorpus. Alle anderen filtern entweder nur den
Titel client-seitig oder nutzen eingeschränkte Server-Filter (WP + Datum).

### Client-seitige Title-Filterung

Die Mehrheit (portala/eUI, ParlDok, StarFinder, BUND) holt einen breiten
Satz von Treffern nach WP/Datum/Typ und filtert dann im Python-Code per
`all(t in title.lower() for t in query_terms)`. Das bedeutet:

- **Nur Titel-Matches** — Inhalte der Drucksachen werden nicht durchsucht
- **AND-Logik** — alle Suchbegriffe müssen im Titel vorkommen
- **Keine Fuzzy-Toleranz** — Tippfehler oder Synonym-Drift werden nicht abgefangen
- **Performance ok** — max. 1000-1500 Treffer pro Request (via chunksize)

### Sonderfälle

| BL | Besonderheit |
|---|---|
| **SN** | Kein Scraping möglich (`robots.txt`); manueller wöchentlicher XML-Export aus EDAS |
| **BE** | `document_type=None` weil Berlin's ETYPF andere Values nutzt; 730-Tage-Fenster als Workaround |
| **TH** | Anträge heißen "Antrag gemäß § 79 GO" → Substring-Match statt Exact-Match; `kinds=["Drucksache", "Vorlage"]` |
| **BW** | Async 2-Step mit Search-ID-Polling (2-15 Versuche × 2s Pause), JSON-in-HTML-Comments |
| **HE** | Perl-Data::Dumper in HTML-Comments, Hex-Escape-Decoding (`\x{e9}` → `é`) |
| **NI** | ❌ **Nicht implementiert** — NILAS-StarWeb braucht Session-Cookie, HAR-Capture nötig |

## Feld-Mapping: Woher kommen die Daten?

Pro Adapter: welches API-Feld wird zu welchem Drucksache-Feld, mit Beispiel.

### NRW (NRWAdapter — OPAL HTML)

| Feld | Quelle | Beispiel |
|---|---|---|
| title | HTML `.e-document-result-item__title` `<a>` Text | "Kostenloses Parken für E-Fahrzeuge aufheben" |
| datum | `<time>` Element, DD.MM.YYYY → ISO | "07.04.2026" → "2026-04-07" |
| fraktionen | `<p>` mit "Urheber:" → `extract_fraktionen()` | "Urheber: SPD, GRÜNE" → `["SPD", "GRÜNE"]` |
| drucksache | Regex aus href `MMD18-12345.pdf` → "18/12345" | "18/18085" |
| link | `https://www.landtag.nrw.de{href}` | `https://www.landtag.nrw.de/.../MMD18-18085.pdf` |
| typ | HTML `.e-document-result-item__category` | "Antrag", "Kleine Anfrage" |

### LSA / BB / RP (PortalaAdapter — eUI Perl-Dump)

| Feld | Quelle (Perl-Dump-Feld) | Beispiel |
|---|---|---|
| title | `WEV06[0].main` | "Energiewende und Klimaschutz" |
| datum | `WEV32[0].main` → Regex, DD.MM.YYYY → ISO | "01.10.2024" → "2024-10-01" |
| fraktionen | `WEV32[0].main` Urheber-Text → `extract_fraktionen()` | "CDU, SPD" → `["CDU", "SPD"]` |
| drucksache | `WEV32[0].main` → Regex | "8/6645" |
| link | `{base_url}{pdf_url_prefix}{WEV32[0].5}` | `https://padoka.landtag.sachsen-anhalt.de/files/drs/8/6645.pdf` |
| typ | Fest: "Antrag" (server-side gefiltert via `ETYPF`) | "Antrag" |

### BE (PortalaAdapter — eUI HTML-Cards)

| Feld | Quelle (HTML-Element) | Beispiel |
|---|---|---|
| title | `<h3 class="h5">` Text | "Kinder- und Familienförderung" |
| datum | `<h6>` Metadata-Zeile → Regex DD.MM.YYYY → ISO | "31.03.2026" → "2026-03-31" |
| fraktionen | `<h6>` Doctype-Zeile → `extract_fraktionen()` | "Antrag CDU, SPD" → `["CDU", "SPD"]` |
| drucksache | `<h6>` → Regex | "19/3104" |
| link | `<a href="…pdf">` (http→https, relativ→absolut) | `https://pardok.parlament-berlin.de/...` |
| typ | `<h6>` vor Fraktionsnamen | "Antrag", "Vorlage" |

### MV / HH / TH (ParLDokAdapter — JSON-API)

| Feld | Quelle (JSON-Feld) | Beispiel |
|---|---|---|
| title | `title` | "Weiterbildungsförderung" |
| datum | `date`, DD.MM.YYYY → ISO | "15.03.2026" → "2026-03-15" |
| fraktionen | `authorhtml` → `extract_fraktionen()` | "Klaus Meyer (CDU)" → `["CDU"]` |
| drucksache | `f"{lp}/{number}"` | lp=8, number=1594 → "8/1594" |
| link | `{base_url}{prefix}{link}` (Fragment `#navpanes=0` gestrippt) | `https://dokumentation.landtag-mv.de/parldok/dokument/8` |
| typ | `type` (TH: Substring-Match auf "Antrag") | "Antrag", "Antrag gemäß § 79 GO" |

### SH (StarFinderCGIAdapter — Legacy CGI)

| Feld | Quelle (HTML-Regex) | Beispiel |
|---|---|---|
| title | `<b>…</b>` in Tabellenzeile | "Energiewende vorantreiben" |
| datum | Nach `</b>`, DD.MM.YYYY → ISO | "07.04.2026" → "2026-04-07" |
| fraktionen | Urheber-Text → `extract_fraktionen()` | "Christian Dirschauer (SSW)" → `["SSW"]` |
| drucksache | `<a>` Text | "20/5136" |
| link | `<a href="…">` direkt | `http://lissh.lvn.parlanet.de/.../20-5136.pdf` |
| typ | Fest: "Antrag" (server-side `dtyp=antrag`) | "Antrag" |

### HE (StarWebHEAdapter — eUI Perl-Dump)

| Feld | Quelle (Perl-Dump-Feld) | Beispiel |
|---|---|---|
| title | `WEV01[0].main` (Hex-Escape-Decoding `\x{e9}` → `é`) | "Schulinfrastruktur modernisieren" |
| datum | `WEV02[0].main`, DD.MM.YYYY → ISO | "29.02.2026" → "2026-02-29" |
| fraktionen | `WEV12[0].main` → `extract_fraktionen()` | "Klaus Dieter (GRÜNE)" → `["GRÜNE"]` |
| drucksache | `WEV08[0].main` | "21/8532" |
| link | `WEV07[0].main` (http→https) | `https://starweb.hessen.de/.../21_8532.pdf` |
| typ | `WEV03[0].main` | "Antrag", "Antrag mit Änderung" |

### HB (PARiSHBAdapter — Java-Servlet HTML)

| Feld | Quelle (HTML-Regex) | Beispiel |
|---|---|---|
| title | `<h2><a>…</a></h2>` | "Bremenpass für Kultur" |
| datum | Nach Drucksache, DD.MM.YYYY → ISO | "23.02.2026" → "2026-02-23" |
| fraktionen | Nach Datum → `extract_fraktionen()` | "SPD, BÜNDNIS 90/DIE GRÜNEN, Die Linke" → `["SPD", "GRÜNE", "LINKE"]` |
| drucksache | `Drs <b>21/730</b>` + optionaler Suffix (S/L) | "21/730", "21/730S" |
| link | `<a href="…pdf" target="new">` | `https://www.bremische-buergerschaft.de/.../21/730.pdf` |
| typ | Regex vor Datum | "Antrag", "Änderungsantrag" |

### BW (PARLISAdapter — eUI async Polling, JSON-in-HTML)

| Feld | Quelle (Perl/JSON-Feld) | Beispiel |
|---|---|---|
| title | `WMV33` (Schlagworte, `<i>` gestrippt) / Fallback `EWBV23` | "Energiewirtschaft; Stromversorgung" |
| datum | `EWBV23` → Regex DD.MM.YYYY → ISO | "16.03.2026" → "2026-03-16" |
| fraktionen | `WMV30` (Kurz-Urheber) → `extract_fraktionen()` | "Felix Herkens (GRÜNE) u. a." → `["GRÜNE"]` |
| drucksache | `EWBV22` oder `EWBD01` → Regex | "17/10323" |
| link | `EWBD05[0].main` (direkte PDF-URL) | `https://parlis.landtag-bw.de/.../17_10323.pdf` |
| typ | Fest: `document_typ="Antrag"` (in `lines.l4`) | "Antrag" |

### BY (BayernAdapter — TYPO3-Solr HTML)

| Feld | Quelle (HTML-Regex) | Beispiel |
|---|---|---|
| title | `<h5><strong>…</strong></h5>` | "Kostenloses Parken für E-Fahrzeuge aufheben" |
| datum | `<h4>` "Drucksache Nr. 19/11407 vom 08.04.2026" DD.MM.YYYY → ISO | "08.04.2026" → "2026-04-08" |
| fraktionen | `<p>` "Antrag AfD" → `extract_fraktionen()` | "Antrag CSU, FREIE WÄHLER" → `["CSU", "FW-BAYERN"]` |
| drucksache | `<h4>` Regex | "19/11407" |
| link | `<a href="…pdf">` (absolute URL) | `https://www.bayern.landtag.de/.../0000009107.pdf` |
| typ | Erstes Wort aus `<p>` | "Antrag" |

### SL (SaarlandAdapter — Umbraco JSON)

| Feld | Quelle (JSON-Feld) | Beispiel |
|---|---|---|
| title | `Title` | "Schule als Lern- und Bildungsort weiter stärken" |
| datum | `PublicDate` ISO-Format, erste 10 Zeichen | "2022-05-12T00:00:00" → "2022-05-12" |
| fraktionen | `Publisher` + `DocumentAuthor` → `extract_fraktionen()` | Publisher "CDU" → `["CDU"]` |
| drucksache | `DocumentNumber` | "17/11" |
| link | `FilePath` mit `/file.ashx` → `/Downloadfile.ashx` Rewrite | `https://www.landtag-saar.de/Downloadfile.ashx?FileId=14230&FileName=Ag17_0011.pdf` |
| typ | `DocumentType` | "Antrag", "Anfrage", "Gesetzentwurf" |

### SN (SNEdasXmlAdapter — Manueller XML-Export)

| Feld | Quelle (XML-Element) | Beispiel |
|---|---|---|
| title | `<Titel>` (CDATA) | "Geschäftsordnung des Sächsischen Landtags" |
| datum | `<Fundstelle>` → Regex "datum"-Gruppe, DD.MM.YYYY → ISO | "01.10.2024" → "2024-10-01" |
| fraktionen | `<Fundstelle>` → Regex "urheber"-Gruppe → `extract_fraktionen()` | "CDU, BSW, SPD" → `["CDU", "BSW", "SPD"]` |
| drucksache | `f"{Wahlperiode}/{Dokumentennummer}"` | "8/2" |
| link | Konstruiert: `.../viewer.aspx?dok_nr={nr}&dok_art=Drs&leg_per={wp}` (PDF wird on-demand aus Iframe gelöst) | `https://edas.landtag.sachsen.de/.../viewer.aspx?dok_nr=2&dok_art=Drs&leg_per=8` |
| typ | Fest: "Antrag" | "Antrag" |

### BUND (BundestagAdapter — DIP REST-API)

| Feld | Quelle (JSON-Feld) | Beispiel |
|---|---|---|
| title | `titel` | "Förderung von Genossenschaften im sozialen Bereich" |
| datum | `datum` (bereits ISO YYYY-MM-DD) | "2026-04-08" |
| fraktionen | `urheber[*].titel` → `extract_fraktionen()` | "Fraktion der AfD" → `["AfD"]` |
| drucksache | `dokumentnummer` | "21/5136" |
| link | `fundstelle.pdf_url` | `https://dip.bundestag.de/documents/btd/21/051/2105136.pdf` |
| typ | `drucksachetyp` (server-side gefiltert) | "Antrag" |

## Gemeinsames Pattern

Alle Adapter normalisieren Fraktionen über den zentralen `parteien.extract_fraktionen(text, bundesland=...)` Mapper (#55). Alle konvertieren DE-Datumsformat (DD.MM.YYYY) nach ISO (YYYY-MM-DD), außer BUND (schon ISO) und SL (schon ISO mit T-Suffix).

## Historien-Tiefe (ältere WPs)

Alle Adapter sind aktuell auf **eine feste Wahlperiode** konfiguriert.
Keiner unterstützt Queries über mehrere WPs hinweg. Ältere Drucksachen
aus früheren WPs sind nicht abrufbar ohne Adapter-Rekonfiguration.

Für eine künftige Multi-WP-Suche müsste pro Adapter geprüft werden, ob
das Backend WP-übergreifende Queries unterstützt:

| API-Typ | Multi-WP möglich? |
|---|---|
| portala/eUI | Ja (WP-Term aus dem JSON-Tree weglassen) |
| ParlDok | Ja (`facet_lp` weglassen) |
| StarFinder/PARiS | Ja (WP-Param weglassen) |
| TYPO3-Solr (BY) | Ja (`wahlperiodeid[]` weglassen) |
| DIP-API (BUND) | Ja (`f.wahlperiode` weglassen) |
| Umbraco (SL) | Ja (`Filter.Periods=[]`) |
| EDAS-XML (SN) | Nur innerhalb des exportierten Datenbestands |

## Fehlende Adapter

| BL | Status | Blocker |
|---|---|---|
| **NI** (Niedersachsen) | Issue #22 offen | NILAS-StarWeb erfordert Session-Cookie, HAR-Capture vom User nötig |
