Modul-Review 3: Struktur, Dashboard, CSV-Export und Grafiken
Deploy App / deploy (push) Successful in 1m59s
Deploy App / deploy (push) Successful in 1m59s
Versionierung: - startet neu bei 0.1; erst eine gesetzte Hauptversion macht daraus 1.0 - Szenario-Liste zeigt die echte Version (z.B. 0.17) statt "1.x", plus neue Spalte "Phasen" - Migration 20260724120000_version_zero_start (nur der Default) Plan-Dashboard: - Kacheln anklickbar (fuehren in ihren Bereich), neue Kachel "Berichte" - Plan umbenennen ueber Stift-Symbol - Ist-Abweichung nennt das Jahr des juengsten Ist-Datensatzes und ist bei positiver Abweichung gruen statt rot Szenario-Liste: - Klick auf die Zeile oeffnet die Matrix (Matrix-Knopf entfaellt) - je Zeile Kopie (Vorlage frei waehlbar) und Loeschen - laedt nach einer Loeschung neu (zeigte vorher den alten Stand) Seitenleiste: - Szenarien wieder verschachtelt nach Herkunft - Effektive Werte / Analysen / Berichte buendig zum Knoten "Szenarien" CSV-Export (neues Modul lib/csv.ts): - vier Bloecke: Kopf, Lebensphasen, ganze Matrix (Elemente x Phasen inkl. Uebergangs-Entscheide im Klartext), Jahreswerte - mit BOM (Excel-Umlaute), Dateiname transliteriert Umlaute - vorher enthielt die Datei kein einziges finanzielles Element Grafiken: - Szenario-Waehler gilt fuer alle drei Grafiken - BUGFIX Szenario-Vergleich: WealthChart nutzte den Namen als Datenschluessel -> gleichnamige Szenarien ueberschrieben sich (Legende zeigte beide, Chart nur eine). Neu die ID; stille Deckelung auf 4 Serien entfaellt - eigene Legende mit freier Farbwahl je Serie + Erklaerung des Linienstils - Vermoegensaufteilung neu: gestapelte Flaeche ueber die Planjahre + Ring fuer die relative Aufteilung zu einem waehlbaren Zeitpunkt - alle Diagrammfarben aus neuen Theme-Tokens (--chart-1..6, --chart-grid) Doku-Drift bereinigt: Kapitel 2.1, 3.2.2-3.2.7 und 3.10 beschrieben noch den Stand vor V7 (Grundprofil am Szenario, parentPlanId, Scenario.startYear, window.confirm, drei Sidebar-Unterpunkte). Nebenbei: verstuemmelte Hex-Farbe --danger-soft (warm) repariert, deutsche Plural-/Umlautfehler in den Uebersichts-Kacheln. SPEZIFIKATION 0.31. 267 -> 275 Tests. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
+134
-67
@@ -4,10 +4,10 @@
|
||||
| | |
|
||||
|---|---|
|
||||
| **Dokument** | Funktionale und Technische Spezifikation FPT |
|
||||
| **Version** | 0.30 |
|
||||
| **Version** | 0.31 |
|
||||
| **Datum** | 2026-07-24 |
|
||||
| **Status** | Lebendes Dokument |
|
||||
| **Codestand** | Arbeitsstand nach `efcc04c` inkl. Tour-Korrekturen (Branch `main`) |
|
||||
| **Codestand** | Arbeitsstand nach `96fdd00` inkl. Modul-Review 3 (Struktur & Grafiken) (Branch `main`) |
|
||||
| **Ersetzt** | `FDD_TDD_FPT.docx` (v1–v5) im Ordner `Info Dateien` – diese sind ab Version 0.1 dieses Dokuments obsolet |
|
||||
| **Geltungsbereich** | Gesamter Code im Verzeichnis `FPT` |
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
|
||||
| Version | Datum | Autor | Änderung |
|
||||
|---|---|---|---|
|
||||
| 0.31 | 2026-07-25 | Claude (Opus 5) | **Modul-Review 3 (Plan-/Szenario-Struktur, Dashboard, Grafiken).** (1) **Versionierung startet bei 0.1** statt 1.0 (Kap. 3.8): Ein Szenario läuft in der 0er-Reihe (0.1, 0.2, … 0.137), bis eine **Hauptversion** gesetzt wird – erst dann entsteht 1.0. Vorher begann jedes Szenario bereits bei 1.0, wodurch die Hauptversion ihre Bedeutung verlor. Die Szenario-Liste zeigt neu die **echte** Version statt «1.x», dazu eine Spalte **Phasen**. (2) **Plan-Dashboard:** Kacheln sind **anklickbar** und führen in ihren Bereich, neu inkl. **Berichte**; der Plan lässt sich über ein Stift-Symbol **umbenennen**; die Ist-Abweichung nennt das **Jahr** des jüngsten Ist-Datensatzes und ist bei einer positiven Abweichung **grün** statt rot. (3) **Szenario-Liste:** Ein Klick auf die **Zeile** öffnet die Matrix (der «Matrix»-Knopf entfällt), dazu je Zeile **Kopie** und **Löschen**; die Kopiervorlage ist damit frei wählbar und nicht mehr auf das Basisszenario festgelegt. Nach einer Löschung lädt die Liste neu (zeigte vorher den alten Stand). (4) **Seitenleiste:** Szenarien werden wieder **verschachtelt** dargestellt (Tiefe = Herkunftskette); «Effektive Werte», «Analysen» und «Berichte» stehen neu **bündig zum Knoten «Szenarien»** statt auf Höhe der einzelnen Szenarien. (5) **CSV-Export vollständig neu** (Kap. 3.6.5, neues Modul `csv.ts`): vier Blöcke – Kopf, Lebensphasen, **die ganze Matrix** (Elemente × Phasen mit Beginn/Ende und den Übergangs-Entscheiden im Klartext) und **Jahreswerte**; mit BOM, damit Excel die Umlaute erkennt. Vorher enthielt die Datei kein einziges finanzielles Element. (6) **Grafiken:** Ein **Szenario-Wähler** gilt neu für **alle drei** Grafiken (vorher nur der Vermögensverlauf, und der nur additiv). Der **Vergleichs-Fehler** ist behoben: `WealthChart` benutzte den Szenario-**Namen** als Datenschlüssel, wodurch sich gleichnamige Szenarien gegenseitig überschrieben (Legende zeigte beide, der Chart nur eine) – neu die **ID**; die stille Deckelung auf vier Serien entfällt. Die **Legende** ist eigenständig, erlaubt eine **freie Farbwahl je Serie** und erklärt den Linienstil (gestrichelt = Plan, durchgezogen = effektiv). Die **Vermögensaufteilung** ist neu eine **gestapelte Fläche über alle Planjahre** plus ein **Ring** für die relative Aufteilung zu einem wählbaren Zeitpunkt (vorher gestapelte Balken je Phase mit schräger Beschriftung). **Alle Diagrammfarben** kommen aus neuen Theme-Tokens (`--chart-1` … `--chart-6`, `--chart-grid`) statt fester Hex-Werte. (7) **Dokumentation nachgezogen:** Die Kapitel 2.1, 3.2.2–3.2.7 und 3.10 beschrieben noch den Stand **vor V7** (Grundprofil am Szenario, `parentPlanId`, `Scenario.startYear`, `window.confirm`, drei Sidebar-Unterpunkte). (8) Nebenbei: verstümmelte Hex-Farbe `--danger-soft` im Warm-Schema repariert, deutsche Plural-/Umlautfehler in den Übersichts-Kacheln, Dateiname des CSV-Exports transliteriert Umlaute statt sie zu `_` zu machen. 8 Tests ergänzt (267 → 275). |
|
||||
| 0.30 | 2026-07-24 | Claude (Opus 4.8) | **Tour-Korrekturen und 3a-Verschiebung.** (1) Der Tour-**Spotlight** wird neu aus **vier fixed-Flächen** um die Bounding-Box des Ziels gezeichnet (Kap. 9.24) statt aus einem `box-shadow`-Trick. Grund: Der Schatten liess sticky Matrix-Köpfe (hoher z-index) hell durchscheinen und wurde im Matrix-Scrollbereich abgeschnitten (dann blieb fast alles hell). Die vier Flächen funktionieren unabhängig von z-index und overflow und folgen dem Ziel per `requestAnimationFrame`. (2) **Tour-Schritte** überarbeitet: neu erklärt sind **Zeitachse** und **Endvermögen**; der vormals «Analysen»-Schritt beschreibt jetzt korrekt die **obere Funktions-Leiste** (die Analyse-Werkzeuge sind dort nicht mehr), und ein neuer Schritt zeigt das **linke Menü** (Analysen, Berichte, Effektive Werte). Unsichtbare Ziele (z. B. das Menü auf schmalen Screens) werden übersprungen. (3) Der Schalter **«Selbstständig – grosse Säule 3a»** wandert im Assistenten von Schritt 4 zu **Schritt 5**, weil er die 3a-Einzahlung (also die Sparraten-Verteilung) betrifft. Kein Eingriff in den Rechenkern; 267 Tests unverändert grün. |
|
||||
| 0.29 | 2026-07-24 | Claude (Opus 4.8) | **Modul-Review 2, Feinschliff (Assistent, Tour, Ansicht).** (1) **Assistent:** neuer **Willkommens-Screen** vor Schritt 1 mit dem Gesamtbild der fünf Schritte, danach eine **persistente Schritt-Leiste** (links im breiten Modal, mobil als Fortschrittsbalken) – der aktuelle Schritt hervorgehoben, erledigte mit Haken, kommende gedämpft. Schritt «Vorsorge & Vermögen» fragt neu auch die **erwartete Rendite** bei PK, 3a und Wertschriften ab (vorher fest verdrahtet). Im Schritt «Sparen & Verteilen» rechnet die Sparquote-Vorschau **Hypothekarzinsen**, die als «noch nicht in den Ausgaben» markiert sind, korrekt zu den Ausgaben dazu (wie der Rechenkern bei `interestHandling: ADD`); der **noch nicht verteilte Rest** steht neu **prominent oben** (zwischen PK und Verteilung), und die Verteilung ist nach **Gemeinsam / Person A / Person B** gruppiert. (2) **Tour** (Kap. 9.24): statt der bisher bewusst schlichten Hervorhebung jetzt ein **Spotlight** – der Rest der Ansicht wird abgedunkelt (ein 9999-px-Kastenschatten, kein separates Overlay), der pulsierende Rahmen ist deutlich stärker, die Karte ist grösser und **springt** auf die dem Ziel gegenüberliegende Bildschirmhälfte (verdeckt es nie); neu mit **«Überspringen»**-Knopf. (3) **Szenario-Ansicht** (Kap. 3.7.7): Grundprofil, Zeitachse und die Kennzahlen (Endvermögen nominal + real, Ruinalter) bilden neu **einen kompakten Block** aus drei Spalten (25 / 50 / 25 %) statt zweier über die ganze Breite gezogener Zeilen. Neue Modal-Grösse `xwide`. Kein Eingriff in den Rechenkern; 267 Tests unverändert grün. |
|
||||
| 0.28 | 2026-07-24 | Claude (Opus 4.8) | **Modul-Review 2 (Onboarding & Ansicht): Layout-Umbau, Tour und Assistenten-Redesign.** (1) **Szenario-Ansicht neu geordnet** (Kap. 3.7.7): oben eine schlanke Funktions-Leiste (Änderungshistorie · Tour · Neues Szenario · Rechenwege · CSV-Export · Löschen · Abweichungs-Badge), darunter Nächste Schritte → Grundprofil → Zeitachse → Anzeige-Umschalter → Matrix. Grafiken, Effektive Werte, Live-Simulation, Monte-Carlo und Einflussfaktoren sind aus der Leiste **entfernt** – sie laufen über die eigenen Menüpunkte (Analysen / Effektive Werte). (2) **Tour** liegt neu in `AppShell` (statt `PlanView`) und startet nach **jeder** Plan-Erstellung – Assistent, Beispielplan **und** leerer Plan – unabhängig davon, ob sie schon einmal beendet wurde (Kap. 3.7.8); die Erfolgsmeldung hält damit ihr Versprechen. (3) **Assistent durchgehend in Du-Form** im Einzelmodus (Paarmodus weiter «ihr» / je Person). (4) **Schritt-Redesign** (Kap. 3.2.8): Schritt «Vorsorge & Vermögen» erfasst nur noch **Bestandswerte**; ein **neuer Schritt «Sparen & Verteilen»** zeigt die Sparquote (Nettoeinkommen − Ausgaben) und lässt sie auf 3a, Wertschriften, Amortisation und Schuldtilgung verteilen – der Rest bleibt sichtbar auf dem Cash-Konto. Die **PK-Einzahlung** steht dort bewusst separat, mit dem Hinweis, dass sie vom Bruttolohn kommt und die Sparquote **nicht** schmälert (deckt sich mit dem Rechenkern). Immobilien fragen im Assistenten neu **Wertsteigerung** und den **Zins-in-Ausgaben-Schalter** ab; der Lohn bekommt 1 % Default-Erhöhung. (5) **«Grosse Säule 3a» für Selbstständige** (Roadmap-Feedback): ein Schalter am 3a-Element (und im Assistenten) hebt die Beitrags-Obergrenze von 7’258 auf ca. 36’288 CHF an (neue Konstante `PILLAR_3A_MAX_SELF_EMPLOYED`, **2026-Wert zu verifizieren**; neues Feld `selfEmployed3a`). (6) Nebenbei: `POST /plans` liefert bei Validierungsfehlern eine lesbare Meldung statt eines rohen zod-Objekts. Keine Änderung am Rechenkern; 267 Tests unverändert grün. |
|
||||
@@ -127,11 +128,12 @@ Referenz: `prisma/schema.prisma` Zeilen 8–10, `src/lib/types.ts` Zeilen 38–4
|
||||
|
||||
```
|
||||
User
|
||||
└── Plan (Behälter: nur Name — KEINE Finanzdaten)
|
||||
└── Scenario[] (die berechenbare Einheit)
|
||||
│ Grundprofil: Haushaltsform, Personen, Inflation, Cash-Startwert
|
||||
└── Plan (der HAUSHALT: Name, Haushaltsform, Startjahr)
|
||||
├── PlanPerson[] (Rolle, Name, Alter — gelten für ALLE Szenarien)
|
||||
└── Scenario[] (die berechenbare Einheit = eine Planungsvariante)
|
||||
│ szenario-eigen: Inflation, Cash-Startwert
|
||||
│ isBase = genau eines je Plan · parentScenarioId = Baum + Vergleichsbasis
|
||||
├── Person[] (1 bei SINGLE, 2 bei COUPLE — je Szenario eigen!)
|
||||
├── Person[] (nur das PENSIONSALTER je Rolle — szenario-eigen)
|
||||
├── Phase[] (Kette 1..n; sourcePhaseId = Gegenstück in der Vorlage)
|
||||
└── FinancialElement[] (szenario-weit; sourceElementId = Gegenstück in der Vorlage)
|
||||
├── ElementPhaseValue[] (Werte je Phase, JSON)
|
||||
@@ -146,14 +148,15 @@ und pro Phasenübergang einen Entscheid-Satz. Dadurch bleibt die Identität eine
|
||||
Vermögensgegenstands über die Zeit erhalten – Voraussetzung für die Fortschreibung (Carry) und
|
||||
die Vermögensaufteilungs-Grafik.
|
||||
|
||||
**(2) Das Grundprofil liegt am Szenario, nicht am Plan** (V6). Nur so lassen sich die
|
||||
wertvollsten Szenario-Fragen abbilden – allen voran ein abweichendes **Pensionsalter**
|
||||
(„Was, wenn ich mit 62 statt 65 aufhöre?"), das in `Person` steckt. Wäre das Profil geteilt,
|
||||
wären Frühpensionierungs-Szenarien unmöglich.
|
||||
**(2) Der Haushalt liegt am Plan, die Annahmen am Szenario** (V7, siehe
|
||||
[9.30](#930-warum-der-haushalt-am-plan-hängt)). Haushaltsform, Personen (Name, Alter) und
|
||||
Planstartjahr beschreiben den **Haushalt** – sie gelten für alle Szenarien. Unterscheiden sie
|
||||
sich, ist es ein anderer **Plan**. Szenario-eigen sind die **Annahmen**: Inflation,
|
||||
Cash-Startwert und – am wichtigsten – das **Pensionsalter** je Person. Nur deshalb sind
|
||||
Frühpensionierungs-Szenarien überhaupt möglich („Was, wenn ich mit 62 statt 65 aufhöre?").
|
||||
|
||||
Der **Plan** ist damit ein reiner Behälter: Er bündelt Szenarien und trägt den Eigentümer
|
||||
(`userId`). Ownership von Szenario/Phase/Element läuft über die Kette
|
||||
`Scenario → Plan → User`.
|
||||
Der **Plan** trägt zudem den Eigentümer (`userId`). Ownership von Szenario/Phase/Element läuft
|
||||
über die Kette `Scenario → Plan → User`.
|
||||
|
||||
Referenz: `prisma/schema.prisma`.
|
||||
|
||||
@@ -317,49 +320,59 @@ Der Dialog «Leer starten» fragt Name plus das vollständige Grundprofil:
|
||||
Konsistenzregel: `SINGLE` erfordert genau eine Person, `COUPLE` genau zwei (Person A und B).
|
||||
Verletzung → HTTP 400 mit Klartextmeldung.
|
||||
|
||||
Referenz: `src/components/PlanProfileFields.tsx` Zeilen 1012–1018, `src/app/api/plans/route.ts`
|
||||
Zeilen 6–35.
|
||||
Referenz: `src/components/PlanProfileFields.tsx`, `src/app/api/plans/route.ts`.
|
||||
|
||||
Ein neu erstellter Plan hat **keine Phasen und keine Elemente**; `initialCash` ist 0.
|
||||
|
||||
### 3.2.2 Grundprofil ändern
|
||||
|
||||
Über „Einstellungen" in der Planansicht. Wichtig: Die Personen werden serverseitig in einer
|
||||
Transaktion **gelöscht und neu angelegt** (`deleteMany` + `create`). Die Person-IDs ändern sich
|
||||
dadurch. Da Elemente über `ownerRole` (nicht über `personId`) zugeordnet sind, bleibt die
|
||||
Zuordnung erhalten.
|
||||
Über **«Profil bearbeiten»** im Grundprofil-Block der Szenario-Ansicht (Panel «Szenario-Profil»).
|
||||
Der Endpunkt ist `PATCH /api/scenarios/<scenarioId>`: Er schreibt Haushaltsform, Personen (Name,
|
||||
Alter) und Startjahr an den **Plan**, Inflation und Pensionsalter ans **Szenario** – die Trennung
|
||||
aus V7 ([9.30](#930-warum-der-haushalt-am-plan-hängt)). Das **Pensionsalter** ist dort nur noch
|
||||
Anzeige; verschoben wird es über «Pensionsalter anpassen» ([3.12](#312-pensionsalter-anpassen)),
|
||||
weil es auf einer Phasengrenze liegt.
|
||||
|
||||
Wichtig: Die Personen werden serverseitig in einer Transaktion **gelöscht und neu angelegt**
|
||||
(`deleteMany` + `create`). Die Person-IDs ändern sich dadurch. Da Elemente über `ownerRole`
|
||||
(nicht über `personId`) zugeordnet sind, bleibt die Zuordnung erhalten.
|
||||
|
||||
Ein Wechsel von `COUPLE` auf `SINGLE` entfernt Person B. Elemente mit `ownerRole = PERSON_B`
|
||||
bleiben in der Datenbank bestehen, finden aber keinen Owner mehr – siehe
|
||||
[9.2](#92-verwaiste-person_b-elemente).
|
||||
|
||||
Referenz: `src/app/api/plans/[planId]/route.ts` Zeilen 55–70.
|
||||
**Plan umbenennen:** über das Stift-Symbol neben dem Plannamen im Plan-Dashboard
|
||||
(`PATCH /api/plans/<planId>`, nur das Feld `name`).
|
||||
|
||||
Referenz: `src/app/api/scenarios/[scenarioId]/route.ts`, `src/app/api/plans/[planId]/route.ts`.
|
||||
|
||||
### 3.2.3 Cash-Anfangswert
|
||||
|
||||
Klick auf die erste Zelle der Cash-Zeile öffnet den Dialog „Cash-Anfangswert". Wertebereich
|
||||
0 bis 1'000'000'000, wird auf ganze Franken gerundet.
|
||||
|
||||
Referenz: `src/components/PlanView.tsx` Zeilen 1130–1156, `src/app/api/plans/[planId]/route.ts` Zeile 36.
|
||||
Referenz: `src/components/PlanView.tsx`, `PATCH /api/scenarios/<scenarioId>` (Feld `initialCash`).
|
||||
|
||||
### 3.2.4 Plan löschen
|
||||
|
||||
Aus der Übersichtskachel oder der Planansicht, mit Browser-`confirm()`. Löscht per Datenbank-Cascade
|
||||
Personen, Phasen, Elemente und alle Werte. Szenarien, die auf diesen Plan als `parentPlanId`
|
||||
zeigen, werden **nicht** gelöscht – ihre `parentPlanId` wird auf `NULL` gesetzt
|
||||
(`onDelete: SetNull`).
|
||||
Aus der Übersichtskachel oder der Seitenleiste, mit dem eigenen Bestätigungs-Dialog
|
||||
(`useConfirm`, siehe [3.7.6](#376-sprache-und-ui-primitiven) – kein Browser-`confirm()` mehr).
|
||||
Löscht per Datenbank-Cascade **alle Szenarien** des Plans und darüber Personen, Phasen, Elemente
|
||||
und sämtliche Werte, dazu die Ist-Datensätze, gespeicherten Analysen und Berichte des Plans.
|
||||
|
||||
Referenz: `prisma/schema.prisma` Zeile 82.
|
||||
Referenz: `prisma/schema.prisma`, `src/app/api/plans/[planId]/route.ts`.
|
||||
|
||||
### 3.2.5 Szenarien
|
||||
|
||||
Beim Anlegen eines Plans entsteht **automatisch das Basisszenario** (`isBase = true`,
|
||||
Name „Basisszenario"). Der beim Anlegen erfasste Profilteil (Haushaltsform, Personen,
|
||||
Inflation) landet dort, der Name am Plan.
|
||||
Name „Basisszenario"). Vom erfassten Profil landen **Haushaltsform, Personen und Startjahr am
|
||||
Plan**, **Inflation und Pensionsalter am Basisszenario** (V7).
|
||||
|
||||
Ein weiteres Szenario ist eine **vollständige Kopie eines beliebigen bestehenden Szenarios**
|
||||
(nicht nur des Basisszenarios). Kopiert werden Grundprofil, alle Personen, alle Phasen, alle
|
||||
Elemente sowie sämtliche Phasen- und Übergangswerte.
|
||||
(nicht nur des Basisszenarios – die Vorlage ist in der Szenario-Liste je Zeile über «Kopie»
|
||||
wählbar). Kopiert werden die szenario-eigenen Angaben (Inflation, Cash-Startwert,
|
||||
Pensionsalter), alle Phasen, alle Elemente sowie sämtliche Phasen- und Übergangswerte. Der
|
||||
Haushalt wird **nicht** kopiert – er liegt am Plan und gilt ohnehin für alle Szenarien.
|
||||
|
||||
Gesetzt werden dabei:
|
||||
- `parentScenarioId` = das kopierte Szenario → ergibt den **Baum** in der Seitenleiste **und**
|
||||
@@ -404,11 +417,11 @@ Referenz: `src/lib/diff.ts`.
|
||||
### 3.2.7 Planstart (Kalenderjahr)
|
||||
|
||||
Das Grundprofil enthält das Feld **Planstart (Jahr)** – das Kalenderjahr, in dem Jahr 1 der
|
||||
Planung liegt (`Scenario.startYear`). Es dient **ausschliesslich der Darstellung**: Zeitachse
|
||||
Planung liegt (`Plan.startYear`, seit V7 plan-weit). Es dient **ausschliesslich der Darstellung**: Zeitachse
|
||||
und Grafiken beschriften damit Jahre statt nur Alter. Die Berechnung rechnet unverändert in
|
||||
**relativen** Jahren ab Planbeginn – `startYear` fliesst in keine Formel ein.
|
||||
|
||||
Beim Anlegen wird das laufende Jahr vorbelegt; bestehende Szenarien wurden per Migration darauf
|
||||
Beim Anlegen wird das laufende Jahr vorbelegt; bestehende Pläne wurden per Migration darauf
|
||||
gesetzt. Kalenderjahr eines Planjahrs: `startYear + (Jahr − 1)`.
|
||||
|
||||
### 3.2.8 Geführter Assistent und Beispielplan
|
||||
@@ -978,10 +991,13 @@ Referenz: `src/components/PlanView.tsx` Zeilen 701–769.
|
||||
|
||||
### 3.6.4 Analyse-Bereich „Grafiken"
|
||||
|
||||
Die Auswertungen liegen **nicht** unter der Matrix, sondern in einem eigenen Bereich: Der Button
|
||||
**Grafiken** in der oberen Aktionsleiste (neben „Neues Szenario aus diesem" und
|
||||
„Monte-Carlo-Simulation") öffnet sie als breiten Dialog. So bleibt die Matrix die ruhige
|
||||
Hauptansicht.
|
||||
Die Auswertungen liegen **nicht** unter der Matrix, sondern in einem eigenen Bereich: Die Kachel
|
||||
**Grafiken** unter dem Menüpunkt **Analysen** ([3.10.2](#3102-analysen-vier-kacheln)) öffnet sie
|
||||
als breiten Dialog. So bleibt die Matrix die ruhige Hauptansicht.
|
||||
|
||||
**Szenario-Wahl:** Ganz oben steht ein Auswahlfeld, welches Szenario die Grafiken zeigen – es
|
||||
gilt für **alle drei**. Vorher war der Bereich fest an das geöffnete Szenario gebunden, und nur
|
||||
der Vermögensverlauf konnte weitere überlagern.
|
||||
|
||||
**Kennzahl-Karten:** Endvermögen nominal und Endvermögen real. (Die frühere Karte „Geschätzter
|
||||
Nachlass" ist entfallen – sie war rechnerisch identisch mit dem nominalen Endvermögen und
|
||||
@@ -994,32 +1010,57 @@ ist grün (Sparquote) oder rot (Verzehr) eingefärbt. Der Keil zwischen roter un
|
||||
anschaulich „das, was die Inflation frisst".
|
||||
|
||||
**Grafik 2 – Vermögensverlauf nach Alter** (`WealthChart`): Liniendiagramm über das Alter von
|
||||
Person A. Je Szenario eine durchgezogene Linie (nominal) und eine gestrichelte (real).
|
||||
Datenpunkte: **jedes Planjahr** (nicht nur die Phasengrenzen) – dadurch werden Verläufe
|
||||
Person A. Datenpunkte: **jedes Planjahr** (nicht nur die Phasengrenzen) – dadurch werden Verläufe
|
||||
*innerhalb* einer Phase sichtbar, etwa das Abschmelzen im Kapitalverzehr. Grundlage ist
|
||||
`YearPoint.wealthNominal/wealthReal` (4.10). Über Checkboxen lassen sich die **Geschwister-
|
||||
Szenarien überlagern**; deren Daten werden bei Bedarf nachgeladen und im Client
|
||||
zwischengespeichert.
|
||||
`YearPoint.wealthNominal/wealthReal` (4.10). Über Checkboxen lassen sich weitere **Szenarien
|
||||
überlagern**; deren Daten werden bei Bedarf nachgeladen und im Client zwischengespeichert.
|
||||
|
||||
**Grafik 3 – Vermögensaufteilung pro Phase**: Gestapeltes Balkendiagramm mit zwei Balken je Phase
|
||||
(Beginn / Ende). Gestapelt werden alle Elemente der Kategorien PK, 3a, Immobilie, Sonstiges
|
||||
Vermögen, die irgendwann einen positiven Wert haben. Stapelung nach `elementId` (nicht Name),
|
||||
damit gleichnamige Elemente nicht kollidieren. Negative Werte werden auf 0 geklammert.
|
||||
Der Datenschlüssel je Serie ist die **Szenario-ID**, nicht der Name. Bis 0.30 diente der Name als
|
||||
Schlüssel – zwei gleichnamige Szenarien überschrieben sich dadurch gegenseitig, und die Legende
|
||||
zeigte eine Linie an, die es im Diagramm gar nicht gab. Die **Legende** ist eigenständig (nicht
|
||||
die von Recharts): Sie erlaubt je Serie eine **freie Farbwahl** und erklärt den Linienstil
|
||||
(gestrichelt = reine Planwerte, durchgezogen = mit effektiven Werten).
|
||||
|
||||
Referenz: `src/components/Dashboard.tsx`, `src/components/WealthChart.tsx`, `src/components/SparquoteChart.tsx`.
|
||||
**Grafik 3 – Vermögensaufteilung im Zeitverlauf**: Links eine **gestapelte Fläche** über alle
|
||||
Planjahre, die Phasengrenzen als feine gestrichelte Senkrechte; rechts ein **Ring**, der die
|
||||
**relative** Aufteilung zu einem wählbaren Zeitpunkt zeigt (Klick in die Fläche wählt das Jahr,
|
||||
Vorgabe ist das Planende). Gestapelt werden alle Elemente der Kategorien PK, 3a, Immobilie,
|
||||
Sonstiges Vermögen, die irgendwann einen positiven Wert haben. Stapelung nach `elementId` (nicht
|
||||
Name), damit gleichnamige Elemente nicht kollidieren. Negative Werte werden auf 0 geklammert.
|
||||
|
||||
Bis 0.30 waren das gestapelte Balken mit zwei Säulen je Phase und schräg gestellter
|
||||
Beschriftung – ab drei Phasen kaum mehr lesbar, und die relative Aufteilung war gar nicht
|
||||
ablesbar. Die Fläche zeigt den Verlauf statt zweier Stichproben je Phase; die Jahreswerte dafür
|
||||
liegen seit 0.11 ohnehin vor (`ElementPhaseComputed.yearly`), es wird nichts neu gerechnet.
|
||||
|
||||
Referenz: `src/components/Dashboard.tsx`, `src/components/WealthChart.tsx`,
|
||||
`src/components/SparquoteChart.tsx`, `src/components/AllocationChart.tsx`.
|
||||
|
||||
### 3.6.5 CSV-Export
|
||||
|
||||
`GET /api/plans/<planId>/export` liefert eine semikolon-getrennte CSV, eine Zeile pro Phase:
|
||||
`GET /api/scenarios/<scenarioId>/export` liefert die **vollständige Matrix** als
|
||||
semikolon-getrennte CSV. Bis 0.30 war das eine reine Phasen-Zusammenfassung – zehn Spalten, eine
|
||||
Zeile je Phase, **kein einziges finanzielles Element**; was am Bildschirm stand, liess sich damit
|
||||
nicht weiterverarbeiten.
|
||||
|
||||
```
|
||||
Phase;Typ;Dauer;Einkommen (Beginn);Ausgaben (Beginn);Quote (Beginn);Quote (Ende);Cash (Ende);Endvermoegen (nominal);Endvermoegen (real)
|
||||
```
|
||||
Die Datei enthält **vier Blöcke** untereinander (Excel kommt damit zurecht, und es ist sofort
|
||||
erkennbar, was zusammengehört):
|
||||
|
||||
Bei vorhandenem Ruin folgt eine Schlusszeile `Ruin: Kapital aufgebraucht mit Alter <N>`.
|
||||
Dateiname = Planname, nicht-alphanumerische Zeichen durch `_` ersetzt.
|
||||
| Block | Inhalt |
|
||||
|---|---|
|
||||
| **Kopf** | Szenario, Haushaltsform, Personen (Alter/Pensionsalter), Planstart, Inflation, Cash-Anfangswert, Erzeugungszeitpunkt |
|
||||
| **LEBENSPHASEN** | je Phase: Typ, Dauer, Altersspanne, Einkommen/Ausgaben, Quote (Beginn/Ende), Cash (Beginn/Ende), Vermögen (Beginn/Ende, nominal + real) |
|
||||
| **MATRIX** | Zeilen = Cash + alle Elemente; je Phase **zwei** Spalten (Beginn/Ende), dazwischen je Übergang **eine** Spalte mit dem Entscheid im Klartext (z. B. «Kapitalbezug (Steuer 8 %)») |
|
||||
| **JAHRESWERTE** | je Planjahr: Kalenderjahr, Alter, Vermögen nominal/real, Cash, Einkommen, Ausgaben, Sparquote |
|
||||
|
||||
Referenz: `src/lib/calculations.ts` Zeilen 620–648.
|
||||
Der Jahreswerte-Block ist der, mit dem sich in Excel selbst weiterrechnen lässt; die Matrix
|
||||
bildet 1:1 die Bildschirm-Ansicht ab.
|
||||
|
||||
Zwei Details, die vorher Ärger machten: Die Datei beginnt mit einem **BOM** – ohne dieses
|
||||
Zeichen zerlegt Excel unter Windows alle Umlaute –, und der **Dateiname** transliteriert Umlaute
|
||||
(ä→ae) statt sie durch `_` zu ersetzen. Bei vorhandenem Ruin folgt eine Schlusszeile.
|
||||
|
||||
Referenz: `src/lib/csv.ts` (rein, ohne I/O), `src/app/api/scenarios/[scenarioId]/export/route.ts`.
|
||||
|
||||
### 3.6.6 Analyse-Bereich „Einflussfaktoren"
|
||||
|
||||
@@ -1058,7 +1099,7 @@ Jede Element-Zeile und jeder Phasenkopf trägt oben rechts ein **Expand-Icon** (
|
||||
|
||||
| Reiter | Inhalt |
|
||||
|---|---|
|
||||
| Übersicht | Typ, Dauer, Vermögen Beginn/Ende; Vermögensaufteilung als gestapelter Balken (Beginn und Ende) |
|
||||
| Übersicht | Typ, Dauer, Vermögen Beginn/Ende; Vermögensaufteilung als Fläche über die Planjahre mit Ring für den gewählten Zeitpunkt |
|
||||
| Wasserfall | Vermögens- und Cash-Wasserfall ([4.14.2](#4142-die-beiden-wasserfälle)) |
|
||||
| Rechenweg | Quote, Spar-/Verzehrrate, Cash-Fortschreibung, Vermögen, Phasentyp, Cash-Übergang |
|
||||
|
||||
@@ -1289,6 +1330,12 @@ die oberste. Animationen (150–220 ms) respektieren `prefers-reduced-motion`.
|
||||
je Farbschema abgestimmt) statt der Akzentfarbe – «hier fehlt eine Eingabe» und «hier kannst
|
||||
du klicken» sind damit unterscheidbar.
|
||||
|
||||
**Diagramm-Palette:** Seit 0.31 kommen auch die Farben aller Diagramme aus Tokens
|
||||
(`--chart-1` … `--chart-6`, dazu `--chart-grid`) statt aus festen Hex-Werten – je Farbschema
|
||||
gedämpft abgestimmt. Recharts bekommt die Variablen direkt als Attributwert (`var(--chart-1)`),
|
||||
der Browser löst sie im SVG auf. Vorher stachen die Diagramme mit greller Standardpalette aus
|
||||
dem Schema heraus und sahen im Dunkelmodus falsch aus.
|
||||
|
||||
### 3.7.7 Inspector-Panel statt Modals
|
||||
|
||||
Alle **Einzel-Bearbeitungen** – Phasenzelle, Übergangszelle, Cash-Übergang, Cash-Anfangswert,
|
||||
@@ -1387,6 +1434,12 @@ sie. Zwei Sicherungen ergänzen das:
|
||||
Eine **Hauptversion** wird nie zusammengefasst und nie nachträglich verändert; die nächste
|
||||
Änderung beginnt bei A.1.
|
||||
|
||||
**Ein Szenario startet bei 0.1.** Die Nebenversion zählt beliebig weit hoch (0.1, 0.2, … 0.137);
|
||||
die **0** bedeutet «noch kein verabschiedeter Stand». Erst eine bewusst gesetzte **Hauptversion**
|
||||
macht daraus **1.0**. Bis 0.30 begann jedes Szenario bereits bei 1.0 – damit war die Hauptversion
|
||||
bedeutungslos, weil jeder Plan schon eine hatte. Bestehende Historien werden **nicht**
|
||||
umnummeriert; nur der Startwert ist neu (Migration `20260724120000_version_zero_start`).
|
||||
|
||||
### 3.8.2 Was die Historie zeigt
|
||||
|
||||
Je Version: **wer** (Benutzername), **wann** (Zeitpunkt der letzten Änderung dieser Sitzung)
|
||||
@@ -1575,15 +1628,20 @@ Referenz: `src/lib/actuals.ts`, `src/lib/dataview.ts`, `src/components/ActualsDi
|
||||
|
||||
## 3.10 Navigation auf Plan-Ebene und gespeicherte Analysen
|
||||
|
||||
Die Seitenleiste ist zweistufig: Unter jedem **Plan** liegen drei leicht eingezogene
|
||||
Unterpunkte. Ein Klick auf den **Plan-Namen** öffnet dessen Dashboard.
|
||||
Die Seitenleiste ist zweistufig: Unter jedem **Plan** liegen vier Unterpunkte. Ein Klick auf den
|
||||
**Plan-Namen** öffnet dessen Dashboard.
|
||||
|
||||
| Ort | Führt zu |
|
||||
|---|---|
|
||||
| Plan-Name | **Plan-Dashboard** (Kennzahlen) |
|
||||
| Szenarien | **Szenario-Liste** – darunter bleibt der Szenario-Baum, dessen Einträge direkt in die Matrix führen |
|
||||
| Plan-Name | **Plan-Dashboard** (Kennzahlen, Umbenennen) |
|
||||
| Szenarien | **Szenario-Liste** – darunter der Szenario-Baum, **verschachtelt** nach Herkunft; seine Einträge führen direkt in die Matrix |
|
||||
| Effektive Werte | Liste + Wizard der Ist-Werte ([3.9](#39-effektive-werte-plan-ist-vergleich)) |
|
||||
| Analysen | Vier Werkzeug-Kacheln + Liste gespeicherter Analysen |
|
||||
| Berichte | PDF-Berichte erzeugen und wieder herunterladen ([3.11](#311-pdf-berichte)) |
|
||||
|
||||
Die vier Unterpunkte stehen **bündig zum Knoten «Szenarien»**; nur die einzelnen Szenarien
|
||||
darunter sind eingerückt – und zwar je nach Tiefe ihrer Herkunftskette, sodass in der
|
||||
Seitenleiste sichtbar ist, woraus ein Szenario entstanden ist.
|
||||
|
||||
### 3.10.1 Plan- vs. Szenario-Ebene der Kennzahlen
|
||||
|
||||
@@ -1591,13 +1649,19 @@ Seit V7 ([9.30](#930-warum-der-haushalt-am-plan-hängt)) liegen Haushaltsform, P
|
||||
Startjahr am Plan; Endvermögen, Ruinalter, Phasen und Elemente sind dagegen **szenario-eigen**.
|
||||
Das Plan-Dashboard zeigt deshalb die Haushaltsdaten direkt, alle gerechneten Kennzahlen aber
|
||||
ausdrücklich als **«laut Basisszenario»** – das Basisszenario ist der kanonische Vertreter.
|
||||
Falls Ist-Werte erfasst sind, weist es zusätzlich die **Abweichung** des Endvermögens gegenüber
|
||||
dem Plan aus.
|
||||
Die vier Kennzahl-Kacheln (Szenarien, Effektive Werte, Analysen, Berichte) sind **anklickbar**
|
||||
und führen in ihren Bereich. Über ein **Stift-Symbol** neben dem Plannamen lässt sich der Plan
|
||||
umbenennen.
|
||||
|
||||
Die **Szenario-Liste** zeigt je Szenario Name, aktuelle Hauptversion, Anzahl Elemente, das
|
||||
Endvermögen und ob das Kapital reicht; das Basisszenario ist farblich hervorgehoben, und die
|
||||
Herkunft (aus welchem Szenario kopiert) steht darunter. Zwei Aktionen je Zeile: **Historie**
|
||||
und **Matrix**.
|
||||
Falls Ist-Werte erfasst sind, weist das Dashboard die **Abweichung** des Endvermögens gegenüber
|
||||
dem Plan aus – benannt mit dem **Jahr des jüngsten Ist-Datensatzes** («Mit den effektiven Werten
|
||||
von 2032 …») und **grün**, wenn die Realität besser ist als der Plan, sonst rot.
|
||||
|
||||
Die **Szenario-Liste** zeigt je Szenario Name, die **aktuelle Version** (z. B. «0.17»), Anzahl
|
||||
**Phasen** und **Elemente**, das Endvermögen und ob das Kapital reicht; das Basisszenario ist
|
||||
farblich hervorgehoben, und die Herkunft (aus welchem Szenario kopiert) steht darunter. Ein
|
||||
Klick auf die **Zeile** öffnet die Matrix; je Zeile gibt es zusätzlich **Historie**, **Kopie**
|
||||
(macht dieses Szenario zur Vorlage) und – ausser beim Basisszenario – **Löschen**.
|
||||
|
||||
### 3.10.2 Analysen: vier Kacheln
|
||||
|
||||
@@ -3233,7 +3297,8 @@ PlanComputed ← an den Client geliefert
|
||||
|
||||
| Datei | Verantwortung |
|
||||
|---|---|
|
||||
| `calculations.ts` | Berechnungskern + CSV-Export. Keine I/O. |
|
||||
| `calculations.ts` | Berechnungskern. Keine I/O. |
|
||||
| `csv.ts` | CSV-Export der vollständigen Matrix (vier Blöcke, Kap. 3.6.5). Rein. |
|
||||
| `elements.ts` | Kategorien, Labels, Reihenfolge, JSON-Payload-Typen, Zod-Schemas, `num()` |
|
||||
| `types.ts` | Domänentypen für API und Berechnung |
|
||||
| `constants.ts` | Schweizer Systemparameter |
|
||||
@@ -3475,6 +3540,7 @@ sondern zu leeren Werten.
|
||||
| `20260720090000_actuals` | Tabelle `ActualsSet` (effektive Werte je Plan, Werte als JSONB, Cash separat) |
|
||||
| `20260720140000_plan_level_profile` | **V7**: Haushaltsform, Personen (Name/Alter) und Startjahr vom Szenario auf den Plan; neue Tabelle `PlanPerson`; `Person` behält nur das Pensionsalter. Datenübernahme aus dem Basisszenario. |
|
||||
| `20260721090000_reports` | Tabelle `Report`: gewählte Parameter, eingefrorenes Modell und die PDF-Datei als `BYTEA` |
|
||||
| `20260724120000_version_zero_start` | `Scenario.currentMajor` startet bei **0** statt 1 – die Versionierung beginnt bei 0.1 (Kap. 3.8). Nur der Default; bestehende Zeilen bleiben |
|
||||
| `20260720160000_saved_analyses` | Tabelle `SavedAnalysis` (Eingaben + Ergebnis als JSONB, denormalisierte Kerndaten) |
|
||||
|
||||
**Zur V6-Migration:** Sie benennt die bisherige `Plan`-Tabelle in `Scenario` um – dadurch
|
||||
@@ -3846,7 +3912,7 @@ Include `src/**/*.test.ts`). Es gibt **keine** Komponenten-, API- oder E2E-Tests
|
||||
| `actuals.test.ts` | 24 | Zuordnung über Kopie-Ketten, Sprung im Ist-Jahr, Weiterrechnen ab dem Ist-Wert, geschlossene Brücken, Fluss-Rückrechnung, Wirkung über die Phasengrenze hinaus |
|
||||
| `dataview.test.ts` | 7 | beide Sichten in einem Zug, Rückfall ohne Ist-Werte, Abweichungsmessung |
|
||||
| `ratefields.test.ts` | 17 | Erkennung geänderter Raten, Reichweite (diese/folgende/alle), Erhalt der übrigen Werte in den Zielphasen |
|
||||
| `versioning.test.ts` | 22 | Nummerierung und Zusammenfassung je Sitzung, unveränderte Stände, Benutzertrennung, Bauplan des Wiederherstellens, Auswirkung auf Kind-Szenarien |
|
||||
| `versioning.test.ts` | 23 | Nummerierung und Zusammenfassung je Sitzung, unveränderte Stände, Benutzertrennung, Bauplan des Wiederherstellens, Auswirkung auf Kind-Szenarien |
|
||||
| `versioning-coverage.test.ts` | 3 | statischer Wächter: jeder schreibende Endpunkt löst eine Version aus |
|
||||
| `report.test.ts` | 9 | Zusammenfassung, Basis-Angabe zu JEDER Kennzahl, Szenario-Deckelung, Plan/Ist-Block, Haftungsausschluss, gültige PDF-Datei |
|
||||
| `livesim.test.ts` | 15 | Element-Regler bewegt genau ein Element; Aufschlüsselung deckt sich mit dem Sammelregler; neutrale Stellung verändert den Plan nicht; Ruinmeldung |
|
||||
@@ -3857,7 +3923,8 @@ Include `src/**/*.test.ts`). Es gibt **keine** Komponenten-, API- oder E2E-Tests
|
||||
| `diff.test.ts` | 9 | Abweichungs-Erkennung gegen das Eltern-Szenario |
|
||||
| `migrations.test.ts` | 3 | spielt alle Migrationen gegen echtes PostgreSQL (PGlite) ein; prüft zusätzlich die V7-**Datenübernahme** (Basisszenario gewinnt, Pensionsalter bleiben szenario-eigen) |
|
||||
| `rate-limit.test.ts` | 6 | Fixed-Window: erlaubt bis Limit, blockt danach, startet nach Fensterablauf neu, trennt je Schlüssel; Client-IP aus X-Forwarded-For / X-Real-IP |
|
||||
| **Total** | **267** | |
|
||||
| `csv.test.ts` | 7 | BOM, alle vier Blöcke, jedes Element als Zeile, Beginn-/Ende-/Übergangsspalten, Entscheid im Klartext, ein Eintrag je Planjahr, Maskierung von `;` und `"` |
|
||||
| **Total** | **275** | |
|
||||
|
||||
## 8.2 Testfälle
|
||||
|
||||
|
||||
Reference in New Issue
Block a user