chore: Release v0.11.0 (Szenario-Löschen, Grafana-Korrekturen, Tabellensortierung)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-09-28 19:34:18 +02:00
co-authored by Claude Opus 5.5
parent b1e007ed15
commit b28b0e69c0
3 changed files with 66 additions and 5 deletions
+42 -1
View File
@@ -37,7 +37,8 @@ flowchart TD
S_balances["balances.py<br/>account_balance(at), total_balance"]
S_categorize["categorize.py<br/>apply_rules"]
S_suggestions["suggestions.py<br/>suggest_recurring"]
S_projection["projection_service.py<br/>run_projection"]
S_projection["projection_service.py<br/>run_projection, refresh_stale_projections"]
S_planning_chart["planning_chart.py<br/>refresh_planning_chart"]
S_admin["admin.py<br/>change_password, apply_rules_retroactively"]
end
@@ -75,6 +76,8 @@ flowchart TD
R_gui --> E_loans
R_gui --> E_recurrence
R_gui --> S_balances
R_gui --> S_projection
R_gui --> S_planning_chart
R_admin --> R_gui
R_accounts --> S_balances
@@ -96,6 +99,9 @@ flowchart TD
S_projection --> E_projection
S_projection --> E_scenario
S_projection --> S_balances
S_planning_chart --> E_loans
S_planning_chart --> E_recurrence
S_planning_chart --> M_tables
S_admin --> S_categorize
E_scenario --> E_loans
@@ -300,6 +306,41 @@ ist die einzige Brücke: es lädt ORM-Objekte (`Loan`, `RecurringItem`,
`PlannedItem`, `Scenario`, `ScenarioModifier`), baut daraus die Plain-Objekte
und ruft `engine.scenario.build_cashflows` → `engine.projection.project`.
**`v_projection` (Ausbaustufe 11) — System-Ist + Szenarien ab heute.**
`models/views.py::VIEWS["v_projection"]` liefert für den Grafana-Szenario-
Vergleich drei Teile in einer Tabelle: die Ist-Gesamtsaldo-Serie unter dem
Namen `RESERVED_SCENARIO_NAME` (`"System-Ist"`, aus `v_balance_total`, endet
heute), je bereits durchgerechnetem Szenario einen Startpunkt exakt heute
(Ist-Saldo, damit die Kurve nahtlos ansetzt) sowie dessen gespeicherte
Projektionspunkte NACH heute (`projection_points`, `day > CURRENT_DATE`) —
Punkte <= heute aus einer älteren Berechnung erscheinen so nie.
`RESERVED_SCENARIO_NAME` ist für Szenario-Namen gesperrt:
`routers/scenarios.py::_check_reserved_name` lehnt `POST`/`PATCH` mit diesem
Namen (case-insensitiv) mit 422 ab.
**Abgeleitete Tabellen + Advisory-Locks (Ausbaustufe 11).** Zwei Datenstände
werden bei GUI-Seitenaufrufen automatisch aufgefrischt, nie beim reinen
API-Zugriff (`routers/gui.py::_safe_refresh`, fehlerresistent — ein Fehler
rollt zurück, loggt und lässt die Seite mit dem alten Stand rendern):
`services/projection_service.py::refresh_stale_projections` rechnet jedes
bereits durchgerechnete, aber veraltete Szenario mit dem Standard-Horizont
neu (Advisory-Lock `STALE_PROJECTION_LOCK = 110_001`), aufgerufen von
`index` und `szenarien_page`. `services/planning_chart.py::refresh_planning_chart`
schreibt die Tabelle `planning_monthly` (`models/tables.py::PlanningMonthly`,
Migration `d5e8b3c7a410`) komplett neu — Monatssummen je Kategorie aus
Planung (wiederkehrende Posten, Einmalposten, Kreditraten aller Kredite
unter Kategorie „Kreditraten") für das Grafana-Panel „Planung nach
Kategorie" (`Advisory-Lock PLANNING_CHART_LOCK = 110_002`), aufgerufen von
`index` und `planung_page`. Beide Tabellen sind jederzeit reproduzierbar
(kein Backup-Sonderfall).
**Tabellensortierung (Ausbaustufe 11).** `static/sort.js` sortiert generische
Tabellen client-seitig per Spaltenkopf-Klick (⇅/▲/▼, deutsche Zahlen-/
Datumsformate, `htmx.onLoad`-Reinit für nachgeladene Fragmente) — Ausnahme
`table[data-sort-mode="server"]`. Die Buchungsliste (`/buchungen`) ist so
markiert und sortiert stattdessen serverseitig über alle Seiten
(`routers/transactions.py::SORT_COLUMNS`, `normalize_sort`, `_apply_sort`).
**`VERSION`-Datei als Single Source.** `finance/VERSION` (ein Einzeiler, z.B.
`0.4.0`) ist die einzige Versionsquelle: `app/version.py::get_version()`
liest sie (Fallback `"0.0.0-dev"`), gespeist in den Jinja2-Footer