diff --git a/Changes.md b/Changes.md
index f36bb60..2923240 100644
--- a/Changes.md
+++ b/Changes.md
@@ -2,6 +2,21 @@
---
+## 2026-07-26 – Feature: Dritte Eingabezeile ohne USt. in der Essensbeleg-Buchungsvorlage (Issue #140)
+
+- Die Buchungsvorlage „Essensbeleg n. abzugsfähig (nur USt.)" hatte nur Eingabezeilen für 7 % und 19 % USt. – Beträge ohne USt. (z. B. Trinkgeld) ließen sich damit nicht erfassen.
+- **`migrations/088_buchungsvorlage_essensbeleg_ohne_ust.sql`:** Ergänzt die Vorlage um ein drittes `ust_zeile`-Feld `netto_0` (0 % USt.) sowie eine Buchungsregel, die den eingegebenen Betrag auf Konto 4657 („Nicht abzugsfähige Bewirtungskosten ohne Vorsteuer") bucht – Formular-Rendering (`buchungsvorlagen/modal.php`), Live-Berechnung (`app.js`) und Buchungsausführung (`VorlageBuchungsService`) sind bereits vollständig datengetrieben und benötigten keine Code-Änderung.
+- **`tests/59_EssensbelegOhneUstTest.php`:** Neuer Test prüft das neue Feld, die zugehörige Regel und die korrekte Buchung auf Konto 4657 bei gleichzeitiger Nutzung aller drei Zeilen.
+
+## 2026-07-26 – Feature: Ereignisanzeige aktualisiert sich automatisch (Issue #139)
+
+- Die Ereignisanzeige (`/ereignisse/nextcloud-import`) war statisch – neu geloggte Ereignisse erschienen erst nach manuellem Neuladen der Seite.
+- **`src/Controllers/EventController.php`:** Neue Methode `nextcloudImportData()` liefert die aktuellen Ereignisse als JSON (Anzahl + serverseitig gerendertes HTML-Fragment), damit initiale Seite und Auto-Reload denselben Rendering-Code (`ereignisse/_nextcloud_import_body.php`) verwenden.
+- **`src/Views/ereignisse/_nextcloud_import_body.php`:** Tabellen-/Leer-Markup aus `nextcloud_import.php` in ein Partial ausgelagert, das von initialer Seite und Datenendpunkt gemeinsam genutzt wird.
+- **`src/Views/ereignisse/nextcloud_import.php`:** Neuer Ein-/Aus-Button oben rechts in der Kartenkopfzeile schaltet automatisches Neuladen per `setInterval` (alle 60s, ohne externe Bibliothek) ein/aus; Zustand wird per `localStorage` gemerkt. Ein echter Push-Mechanismus (z. B. Server-Sent Events) hätte dauerhafte PHP-FPM-Worker gebunden – bei diesem Anwendungsfall (Log-Anzeige) ist periodisches Polling die robustere Lösung.
+- **`public/index.php`:** Neue Route `GET /ereignisse/nextcloud-import/data`.
+- **`tests/58_EreignisAutoReloadTest.php`:** Neuer Test prüft Button, Polling-Code, Partial-Wiederverwendung und Routen-Registrierung.
+
## 2026-07-21 – Fix: Zwei dauerhaft fehlschlagende Tests (Session-Cookie-Härtung, Nextcloud-SSRF)
- **Test 54 (Session-Cookie-Härtung):** Der Test rief echtes `Auth::startSession()` auf. Da `tests/run.php` Ergebnisse laufend per `echo` ausgibt und Test 54 der einzige Test ist, der Sessions anfasst, war zum Testzeitpunkt bereits Output gesendet – PHP lehnt `session_set_cookie_params()`/`session_start()` danach mit „headers already sent" ab (Warnung + wirkungslos). Ein nachträglicher Output-Buffer im Test half nicht, da bereits vor dem Test unbuffered Output geflossen war.
diff --git a/docs/funktionen.md b/docs/funktionen.md
index c54da1c..5bc5025 100644
--- a/docs/funktionen.md
+++ b/docs/funktionen.md
@@ -16,6 +16,7 @@ Vollständige Kontenliste: [kontenrahmen.md](kontenrahmen.md)
- KI-gestützter Kontierungsvorschlag (optional, siehe [konfiguration.md](konfiguration.md))
- Nextcloud-Import via WebDAV (optional)
- Belege können nicht gelöscht werden, solange Buchungen darauf verweisen (GoBD)
+- **Ereignisanzeige** (`/ereignisse/nextcloud-import`): Log der letzten 500 Import-Ereignisse (importiert/übersprungen/Fehler); aktualisiert sich per Ein-/Aus-Button oben rechts automatisch alle 60 Sekunden (Zustand wird im Browser gemerkt)
---
diff --git a/migrations/088_buchungsvorlage_essensbeleg_ohne_ust.sql b/migrations/088_buchungsvorlage_essensbeleg_ohne_ust.sql
new file mode 100644
index 0000000..ceeb9bb
--- /dev/null
+++ b/migrations/088_buchungsvorlage_essensbeleg_ohne_ust.sql
@@ -0,0 +1,21 @@
+-- 088_buchungsvorlage_essensbeleg_ohne_ust.sql
+-- Ergänzt die Vorlage "Essensbeleg n. abzugsfähig (nur USt.)" um eine dritte
+-- Eingabezeile für Beträge ohne USt. (z.B. Trinkgeld).
+-- Idempotent: Feld/Regel werden nur angelegt wenn nicht vorhanden.
+
+SET @vorlage_name = 'Essensbeleg n. abzugsfähig (nur USt.)';
+SET @vid = (SELECT id FROM buchungsvorlagen WHERE name = @vorlage_name LIMIT 1);
+
+INSERT INTO buchungsvorlage_felder (vorlage_id, gruppe_nr, sort_order, feldname, label, typ, ust_satz, meta_key)
+SELECT @vid, 2, 30, 'netto_0', '0% USt. (z.B. Trinkgeld)', 'ust_zeile', 0.00, NULL
+WHERE @vid IS NOT NULL
+ AND NOT EXISTS (SELECT 1 FROM buchungsvorlage_felder WHERE vorlage_id = @vid AND feldname = 'netto_0');
+
+-- Regel: Betrag ohne USt. → nicht abzugsfähige Bewirtungskosten ohne Vorsteuer (Konto 4657)
+INSERT INTO buchungsvorlage_regeln (vorlage_id, sort_order, bedingung_feld, bedingung_op, buchungen)
+SELECT @vid, 30, 'netto_0', 'neq_zero',
+ JSON_ARRAY(
+ JSON_OBJECT('betrag_ref', 'netto_0', 'nach_konto', '4657')
+ )
+WHERE @vid IS NOT NULL
+ AND NOT EXISTS (SELECT 1 FROM buchungsvorlage_regeln WHERE vorlage_id = @vid AND bedingung_feld = 'netto_0');
diff --git a/public/index.php b/public/index.php
index 09b54ef..3eb7d8a 100644
--- a/public/index.php
+++ b/public/index.php
@@ -186,8 +186,9 @@ $router->get('/api/buchungsvorlagen/{id}/modal', fn($p) =
$router->post('/belege/{belegId}/vorlage/{vorlageId}/buchen', fn($p) => (new BuchungsvorlageController())->buchen($p));
// ── Ereignisse ───────────────────────────────────────────────
-$router->get('/ereignisse', fn($p) => (new EventController())->index($p));
-$router->get('/ereignisse/nextcloud-import', fn($p) => (new EventController())->nextcloudImport($p));
+$router->get('/ereignisse', fn($p) => (new EventController())->index($p));
+$router->get('/ereignisse/nextcloud-import', fn($p) => (new EventController())->nextcloudImport($p));
+$router->get('/ereignisse/nextcloud-import/data', fn($p) => (new EventController())->nextcloudImportData($p));
// ── Login / Logout ────────────────────────────────────────────
$router->get('/login', fn($p) => (new LoginController())->showLogin($p));
diff --git a/src/Controllers/EventController.php b/src/Controllers/EventController.php
index c989236..c077783 100644
--- a/src/Controllers/EventController.php
+++ b/src/Controllers/EventController.php
@@ -22,8 +22,24 @@ class EventController extends BaseController
$view->render('layout/base.php', [
'pageTitle' => 'Ereignisse – Nextcloud-Import',
'content' => $this->renderView('ereignisse/nextcloud_import', [
- 'events' => $events,
+ 'events' => $events,
+ 'eventsHtml' => $this->renderView('ereignisse/_nextcloud_import_body', [
+ 'events' => $events,
+ ]),
]),
]);
}
+
+ public function nextcloudImportData(array $params): void
+ {
+ $events = EventLog::findByChannel('nextcloud-import', 500);
+
+ header('Content-Type: application/json');
+ echo json_encode([
+ 'count' => count($events),
+ 'html' => $this->renderView('ereignisse/_nextcloud_import_body', [
+ 'events' => $events,
+ ]),
+ ], JSON_UNESCAPED_UNICODE);
+ }
}
diff --git a/src/Views/ereignisse/_nextcloud_import_body.php b/src/Views/ereignisse/_nextcloud_import_body.php
new file mode 100644
index 0000000..2e19645
--- /dev/null
+++ b/src/Views/ereignisse/_nextcloud_import_body.php
@@ -0,0 +1,28 @@
+ View::h($v); ?>
+
+
Keine Ereignisse vorhanden. Einträge entstehen, sobald der Nextcloud-Import Dateien importiert, überspringt oder auf Fehler stößt.