diff --git a/Changes.md b/Changes.md
index 86929db..9707574 100644
--- a/Changes.md
+++ b/Changes.md
@@ -2,6 +2,11 @@
---
+## 2026-10-12 – Bank buchen: älteste Umsätze zuerst (#219)
+
+- **`src/Models/BankTransaction.php`** (`all()`) **und `src/Views/bank/index.php`:** Die Standard-Sortierrichtung ist jetzt aufsteigend statt absteigend – ohne `dir`-Parameter erscheinen die ältesten Umsätze oben, damit datumsgetreu gebucht wird und die Buchungsnummern zeitlich fortlaufend entstehen. Im Filter ist „↑ Aufsteigend“ vorbelegt; „↓ Absteigend“ bleibt über `dir=desc` wählbar, unbekannte Werte fallen auf aufsteigend zurück.
+- **`tests/104_BankSortierungAeltesteZuerstTest.php`** (neu) und **`tests/e2e/specs/bank-sortierung.spec.js`** (neu): prüfen die Standardreihenfolge, `dir=desc` und die Vorbelegung im Filter.
+
## 2026-10-06 – Header-Injection über Dateinamen im Content-Disposition-Header behoben (#217)
- **`src/View.php`:** neue Methode `View::contentDispositionHeader(string $disposition, string $filename): string`. `PATHINFO_BASENAME` entfernt beim Beleg-Upload nur Verzeichnisanteile, nicht aber Anführungszeichen oder Backslashes im client-seitig gewählten Dateinamen – ein präparierter Name wie `legit"; filename*=UTF-8''%2e%2e%2fevil.exe` brach beim Download aus dem `filename="..."`-Parameter aus und schleuste einen zusätzlichen, von vielen Browsern bevorzugt ausgewerteten `filename*=`-Parameter ein. Damit ließ sich der im Download-Dialog angezeigte Dateiname/die Endung gegenüber anderen Nutzern fälschen (Dateityp-Spoofing). Die neue Methode maskiert Anführungszeichen, Backslashes und Steuerzeichen im ASCII-`filename`-Parameter und setzt zusätzlich RFC-6266-konform `filename*=UTF-8''...` mit dem unveränderten, `rawurlencode()`-kodierten Namen.
diff --git a/docs/funktionen.md b/docs/funktionen.md
index 6b0e39f..a7909d0 100644
--- a/docs/funktionen.md
+++ b/docs/funktionen.md
@@ -106,6 +106,7 @@ Anlagenspiegel für abnutzbare Wirtschaftsgüter – siehe [anlagevermögen.md](
- **Beleg-Zuordnung**: jede Banktransaktion kann einem oder mehreren Belegen zugeordnet werden; der zugeordnete Betrag wird separat erfasst
- **Teilzuordnung**: eine Transaktion kann schrittweise mehreren Belegen anteilig zugeordnet werden
- **Status-Logik**: `offen` → keine Zuordnung, `teilweise` → Restsaldo > 0,01 €, `gebucht` → vollständig zugeordnet
+- **Sortierung**: Die Liste unter `/bank` zeigt standardmäßig die ältesten Umsätze zuerst (Wertstellung aufsteigend), damit datumsgetreu gebucht wird und die Buchungsnummern zeitlich fortlaufend vergeben werden; Sortierfeld und Richtung (*Absteigend*) sind im Filter umstellbar
- Direkter Beleg-Upload aus der Transaktionsansicht heraus (erzeugt neuen Beleg und verknüpft ihn)
- **Verschlüsselung**: Der `APP_KEY` in `.env` ist Pflicht für Direktverbindungen – im Backup mitsichern, Verlust = Verlust aller gespeicherten Credentials
diff --git a/src/Models/BankTransaction.php b/src/Models/BankTransaction.php
index a464b8a..6065cd4 100644
--- a/src/Models/BankTransaction.php
+++ b/src/Models/BankTransaction.php
@@ -55,7 +55,7 @@ class BankTransaction
'status' => 'bt.status',
];
$sortCol = $sortMap[$filter['sort'] ?? ''] ?? 'bt.wertstellung';
- $sortDir = ($filter['dir'] ?? 'desc') === 'asc' ? 'ASC' : 'DESC';
+ $sortDir = ($filter['dir'] ?? 'asc') === 'desc' ? 'DESC' : 'ASC';
$whereStr = implode(' AND ', $where);
$offset = ($page - 1) * $perPage;
diff --git a/src/Views/bank/index.php b/src/Views/bank/index.php
index 8d2fe93..6dc12fe 100644
--- a/src/Views/bank/index.php
+++ b/src/Views/bank/index.php
@@ -86,8 +86,8 @@ $months = ['Jan','Feb','Mär','Apr','Mai','Jun','Jul','Aug','Sep','Okt','Nov','D
diff --git a/tests/104_BankSortierungAeltesteZuerstTest.php b/tests/104_BankSortierungAeltesteZuerstTest.php
new file mode 100644
index 0000000..9d1815d
--- /dev/null
+++ b/tests/104_BankSortierungAeltesteZuerstTest.php
@@ -0,0 +1,69 @@
+ array_column($result['rows'], 'wertstellung');
+
+ $standard = BankTransaction::all(['search' => $marker]);
+ $this->assertEquals(
+ ['2026-01-05', '2026-02-10', '2026-03-15'],
+ $daten($standard),
+ 'Ohne dir-Parameter: älteste Wertstellung zuerst'
+ );
+
+ $absteigend = BankTransaction::all(['search' => $marker, 'dir' => 'desc']);
+ $this->assertEquals(
+ ['2026-03-15', '2026-02-10', '2026-01-05'],
+ $daten($absteigend),
+ 'dir=desc: neueste Wertstellung zuerst'
+ );
+
+ $ungueltig = BankTransaction::all(['search' => $marker, 'dir' => 'quatsch']);
+ $this->assertEquals(
+ ['2026-01-05', '2026-02-10', '2026-03-15'],
+ $daten($ungueltig),
+ 'Ungültiger dir-Wert fällt auf aufsteigend zurück'
+ );
+
+ $view = (string)file_get_contents(dirname(__DIR__) . '/src/Views/bank/index.php');
+ $this->assert(
+ str_contains($view, "(\$filter['dir'] ?? 'asc') === 'asc'"),
+ 'Filterauswahl zeigt „Aufsteigend“ als Vorbelegung'
+ );
+ $this->assert(
+ !str_contains($view, "(\$filter['dir'] ?? 'desc')"),
+ 'Filterauswahl belegt nicht mehr „Absteigend“ vor'
+ );
+ }
+}
diff --git a/tests/e2e/specs/bank-sortierung.spec.js b/tests/e2e/specs/bank-sortierung.spec.js
new file mode 100644
index 0000000..a04dd6f
--- /dev/null
+++ b/tests/e2e/specs/bank-sortierung.spec.js
@@ -0,0 +1,18 @@
+// @ts-check
+// „Bank buchen“ sortiert standardmäßig älteste zuerst (Issue #219): Ohne
+// Parameter ist im Filter „Aufsteigend“ vorbelegt, „Absteigend“ bleibt wählbar.
+
+const { test, expect } = require('@playwright/test')
+const { gotoOk } = require('../helpers/app')
+
+test.describe('Bank buchen – Sortierrichtung', () => {
+ test('ohne Parameter ist „Aufsteigend“ vorbelegt', async ({ page }) => {
+ await gotoOk(page, '/bank')
+ await expect(page.locator('select[name="dir"]')).toHaveValue('asc')
+ })
+
+ test('dir=desc bleibt ausgewählt', async ({ page }) => {
+ await gotoOk(page, '/bank?dir=desc')
+ await expect(page.locator('select[name="dir"]')).toHaveValue('desc')
+ })
+})