Modul-Review 4: Matrix -- Kapitalverwendung, Phasendauer, Bedienung
Deploy App / deploy (push) Successful in 1m10s

Kapitalverwendung (Punkt C) am richtigen Ort:
- Prozent-Aufteilung des bezogenen Alterskapitals wandert vom Cash-Uebergang
  zum Bezugs-Entscheid der PK (nur bei Kapitalbezug) bzw. der Saeule 3a --
  mit zwei Guthaben liess sie sich vorher gar nicht getrennt beantworten
- Dialoge fuehren neu brutto -> Steuersatz -> netto -> Verteilung
- BUGFIX: Der zugeteilte Betrag erhoehte still den internen Bestand, deshalb
  zeigten Ziel-Element und "Kapital verteilen" eine 0. Er laeuft jetzt ueber
  Carry.capitalIn als Zusatzeinlage der Folgephase und ist ueberall sichtbar
- Saeule 3a ist am Pensions-Uebergang neu ein offener Entscheid

Phasendauer (gemeldeter Fehler):
- Die Folgephase gleicht eine geaenderte Dauer aus; Gesamtdauer bleibt gleich
- Vorher kappte das Tool nur die bearbeitete Phase -> Phase 2 ueberspannte
  danach die Pensionierung und die Invariante aus Punkt 44 kippte
- Rueckfrage vorher, Blockade wenn die Folgephase unter 1 Jahr fiele
- neue reine Funktion planDurationChange

Bedienung:
- Element-Zeile und Phasenkopf: Stift (umbenennen, beim Element inkl.
  Zuordnung), Papierkorb, Expand -- alle immer sichtbar
- PATCH /api/elements/<id> nimmt neu auch ownerRole
- Hilfetexte via Portal (wurden in scrollenden Dialogen abgeschnitten)
- Verteil-Dialoge: Zuordnung je Zeile, nach vom/ins Cash gruppiert,
  Vorbelegung mit dem EFFEKTIVEN Wert inkl. Vererbung (zeigte vorher 0)
- Matrix: gleiche Spaltenbreiten + horizontales Scrollen, "Alle auf-/
  zuklappen", Kategorie-Summe in der zugeklappten Zeile
- Phasen-Detailansicht nutzt die neue Aufteilungs-Grafik
- Uebersicht: "Leer starten" auch im leeren Zustand

