diff --git a/docs/ARCHITEKTUR.md b/docs/ARCHITEKTUR.md index a0ff060..dec8161 100644 --- a/docs/ARCHITEKTUR.md +++ b/docs/ARCHITEKTUR.md @@ -40,8 +40,11 @@ flowchart TD S_projection["projection_service.pyrun_projection, refresh_stale_projections"] S_planning_chart["planning_chart.pyrefresh_planning_chart"] S_admin["admin.pychange_password, apply_rules_retroactively"] + S_doublecount["double_count.pyall_conflicts, conflicts_for_recurring,conflicts_for_loan"] end + N_reserved["app/reserved.pycheck_reserved_name"] + subgraph ENGINE["engine/ (rein, kein DB-Zugriff)"] E_loans["loans.pyloan_schedule, annuity_payment, add_months"] E_recurrence["recurrence.pyoccurrences"] @@ -86,7 +89,11 @@ flowchart TD R_imports --> S_importer R_planning --> E_loans R_planning --> S_suggestions + R_planning --> S_doublecount R_scenarios --> S_projection + R_scenarios --> N_reserved + R_categories --> N_reserved + R_gui --> S_doublecount R_admin --> S_admin ROUTERS -.-> M_tables @@ -315,9 +322,36 @@ heute), je bereits durchgerechnetem Szenario einen Startpunkt exakt heute 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 +`app/reserved.py::check_reserved_name` lehnt `POST`/`PATCH` mit diesem Namen (case-insensitiv) mit 422 ab. +**Präfix `System-` reserviert (Ausbaustufe 12).** `app/reserved.py` +(`SYSTEM_PREFIX = "System-"`, `is_reserved_name`, `check_reserved_name`) +sperrt diesen Präfix für Kategorie- und Szenario-Namen (`routers/categories.py`, +`routers/scenarios.py`, je `check_reserved_name` auf `POST`/`PATCH`, 422 bei +Verstoß) — er gehört den vom Tool erzeugten Serien `RESERVED_SCENARIO_NAME` +(`"System-Ist"`, `models/views.py`) und `services/planning_chart.py::KREDITRATEN` +(`"System-Kreditraten"`). + +**Doppelzählungs-Erkennung Kredit ↔ Fixposten (Ausbaustufe 12).** +`app/services/double_count.py` erkennt, wenn ein monatlicher Ausgabe-Posten +(`RecurringItem`, `rhythm == "monthly"`) betraglich vermutlich einer regulären +Kreditrate (`regular_rate`, Annuität bzw. bei endfälligen Krediten die +monatlichen Zinsen) entspricht — Toleranz `max(TOLERANZ_MIN=1.00, +rate * TOLERANZ_PROZENT=3 / 100)` — und sich die Zeiträume überschneiden +(`rate_period`). `routers/planning.py` ruft `conflicts_for_recurring` bzw. +`conflicts_for_loan` bei `POST`/`PATCH` auf `/api/recurring` und +`/api/loans` auf; ohne `doppelzaehlung_bestaetigt: true` im Request-Body +antwortet es mit `409` (`detail.code == "doppelzaehlung_kredit"`, Konstante +`CODE`). `static/doppelzaehlung.js` fängt genau diesen 409 im globalen +`htmx:responseError`-Handler ab und zeigt das `` aus `base.html`; „Trotzdem speichern“ markiert das +Formular (`data-doppelzaehlung-bestaetigt="1"`) und sendet es erneut, die +`json-form`-Erweiterung ergänzt dabei `doppelzaehlung_bestaetigt: true`. +`routers/gui.py::planung_page` ruft zusätzlich `all_conflicts` auf und zeigt +einen dauerhaften ⚠-Hinweis je betroffenem Posten/Kredit in `planning.html`, +solange der Konflikt fortbesteht. + **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 diff --git a/finance/VERSION b/finance/VERSION index a0bbdef..15d9519 100644 --- a/finance/VERSION +++ b/finance/VERSION @@ -1 +1 @@ -0.11.0 +0.12.0 diff --git a/finance/app/templates/hilfe.html b/finance/app/templates/hilfe.html index c45ad0d..f273850 100644 --- a/finance/app/templates/hilfe.html +++ b/finance/app/templates/hilfe.html @@ -87,12 +87,33 @@ Kategorie, der Szenario-Vergleich als Kurven (darin die Ist-Kurve „System-Ist“ bis heute, ab heute je Szenario weiter) und das Panel „Planung nach Kategorie“ (Monatssummen aus der reinen Planung inkl. - Kreditraten, ohne Szenario-Modifikatoren) – einmal mit demselben + „System-Kreditraten“, ohne Szenario-Modifikatoren) – einmal mit demselben Passwort wie hier anmelden, dann erscheint das Dashboard auch in der Übersicht. + + Reservierte Namen: Kategorien und Szenarien dürfen nicht + mit „System-“ beginnen – dieses Präfix ist für vom Tool erzeugte Einträge + reserviert (z. B. die Ist-Serie „System-Ist“ und die Kreditraten-Serie + „System-Kreditraten“ in Grafana). Ein Versuch, einen eigenen Namen mit + diesem Präfix anzulegen, wird abgelehnt. + + + + Doppelzählungs-Warnung: beim Anlegen oder Ändern eines + wiederkehrenden Postens oder eines Kredits prüft das Tool, ob ein + monatlicher Ausgabe-Posten ungefähr einer regulären Kreditrate entspricht + (Betrag innerhalb ±3 %, mindestens 1 €, mit überlappendem Zeitraum). Trifft + das zu, erscheint ein Warnfenster – erst ein Klick auf „Trotzdem + speichern“ übernimmt den Eintrag. Solange der Konflikt bestehen bleibt, + zeigt die Planungs-Seite dauerhaft einen ⚠-Hinweis bei den betroffenen + Posten und Krediten an. Am saubersten lässt sich das vermeiden, wenn + Kreditraten ausschließlich über „Kredite“ gepflegt werden statt zusätzlich + als wiederkehrender Posten. + + Tabellen sortieren: ein Klick auf einen Spaltenkopf sortiert die Tabelle danach (⇅ unsortiert, ▲ aufsteigend, ▼ absteigend);
+ Reservierte Namen: Kategorien und Szenarien dürfen nicht + mit „System-“ beginnen – dieses Präfix ist für vom Tool erzeugte Einträge + reserviert (z. B. die Ist-Serie „System-Ist“ und die Kreditraten-Serie + „System-Kreditraten“ in Grafana). Ein Versuch, einen eigenen Namen mit + diesem Präfix anzulegen, wird abgelehnt. +
+ Doppelzählungs-Warnung: beim Anlegen oder Ändern eines + wiederkehrenden Postens oder eines Kredits prüft das Tool, ob ein + monatlicher Ausgabe-Posten ungefähr einer regulären Kreditrate entspricht + (Betrag innerhalb ±3 %, mindestens 1 €, mit überlappendem Zeitraum). Trifft + das zu, erscheint ein Warnfenster – erst ein Klick auf „Trotzdem + speichern“ übernimmt den Eintrag. Solange der Konflikt bestehen bleibt, + zeigt die Planungs-Seite dauerhaft einen ⚠-Hinweis bei den betroffenen + Posten und Krediten an. Am saubersten lässt sich das vermeiden, wenn + Kreditraten ausschließlich über „Kredite“ gepflegt werden statt zusätzlich + als wiederkehrender Posten. +
Tabellen sortieren: ein Klick auf einen Spaltenkopf sortiert die Tabelle danach (⇅ unsortiert, ▲ aufsteigend, ▼ absteigend);