gwoe-antragspruefer/app/templates/monitoring_digest.html
Dotty Dotter 2c0e94d29d feat(#106,#135,#128): Monitoring + abgeordnetenwatch + Wahlprogramm-Check
- monitoring.py: taeglicher Scan-Adapter aller aktiven BL, kein Auto-Fetch (#135)
- monitoring_digest.html: Mail-Template mit '0-Kontext'-Hinweis
- abgeordnetenwatch.py + sync_*.py: Phase 1 Roll-Call-Voting (#106)
  - 17 Parlamente (16 BL + BT)
  - 9 BL-spezifische Drucksachen-Patterns + Date-Title-Fallback
  - 28977 Votes fuer BUND in DB
- wahlprogramm_check.py: fehlende Programme erkennen (#128)
- NI-Skip-Liste, NRW Empty-Query-Fallback

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 20:55:16 +02:00

129 lines
5.4 KiB
HTML

<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>GWÖ-Monitor {{ scan_date }}</title>
</head>
<body style="font-family:Helvetica,Arial,sans-serif;max-width:640px;margin:0 auto;padding:20px;color:#333">
<h2 style="color:#007a80;margin-bottom:4px">GWÖ-Antragsprüfer — Monitoring {{ scan_date }}</h2>
<p style="color:#666;margin-top:4px;font-size:0.9em">Täglicher Scan aller aktiven Bundesländer</p>
{% if new_total == 0 %}
<div style="background:#f0fafa;border-left:3px solid #009da5;padding:10px 14px;margin:12px 0;font-size:0.95em;color:#444">
<b style="color:#007a80">Heute keine Änderungen.</b> Alle {{ total_seen }} in den Landtags-Portalen sichtbaren Drucksachen sind bereits seit dem letzten Scan bekannt. Das heißt: die Portale haben seit gestern keine neuen Anträge publiziert — nicht: der Scan war erfolglos.
</div>
{% endif %}
<!-- Kennzahlen-Block -->
<table style="width:100%;border-collapse:collapse;margin:16px 0">
<tr style="background:#f0fafa">
<td style="padding:10px 14px;border:1px solid #c8e6e6;font-weight:bold">Neue Drucksachen seit letztem Scan</td>
<td style="padding:10px 14px;border:1px solid #c8e6e6;font-size:1.4em;color:#007a80;font-weight:bold">{{ new_total }}</td>
</tr>
<tr>
<td style="padding:10px 14px;border:1px solid #ddd">Im Portal aktuell sichtbar (inkl. bekannter)</td>
<td style="padding:10px 14px;border:1px solid #ddd">{{ total_seen }}</td>
</tr>
<tr style="background:#fffbf0">
<td style="padding:10px 14px;border:1px solid #ddd">Kosten-Schätzung (alle analysieren)</td>
<td style="padding:10px 14px;border:1px solid #ddd">
<b>{{ "%.4f"|format(estimated_cost_eur) }} EUR</b>
<span style="font-size:0.8em;color:#888">&nbsp;(Qwen Plus, Näherung)</span>
</td>
</tr>
{% if errors %}
<tr style="background:#fff3f3">
<td style="padding:10px 14px;border:1px solid #f5c0c0;color:#c00">Adapter-Fehler</td>
<td style="padding:10px 14px;border:1px solid #f5c0c0;color:#c00;font-weight:bold">{{ errors|length }}</td>
</tr>
{% endif %}
</table>
<!-- Fehler-Details -->
{% if errors %}
<div style="background:#fff3f3;border-left:3px solid #c00;padding:10px 14px;margin:12px 0">
<b style="color:#c00">Fehler-Details:</b>
<ul style="margin:6px 0 0;padding-left:18px;font-size:0.9em">
{% for e in errors %}
<li>{{ e }}</li>
{% endfor %}
</ul>
</div>
{% endif %}
<!-- Bundesland-Übersicht -->
<h3 style="color:#007a80;border-bottom:1px solid #c8e6e6;padding-bottom:6px">Bundesland-Übersicht</h3>
<table style="width:100%;border-collapse:collapse;font-size:0.9em">
<thead>
<tr style="background:#e6f4f4">
<th style="padding:7px 10px;border:1px solid #c8e6e6;text-align:left">BL</th>
<th style="padding:7px 10px;border:1px solid #c8e6e6;text-align:right">Gesehen</th>
<th style="padding:7px 10px;border:1px solid #c8e6e6;text-align:right">Neu</th>
<th style="padding:7px 10px;border:1px solid #c8e6e6;text-align:left">Status</th>
</tr>
</thead>
<tbody>
{% for r in results %}
<tr style="{% if r.error %}background:#fff8f8{% elif r.new_count > 0 %}background:#f8fff8{% endif %}">
<td style="padding:6px 10px;border:1px solid #ddd;font-weight:bold">{{ r.bundesland }}</td>
<td style="padding:6px 10px;border:1px solid #ddd;text-align:right">{{ r.total_seen }}</td>
<td style="padding:6px 10px;border:1px solid #ddd;text-align:right;color:{% if r.new_count > 0 %}#007a80{% else %}#999{% endif %}">
{{ r.new_count }}
</td>
<td style="padding:6px 10px;border:1px solid #ddd;font-size:0.85em">
{% if r.error %}
<span style="color:#c00">✗ {{ r.error[:100] }}</span>
{% elif r.new_count > 0 %}
<span style="color:#2a7a2a">✓ {{ r.new_count }} neue</span>
{% else %}
<span style="color:#999">keine Änderung</span>
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
<!-- Neue Drucksachen -->
{% if new_docs %}
<h3 style="color:#007a80;border-bottom:1px solid #c8e6e6;padding-bottom:6px;margin-top:24px">
Neue Drucksachen ({{ new_docs|length }})
</h3>
{% for doc in new_docs[:30] %}
<div style="border-left:3px solid #007a80;padding:6px 12px;margin:8px 0;background:#f9f9f9;font-size:0.9em">
<span style="color:#007a80;font-weight:bold">{{ doc.bundesland }}</span>
<span style="color:#555;margin-left:8px">{{ doc.drucksache }}</span>
{% if doc.datum %}
<span style="color:#888;font-size:0.85em;margin-left:8px">{{ doc.datum }}</span>
{% endif %}
<br>
<span style="color:#333">{{ (doc.title or doc.drucksache or '')[:120] }}</span>
{% if doc.fraktionen %}
<br><span style="color:#777;font-size:0.85em">
{% if doc.fraktionen is iterable and doc.fraktionen is not string %}
{{ doc.fraktionen | join(', ') }}
{% else %}
{{ doc.fraktionen }}
{% endif %}
</span>
{% endif %}
</div>
{% endfor %}
{% if new_docs|length > 30 %}
<p style="color:#666;font-size:0.9em">… und {{ new_docs|length - 30 }} weitere neue Drucksachen.</p>
{% endif %}
{% else %}
<p style="color:#888;font-style:italic">Keine neuen Drucksachen heute.</p>
{% endif %}
<!-- Footer -->
<hr style="border:none;border-top:1px solid #ddd;margin:24px 0">
<p style="font-size:0.8em;color:#aaa">
GWÖ-Antragsprüfer Monitoring &middot; Kosten-Schätzung basiert auf Qwen-Plus-Preisen (DashScope, April 2026) &middot;
Nur Metadaten — kein LLM-Call im Scan
</p>
</body>
</html>