Nebenbei: dritte verstuemmelte Hex-Farbe (#7c3aed) repariert, Phasen-Panel
nutzt den eigenen Bestaetigungs-Dialog statt window.confirm; mehrere veraltete
Referenzen und die buildCarryData-Tabelle in der Spez nachgezogen.

SPEZIFIKATION 0.33. 278 -> 288 Tests.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-25 23:09:03 +02:00
parent 0761f6b3e2
commit 0953880a80
17 changed files with 1040 additions and 267 deletions
+87 -44
View File
@@ -4,10 +4,10 @@
| | |
|---|---|
| **Dokument** | Funktionale und Technische Spezifikation FPT |
| **Version** | 0.32 |
| **Version** | 0.33 |
| **Datum** | 2026-07-25 |
| **Status** | Lebendes Dokument |
| **Codestand** | Arbeitsstand nach `b42f9b3` inkl. Modul-Review 3 (Nachbesserungen) (Branch `main`) |
| **Codestand** | Arbeitsstand nach `0761f6b` inkl. Modul-Review 4 (Matrix) (Branch `main`) |
| **Ersetzt** | `FDD_TDD_FPT.docx` (v1v5) 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.33 | 2026-07-25 | Claude (Opus 5) | **Modul-Review 4 (Matrix: Phasen und Elemente).** (1) **Kapitalverwendung neu am Vorsorge-Element** (Punkt C aus Roadmap Nr. 44): Die Prozent-Aufteilung des bezogenen Alterskapitals hing am **Cash-Übergang** dem falschen Ort, denn mit zwei Guthaben (PK und 3a) liess sie sich dort gar nicht getrennt beantworten. Sie steht jetzt beim **Bezugs-Entscheid** der Pensionskasse (nur bei Kapitalbezug) bzw. der **Säule 3a**. Beide Dialoge führen neu **brutto → Steuersatz → netto** und darunter die Verteilung. Der zugeteilte Betrag fliesst über den regulären Weg (`Carry.capitalIn` → Zusatzeinlage der Folgephase) und ist damit **überall sichtbar**: am Ziel-Element, in der Cash-Brücke als Investition und im «Kapital verteilen»-Dialog. Vorher erhöhte er still den Bestand, weshalb Element und Dialog eine **0** zeigten. Die **Säule 3a** ist am Pensions-Übergang neu ein **offener Entscheid** (Steuersatz und Verwendung); vorher galt sie als automatisch beantwortet. (2) **Phasendauer: die Folgephase gleicht aus** (Kap. 3.3.2). Bis 0.32 prüfte die Kappung nur die **bearbeitete** Phase wurde Phase 1 von 10 auf 12 Jahre verlängert, überspannte danach Phase 2 die Pensionierung, und die tragende Invariante aus Roadmap Nr. 44 kippte. Neu trägt die Folgephase die Differenz (Gesamtdauer bleibt gleich, wie beim Verschieben des Pensionsalters); passt sie nicht, wird blockiert; vorher erscheint eine Rückfrage. Neue reine Funktion `planDurationChange`. (3) **Element und Phase direkt bedienbar:** In der Matrix tragen Element-Zeile und Phasenkopf neu **Stift** (umbenennen, beim Element inkl. **Zuordnung**) und **Papierkorb**; das Expand-Symbol ist **immer** sichtbar statt nur bei Mouseover. `PATCH /api/elements/<id>` nimmt dafür neu auch `ownerRole` (bleibt für AHV/PK/3a personengebunden). (4) **Hilfetexte** werden über ein **Portal** gezeichnet in scrollenden Dialogen schnitt der Container sie vorher ab; sie klappen nach oben, wenn unten kein Platz ist. (5) **Verteil-Dialoge:** Zeilen zeigen die **Zuordnung** (Person A/B/Gemeinsam) und sind nach **«vom Cash»/«ins Cash»** gruppiert; die Vorbelegung nutzt neu den **effektiven** Wert inklusive Vererbung aus der Vorphase ein geerbter 3a-Beitrag erschien vorher als 0. (6) **Matrix:** alle Phasenspalten **gleich breit**, bei vielen Phasen wird horizontal gescrollt; **«Alle auf-/zuklappen»**; eine zugeklappte Kategorie zeigt je Phase die **Summe** ihrer Elemente. (7) **Phasen-Detailansicht** nutzt die neue Aufteilungs-Grafik (Fläche + Ring) statt der alten Balken. (8) **Übersicht:** «Leer starten» steht neu auch im leeren Zustand zur Wahl. (9) Nebenbei: dritte vom Umlaut-Sweep verstümmelte Hex-Farbe (`#7c3äd`) repariert, das Phasen-Panel nutzt den eigenen Bestätigungs-Dialog statt `window.confirm`. 10 Tests ergänzt (278 → 288). |
| 0.32 | 2026-07-25 | Claude (Opus 5) | **Modul-Review 3, Nachbesserungen darunter ein gravierender Rechenfehler bei den effektiven Werten.** (1) **Immobilien-Bugfix (Kap. 3.9):** Der Ist-Wizard belegte den Immobilienwert mit dem **Eigenkapital** vor (`ElementYearPoint.value`), während Erfassung und Rechenkern den **Verkehrswert** erwarten. Der Rechenkern setzte den vorbelegten Wert als Verkehrswert ein, liess die Hypothek aber stehen das Eigenkapital brach im Ist-Jahr schlagartig ein, typischerweise ins Negative. Sichtbar wurde das als **negative Gesamt-Abweichung, obwohl nur ein Lohn erhöht** wurde, und als «wegbrechendes» Wohneigentum in der Vermögensaufteilung. Neu wird `propertyValue` vorbelegt; das Feld ist als «Verkehrswert + Restschuld» beschriftet. Drei Regressionstests. (2) **Ist-Datensätze bearbeitbar:** Ein Klick auf die Zeile (oder «Bearbeiten») öffnet den erfassten Satz erneut; neuer Endpunkt `PUT /api/plans/<id>/actuals/<setId>`. Beim Bearbeiten überschreiben die Planwerte die erfassten Zahlen nicht mehr. (3) **Ring-Klick in der Vermögensaufteilung repariert:** Recharts 3 reicht im Klick-Parameter **kein `activePayload`** mehr durch (nur noch `activeIndex`) der Handler feuerte nie, der Ring zeigte immer das Planende. (4) **Seitenleiste sauber dreistufig:** Ebene 1 Pläne, Ebene 2 die vier Bereiche (Szenarien, Effektive Werte, Analysen, Berichte) mit **bündigen Symbolen**, Ebene 3 nur die Szenarien verschachtelt nach Herkunft. (5) Die **Szenario-Liste** zeigt neben der Version deren **Kommentar**. |
| 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.23.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. |
@@ -528,32 +529,47 @@ und die AHV-/PK-Renten am Phasenbeginn ausgewertet werden.
mindestens eine Person pensioniert ist, sonst „Erwerbsphase".
**Vorbelegung der Elemente:** Beim Anlegen einer Phase wird für jedes noch aktive Element
(nicht `SOLD`, nicht `SETTLED`) ein `ElementPhaseValue` mit den **editierbaren** Feldern der
Vorphase erzeugt (`buildCarryData`):
(nicht `SOLD`, nicht `SETTLED`) ein `ElementPhaseValue` erzeugt seit 0.28 aber fast **leer**
(`buildCarryData`):
| Kategorie | Übernommene Felder |
| Kategorie | Kopierte Felder |
|---|---|
| `INCOME`, `EXPENSE` | nur `teuerungsausgleich` (Basis wird live fortgeschrieben) |
| `AHV` | `gapYears: 0` |
| `PENSION_FUND`, `PILLAR_3A`, `OTHER_ASSET` | `annualContribution`, `expectedReturn` |
| `REAL_ESTATE` | `purchasePrice`, `amortization` (Resthypothek wird live fortgeschrieben) |
| `OTHER_DEBT` | `annualRepayment` |
| `AHV` | `gapYears: 0` Ausfalljahre gelten für genau eine Phase, ein geerbter Wert würde eine Lücke erfinden |
| `REAL_ESTATE` | `purchasePrice` (eine Tatsache, Basis der Grundstückgewinnsteuer) und `interestHandling` (ein Schalter ohne Zahlenwert) |
| alle übrigen | **nichts** |
Bestände (PK-/3a-/Vermögenswert, Resthypothek, Restschuld) werden **bewusst nicht als Snapshot
gespeichert**, sondern in jeder Berechnung live aus der Vorphase fortgeschrieben. Damit wirken
sich nachträgliche Änderungen an frühen Phasen automatisch auf alle Folgephasen aus.
Alles andere wird **nicht kopiert, sondern live vererbt**: Beträge und Bestände werden aus der
Vorphase fortgeschrieben, die **Wiederkehr-Parameter** (Raten, Beiträge, Amortisation,
Wertsteigerung, Zinssatz) gelten weiter, solange das Feld leer bleibt
([3.12.4](#3124-punkt-a-aus-vorphase-übernehmen)). Der Unterschied zeigt sich, sobald man eine
frühe Phase nachträglich ändert: Eine Kopie bliebe stehen, die Vererbung zieht mit.
Referenz: `src/app/api/plans/[planId]/phases/route.ts`.
Referenz: `src/app/api/scenarios/[scenarioId]/phases/route.ts`.
### 3.3.2 Phase bearbeiten
Klick auf einen Phasenkopf öffnet ein **Popup** („Lebensphase: <Name>") mit Bezeichnung und
Dauer konsistent zu allen anderen Eingaben (Element-Zellen, Übergänge). Speichern schliesst
das Popup. Die Dauer wird auch hier gekappt. Eine phasenspezifische Inflationsrate gibt es nicht;
das Panel weist darauf hin: „Die Inflationsrate gilt plan-weit und wird in den Plan-Einstellungen
gesetzt."
Klick auf einen Phasenkopf (oder auf dessen **Stift-Symbol**) öffnet das Panel „Lebensphase:
<Name>" mit Bezeichnung und Dauer. Eine phasenspezifische Inflationsrate gibt es nicht; das
Panel weist darauf hin.
Referenz: `src/components/PhaseDetail.tsx`.
**Die Folgephase gleicht eine geänderte Dauer aus.** Wird eine Phase um N Jahre verlängert, wird
die **nächste** um N Jahre kürzer die Gesamtdauer des Plans bleibt gleich. Das Panel zeigt die
Auswirkung live und fragt vor dem Speichern nach.
Warum das nötig ist: Bis 0.32 kappte das Tool nur die **bearbeitete** Phase am nächsten
Pensionsereignis. Das ist richtig, aber nicht ausreichend. Beispiel: Phase 1 (10 J.) + Phase 2
(10 J.), Pensionierung im Jahr 20. Eine Verlängerung von Phase 1 auf 12 Jahre ist für Phase 1
zulässig danach lief Phase 2 aber von Jahr 12 bis 22 und **überspannte die Pensionierung**.
Da `computePlan` die Dauer nicht nachkappt und den Phasentyp am Phasen*beginn* ableitet, wurde
die Pensionierung faktisch übersprungen; die tragende Invariante aus
[4.16.1](#4161-die-tragende-invariante) war verletzt.
Passt der Ausgleich nicht (die Folgephase fiele unter ein Jahr), wird die Änderung **blockiert**
mit dem Hinweis, um wie viel sie höchstens möglich wäre. Die **letzte** Phase hat keine
Nachfolgerin sie verlängert oder verkürzt den Plan tatsächlich.
Referenz: `planDurationChange` in `src/lib/phaseplan.ts`, `src/components/PhaseDetail.tsx`,
`src/app/api/phases/[phaseId]/route.ts` (setzt beide Dauern in einer Transaktion).
### 3.3.3 Phase löschen
@@ -561,7 +577,7 @@ Referenz: `src/components/PhaseDetail.tsx`.
Phase kann gelöscht werden."). Damit bleibt die Kette der `sequenceNumber` lückenlos. Der
Löschen-Button erscheint im Detail-Panel nur bei der letzten Phase.
Referenz: `src/app/api/phases/[phaseId]/route.ts` Zeilen 5577.
Referenz: `src/app/api/phases/[phaseId]/route.ts`.
## 3.4 Finanzielle Elemente
@@ -584,7 +600,7 @@ Kategorien kein `PERSON_A`/`PERSON_B` übergeben → HTTP 400.
Für die übrigen Kategorien gilt: fehlt die Zuordnung, wird serverseitig `HOUSEHOLD` gesetzt.
Referenz: `src/lib/elements.ts` Zeilen 1923, `src/app/api/plans/[planId]/elements/route.ts` Zeilen 4354.
Referenz: `src/lib/elements.ts` (`PERSON_ONLY_CATEGORIES`), `src/app/api/scenarios/[scenarioId]/elements/route.ts`.
### 3.4.2 Element anlegen
@@ -595,17 +611,28 @@ Bezeichnungs-Default ist das Kategorie-Label.
`orderIndex` = bisheriges Maximum + 1; bestimmt die Reihenfolge innerhalb der Kategoriegruppe.
Referenz: `src/components/PlanView.tsx` Zeilen 799947.
Referenz: `AddElementDialog` in `src/components/PlanView.tsx`.
### 3.4.3 Element bearbeiten und löschen
Ein Klick auf eine **Phasenzelle** öffnet den Dialog „Lebensphase: <Name>" mit den
kategorie- und kontextabhängigen Feldern (siehe [3.4.4](#344-feldkatalog-je-kategorie)) sowie
dem Button „Element löschen". Löschen entfernt das Element **aus allen Phasen**
(Browser-`confirm()`, dann Cascade auf `ElementPhaseValue` und `ElementTransitionValue`).
Ein Klick auf eine **Phasenzelle** öffnet das Panel mit den kategorie- und kontextabhängigen
Feldern (siehe [3.4.4](#344-feldkatalog-je-kategorie)) dort stehen die Werte **dieser Phase**.
Umbenennen ist per API möglich (`PATCH /api/elements/<id>`), im aktuellen UI aber nicht
angebunden.
Die Eigenschaften des **Elements selbst** (Bezeichnung, Zuordnung) sind phasenunabhängig und
haben deshalb ihren eigenen Ort: In der Element-Zeile ganz links stehen drei Symbole
**Stift** (umbenennen und Zuordnung ändern), **Papierkorb** (löschen) und **Expand**
(Detailansicht). Alle drei sind **immer** sichtbar, nicht erst bei Mouseover; auf einem
Touch-Gerät gäbe es sonst keinen Weg dorthin. Denselben Aufbau trägt der **Phasenkopf**.
Die Zuordnung läuft über `ownerRole`, nicht über eine Person-ID deshalb übersteht sie auch
das Neuanlegen der Personen im Profil-Dialog. Für AHV, Pensionskasse und Säule 3a bleibt sie
zwingend personengebunden (HTTP 400 bei „Gemeinsam").
Löschen entfernt das Element **aus allen Phasen** (eigener Bestätigungs-Dialog, dann Cascade auf
`ElementPhaseValue` und `ElementTransitionValue`).
Referenz: `PATCH /api/elements/<id>` (Felder `name`, `ownerRole`), `ElementMetaPanel` in
`src/components/PlanView.tsx`.
### 3.4.4 Feldkatalog je Kategorie
@@ -614,7 +641,7 @@ Die angezeigten Felder hängen von drei Kontextgrössen ab:
- **`ownerWorking`** ob der zugeordnete Besitzer in dieser Phase erwerbstätig ist
- **`durationYears`** Phasendauer (begrenzt z. B. die Ausfalljahre)
Referenz: `src/components/ElementDetail.tsx` Zeilen 124340.
Referenz: `ElementPhaseFields` in `src/components/ElementDetail.tsx`.
#### INCOME (Einkommen)
@@ -669,7 +696,7 @@ Ausgaben beruecksichtigt)" Lohnabzüge sind im Nettoeinkommen bereits weg.
Wie PK, aber:
- Die Einzahlung **zählt** zur Sparquote (verlässt das Cash).
- Das Feld ist auf `PILLAR_3A_MAX_ANNUAL` = **7'258 CHF** (2026, mit PK) hart geklammert.
- Das Feld ist auf `PILLAR_3A_MAX_ANNUAL` = **7'258 CHF** (2026, mit PK) hart geklammert mit dem Schalter «Selbstständig ohne PK» auf `PILLAR_3A_MAX_SELF_EMPLOYED` (Feld `selfEmployed3a`, siehe 4.11).
- Bei Pensionierung: „Die Saeule 3a wird beim Pensions-Uebergang vollstaendig bezogen."
#### REAL_ESTATE (Immobilie)
@@ -947,7 +974,7 @@ in den Modi «Nominal» und «Real» bleibt alles einzeilig.
Es werden zwei verschiedene Deflatoren verwendet siehe [4.5.3](#453-die-drei-deflatoren).
Referenz: `src/components/PlanView.tsx` Zeilen 665699.
Referenz: `src/components/PlanView.tsx` (Anzeige-Umschalter über der Matrix).
### 3.6.2 Zeitachse
@@ -1922,12 +1949,18 @@ Annahme) und die **Zins-Behandlung** (ein Schalter ohne Zahlenwert).
Bestehende Pläne verhalten sich unverändert: Dort sind die Werte gespeichert und gewinnen daher
gegen die Vererbung, bis man das Häkchen aktiv setzt.
### 3.12.5 Punkt C: Verwendung des Kapitalzuflusses
### 3.12.5 Punkt C: Verwendung des bezogenen Alterskapitals
Am Pensions-Übergang kommt oft ein grosser Betrag auf einmal herein (PK-Kapital, Säule 3a,
Verkaufserlös). Ihn vollständig als Cash liegen zu lassen ist selten die Absicht. Im
Cash-Übergang lässt sich deshalb erfassen, wie viel **in Prozent** in die Amortisation der
Hypothek und in eine Anlage fliesst; der Rest bleibt Cash.
Am Pensions-Übergang kommt oft ein grosser Betrag auf einmal herein (PK-Kapital, Säule 3a).
Ihn vollständig als Cash liegen zu lassen ist selten die Absicht. Beim **Bezugs-Entscheid des
jeweiligen Guthabens** lässt sich deshalb erfassen, wie viel **in Prozent** in die Amortisation
der Hypothek und in eine Anlage fliesst; der Rest bleibt Cash.
Die Frage steht seit 0.33 dort, wo der Bezug entschieden wird bei der **Pensionskasse** (nur
wenn Kapital bezogen wird) und bei der **Säule 3a**. Bis 0.32 hing sie am **Cash-Übergang**:
Das war der falsche Ort, weil sich mit zwei Guthaben nicht getrennt festlegen liess, welches
wohin fliesst. Beide Dialoge führen deshalb neu in der Reihenfolge, in der man tatsächlich
entscheidet: **Bezugsart → Betrag brutto → Steuersatz → Betrag netto → Verteilung**.
**Warum Prozent und nicht Franken:** Verschiebt man das Pensionsalter, ändert sich das bezogene
Kapital. Ein Frankenbetrag müsste von Hand nachgezogen werden und würde bis dahin still eine
@@ -1936,7 +1969,17 @@ falsche Aufteilung rechnen. Eine Quote skaliert mit.
Die Amortisations-Quote ist am Restsaldo der Hypothek gekappt; ist sie grösser, bleibt der Rest
Cash. Die Anlage-Quote fliesst in ein wählbares Vermögens-Element (Vorgabe: das erste aktive).
Beide sind mechanisch nichts Neues die eine wirkt wie eine Sonderamortisation, die andere wie
eine Zusatzinvestition, und beide laufen dadurch korrekt durch die zwei Wasserfall-Brücken.
eine Zusatzeinlage, und beide laufen dadurch korrekt durch die zwei Wasserfall-Brücken.
**Der zugeteilte Betrag ist überall sichtbar.** Er wandert über `Carry.capitalIn` in die
**Zusatzeinlage der Folgephase** und erscheint dadurch am Ziel-Element (als eigene, read-only
Zeile «Davon aus Kapitalbezug»), in der Cash-Brücke als **Investition** und im Dialog «Kapital
verteilen». Bis 0.32 erhöhte die Verteilung direkt den internen Bestand Element und Dialog
zeigten deshalb eine **0**, obwohl das Geld geflossen war.
**Die Säule 3a ist am Pensions-Übergang ein offener Entscheid.** Der Bezug selbst steht fest
(sie wird immer ausbezahlt), zu entscheiden sind Steuersatz und Verwendung. Vorher galt der
Übergang als automatisch beantwortet, wodurch die Verwendungsfrage nie gestellt wurde.
Referenz: `src/lib/retirement.ts`, `src/components/RetirementAdjuster.tsx`,
`src/components/FormField.tsx` (`InheritableField`).
@@ -3529,6 +3572,9 @@ den Wert der Vorphase. Alle übrigen Felder bedeuten «nicht gesetzt = 0» wie b
| `extraAmortization` | REAL_ESTATE (Sonderamortisation) | ≥ 0 |
| `saleTaxRate` | REAL_ESTATE | 0100 |
| `immediateRepayment` | OTHER_DEBT | ≥ 0 |
| `capitalUseAmortizationPct` | PENSION_FUND (Kapitalbezug), PILLAR_3A Anteil des bezogenen Kapitals in die Amortisation | 0100 |
| `capitalUseInvestPct` | dito Anteil in eine Anlage | 0100 |
| `capitalUseTargetElementId` | Ziel der Anlage-Quote; ohne Angabe das erste aktive Sonstige Vermögen | ≤ 60 Zeichen |
### 5.4.5 JSON-Payload `CashTransitionData`
@@ -3542,9 +3588,6 @@ Liegt in `Phase.cashTransition`. Validierung über `cashTransitionSchema`.
| `inflowTaxRate` | Steuer auf den Zufluss, Default 0 % | 0100 |
| `outflowLabel` | Bezeichnung der Kosten (z. B. „Poolbau") | ≤ 120 Zeichen |
| `outflowAmount` | Betrag **real** (heutige Kaufkraft) | ≥ 0 |
| `capitalUseAmortizationPct` | Anteil des Kapitalzuflusses in die Amortisation (Kap. 3.12.5) | 0100 |
| `capitalUseInvestPct` | Anteil des Kapitalzuflusses in eine Anlage | 0100 |
| `capitalUseTargetElementId` | Ziel der Anlage-Quote; ohne Angabe das erste aktive Sonstige Vermögen | ≤ 60 Zeichen |
Pro Übergang ist **genau ein** Zufluss und **eine** Kostenposition möglich siehe
[9.7](#97-nur-ein-zufluss-und-eine-kostenposition-pro-übergang).
@@ -3950,15 +3993,15 @@ Include `src/**/*.test.ts`). Es gibt **keine** Komponenten-, API- oder E2E-Tests
| `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 |
| `phaseplan.test.ts` | 8 | Ableitung der Lebensabschnitte aus den Pensionierungszeitpunkten (Einzel/Paar/bereits pensioniert); letzter Teil immer offen |
| `bridges.test.ts` | 13 | Vermögens- und Cash-Brücke gehen über acht Plankonstellationen ohne Restgrösse auf; Umbuchungen bleiben aus der Vermögensbrücke heraus; Kapitalverwendung nach Quote (Punkt C) |
| `phaseplan.test.ts` | 14 | Ableitung der Lebensabschnitte aus den Pensionierungszeitpunkten (Einzel/Paar/bereits pensioniert); letzter Teil immer offen |
| `bridges.test.ts` | 17 | Vermögens- und Cash-Brücke gehen über acht Plankonstellationen ohne Restgrösse auf; Umbuchungen bleiben aus der Vermögensbrücke heraus; Kapitalverwendung nach Quote (Punkt C) |
| `retirement.test.ts` | 16 | Spielraum und Sperren je Person, Verschiebung ohne Änderung der Gesamtdauer, Wegfall einer Phase, Zusammenführung der Übergangs-Entscheide |
| `server-boundary.test.ts` | 1 | statischer Wächter: kein Modul unter `src/lib` importiert aus `src/components` |
| `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 |
| `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** | **278** | |
| **Total** | **288** | |
## 8.2 Testfälle