Modul-Review 2: Onboarding-Umbau, Tour, Assistenten-Redesign
Deploy App / deploy (push) Successful in 1m10s
Deploy App / deploy (push) Successful in 1m10s
Ergebnis der zweiten Test- und Review-Runde (Modul "Onboarding & Plan-Erstellung"): Layout: - Szenario-Ansicht neu geordnet: schlanke Funktions-Leiste oben (Historie, Tour, Neues Szenario, Rechenwege, CSV-Export, Loeschen, Diff-Badge), dann Naechste Schritte -> Grundprofil -> Zeitachse -> Anzeige -> Matrix - Grafiken/Effektive Werte/Live-Sim/MC/Einflussfaktoren aus der Leiste entfernt (laufen ueber die eigenen Menuepunkte) - Tour nach AppShell gehoben; startet neu bei JEDER Plan-Erstellung (F14) Assistent: - durchgehend Du-Form im Einzelmodus - Schritt "Vorsorge & Vermoegen" nur noch Bestandswerte - neuer Schritt "Sparen & Verteilen": Sparquote (Netto - Ausgaben) auf 3a/Wertschriften/Amortisation/Tilgung verteilen, Rest bleibt Cash; PK separat mit Hinweis "vor Netto, reduziert Sparquote nicht" - Immobilie: Wertsteigerung + Zins-in-Ausgaben-Schalter; Lohn 1% Default Grosse Saeule 3a (Selbststaendige ohne PK): - Schalter am 3a-Element + im Assistenten hebt Obergrenze 7258 -> 36288 - neue Konstante PILLAR_3A_MAX_SELF_EMPLOYED (2026-Wert zu verifizieren) - neues Feld selfEmployed3a Nebenbei: POST /plans liefert lesbare Fehlermeldung statt zod-Objekt. Kein Eingriff in den Rechenkern; 267 Tests unveraendert. SPEZIFIKATION 0.28. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+48
-10
@@ -4,10 +4,10 @@
|
||||
| | |
|
||||
|---|---|
|
||||
| **Dokument** | Funktionale und Technische Spezifikation FPT |
|
||||
| **Version** | 0.27 |
|
||||
| **Version** | 0.28 |
|
||||
| **Datum** | 2026-07-24 |
|
||||
| **Status** | Lebendes Dokument |
|
||||
| **Codestand** | Arbeitsstand nach `d6855ef` inkl. Sicherheits-Nachbesserungen Auth (Branch `main`) |
|
||||
| **Codestand** | Arbeitsstand nach `2bb243b` inkl. Modul-Review 2 (Onboarding) (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.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. |
|
||||
| 0.27 | 2026-07-24 | Claude (Opus 4.8) | **Modul-Review 1 (Zugang & App-Rahmen): fünf Nachbesserungen an der Authentifizierung.** Ergebnis der ersten gemeinsamen Test- und Review-Runde. (1) **Timing-Ausgleich beim Login:** Ein unbekannter Benutzer wird neu gegen einen Dummy-bcrypt-Hash geprüft, damit die Antwortzeit dieselbe ist wie bei einem bekannten -- vorher liess sich aus der Dauer ablesen, ob ein Benutzername existiert (Kap. 3.1.2). (2) **Zurück-Knopf nach Logout:** Die aus dem Browser-Cache (bfcache) zurückgeholte, eingefrorene Ansicht prüft neu beim `pageshow` die Session und leitet ohne Anmeldung sofort auf `/login` -- vorher blieb die alte Ansicht sichtbar (Kap. 3.1.3). (3) **Rate-Limiting:** Login (10/15 min je IP), Registrierung (5/h je IP) und Passwortänderung (10/15 min je Benutzer) sind gegen Durchprobieren gebremst; neues In-Memory-Modul `rate-limit.ts`, 429 mit `Retry-After` (Kap. 3.1.6). Der Login-Zähler läuft je IP **und Benutzername** -- ein Konto sperrt nicht die anderen Konten derselben IP. (4) **Passwort-Dialog** läuft neu über die zentrale `Modal`-Komponente und schliesst damit auf Esc (Fokus-Falle, aria-modal inklusive) -- war zuvor von Hand gebaut (Kap. 3.1.4). (5) **Registrierungs-Fehler** werden sauber getrennt: nur der belegte Benutzername ist ein 409 mit freundlicher Meldung, jeder andere Fehler ein 500 statt einer rohen Prisma-Meldung als Konflikt. 6 Tests ergänzt (261 → 267). Offen für Roadmap #34: kein Passwort-Längen-Maximum (bcrypt-72-Byte-Grenze), keine ARIA-Labels auf Login/Palette. |
|
||||
| 0.26 | 2026-07-21 | Claude (Opus 4.8) | **Pensionsalter anpassen** (Roadmap Nr. 44, neue Kapitel 3.12, 4.4.7 und 4.16). Bisher war das Pensionsalter faktisch unantastbar: Es bestimmt, wo eine Lebensphase endet – ein frei geändertes Alter hätte die Phasengrenze zerrissen. Neu wird nicht das Alter geändert, sondern **die Grenze verschoben**: Die Phase davor wird länger, die danach kürzer, die Gesamtdauer bleibt gleich. Der Spielraum endet dort, wo eine angrenzende Phase unter ein Jahr fiele; ein Schritt weiter **entfällt sie ganz**, was vorher bestätigt wird, weil dabei zwei Übergänge **zusammengelegt** werden (bereits getroffene Entscheide bleiben, leere Felder werden aus dem entfallenden Übergang ergänzt, einmalige Cash-Beträge werden addiert – der Steuersatz betragsgewichtet). Das Pensionsalter ist damit auch **Treiber im Tornado** und **Regler in der Live-Simulation**. **AHV-Referenzalter (4.4.7):** Die Rente beginnt neu **immer mit 65**, unabhängig vom Pensionsalter – wer länger arbeitet, erhält sie zusätzlich zum Lohn; wer früher aufhört, zahlt bis 65 einen **Beitrag als Nichterwerbstätige(r)**, der als laufende Ausgabe auf die Verzehrquote schlägt und mit 65 wegfällt (neues Feld `ahvContribution`, ohne Default, Hilfetext nennt die reale Bandbreite von rund 530 bis 26'500 CHF pro Jahr). Beide Wechsel können **innerhalb** einer Phase liegen, die AHV wird deshalb **jahresweise** statt phasenweise gerechnet. **Punkt B:** Ein Einkommen, das einer **Person** zugeordnet ist, fällt bei deren Pensionierung auf 0 – bisher lief der Lohn stillschweigend in die Pension weiter. Gemeinsame Einkommen (Mieterträge o. Ä.) bleiben; ein ausdrücklich erfasster Betrag gewinnt, damit ein Teilzeitpensum modellierbar bleibt. **Punkt A:** Wiederkehr-Parameter (Raten, Beiträge, Amortisation, Wertsteigerung, Zinssatz) werden neu **live aus der Vorphase geerbt** statt beim Anlegen der Phase kopiert – sichtbar als angehaktes **«Aus Vorphase übernehmen»** je Feld. Vorher blieb die Kopie stehen, wenn man die Vorphase später änderte. **Punkt C:** Der Kapitalzufluss am Pensions-Übergang (PK, 3a, Verkaufserlös) lässt sich in **Prozent** auf Amortisation, Anlage und Cash aufteilen – bewusst nicht in Franken, weil sich der Betrag mit dem Pensionsalter ändert und eine Quote mitskaliert. **Nebenbei ein echter Fehler behoben:** Der fortgeschriebene Basiswert für Einkommen und Ausgaben wurde **vor** der Jahresschleife berechnet – effektive Werte kamen dadurch nie in der Folgephase an. Neues Modul `retirement.ts`, neuer Endpunkt `POST /api/scenarios/<id>/retirement`; 40 Tests ergänzt (221 → 261). |
|
||||
| 0.25 | 2026-07-21 | Claude (Opus 4.8) | **PDF-Berichte** (Roadmap Nr. 11, neues Kapitel 3.11). Neuer Unterpunkt **«Berichte»** auf Plan-Ebene: Liste der erzeugten Berichte plus Assistent zum Anlegen (Titel, Notiz, nominal **oder** real, Plan- oder effektive Daten, bis zu **drei** Szenarien, beliebige gespeicherte Analysen). Das **Layout ist immer gleich**; die Auswahl bestimmt nur, welche Bausteine erscheinen: Deckblatt mit Zusammenfassung und drei Kernaussagen, dann je Szenario Kennzahlen, Vermögensverlauf, Lebensphasen und Annahmen, danach Vergleich, Plan/Ist, Analysen und die Hinweise. **Die PDF-Datei wird als Datei abgelegt** (BYTEA in Postgres, nicht im Container-Dateisystem, das jeder Deploy neu baut): Ein Bericht muss in drei Jahren byte-identisch wieder herunterladbar sein – eine Neuerzeugung könnte das nach Änderungen an Plan, Rechenkern oder Layout nicht garantieren. **Kennzahlen je Szenario:** Endvermögen, Kapitalreichweite, Vermögen und Vorsorgekapital bei Pensionierung, AHV- und PK-Rente sowie die **offenen Entscheide** – die einzige unmittelbar handlungsleitende Zahl. Damit Bericht und Matrix nie verschiedene Zahlen nennen, liegt deren Zählung neu als reine Funktion in `decisions.ts`, die beide benutzen. **Zu jeder Kennzahl steht ihre Grundlage** als kurzer Verweis; die vollständigen Annahmen (Startwerte, Renditen, Raten je Element) stehen **einmal** je Szenario, statt bei jeder Kennzahl wiederholt zu werden. Ein **Haftungsausschluss** ist verpflichtend und durch einen Test gesichert – ein formal gesetztes PDF wird sonst als Beratung gelesen. **Technik:** `pdfkit` in der Node-Runtime statt Headless-Browser (kein Chromium im Image); `@react-pdf/renderer` schied aus, weil es mit React 19 / Next 16 bricht. Diagramme entstehen als **echte Vektoren** aus den gespeicherten Zahlen – genau dafür wurden die Analysen in 0.24 als Zahlen und nicht als Bilder abgelegt. `pdfkit` ist als externes Paket deklariert, weil es Font-Metriken über Dateipfade lädt und gebündelt erst in der Produktion bräche. Neue Tabelle `Report`, Endpunkte unter `/api/plans/<id>/reports`, neue Module `report.ts`, `report-pdf.ts`, `decisions.ts`; 9 Tests ergänzt (212 → 221). |
|
||||
@@ -411,8 +412,10 @@ gesetzt. Kalenderjahr eines Planjahrs: `startYear + (Jahr − 1)`.
|
||||
### 3.2.8 Geführter Assistent und Beispielplan
|
||||
|
||||
**Der Plan-Assistent** (Roadmap Nr. 10: «Schritt für Schritt statt leerer Matrix») fragt in
|
||||
fünf Schritten in Alltagssprache: (1) Grundprofil, (2) Lebensphasen, (3) Einkommen und Ausgaben
|
||||
plus Kontostand, (4) Vorsorge und Vermögen, (5) Zusammenfassung.
|
||||
**sechs** Schritten in Alltagssprache: (1) Grundprofil, (2) Lebensphasen, (3) Einkommen und
|
||||
Ausgaben plus Kontostand, (4) Vorsorge und Vermögen (**nur Bestandswerte**), (5) Sparen und
|
||||
Verteilen, (6) Zusammenfassung. Im **Einzelmodus** durchgehend in **Du-Form** («Was verdienst
|
||||
du?»); im Paarmodus je Person bzw. «ihr».
|
||||
|
||||
**Schritt 2 ist an den fixen Pensionierungszeitpunkten ausgerichtet.** Das Pensionsalter jeder
|
||||
Person ist ein Fixpunkt auf der Lebenslinie; dazwischen entstehen Abschnitte mit konstantem
|
||||
@@ -444,7 +447,22 @@ Phasen lesbar bleiben.
|
||||
|
||||
**Schritt 4 (Vorsorge & Vermögen)** ist bei Paaren in **Gemeinsam / Person A / Person B**
|
||||
aufgeteilt. Pensionskasse und Säule 3a sind immer persönlich (personengebundene Kategorien);
|
||||
Wertschriften, Wohneigentum und Schulden lassen sich gemeinsam **oder** je Person erfassen.
|
||||
Wertschriften, Wohneigentum und Schulden lassen sich gemeinsam **oder** je Person erfassen. Hier
|
||||
werden nur die **heutigen Bestandswerte** erfasst (Guthaben, Kaufpreis, Hypothek, Restschuld) –
|
||||
die laufenden Jahresbeträge folgen in Schritt 5. Zusätzlich fragt das Wohneigentum die
|
||||
**Wertsteigerung** und den **Zins-in-Ausgaben-Schalter** ab (damit Hypothekarzinsen nicht
|
||||
doppelt zählen), und die Säule 3a einen Schalter **«Selbstständig ohne PK (grosse Säule 3a)»**,
|
||||
der die Beitrags-Obergrenze anhebt (siehe 4.11 / Feld `selfEmployed3a`).
|
||||
|
||||
**Schritt 5 (Sparen & Verteilen)** bringt das Kernmodell des Tools zum Anfassen: Aus
|
||||
`Nettoeinkommen − Ausgaben` entsteht die **Sparquote**; der Nutzer verteilt sie auf Säule 3a,
|
||||
Wertschriften, Amortisation und Schuldtilgung, und der **Rest bleibt sichtbar auf dem
|
||||
Cash-Konto** (live gerechnet, negativer Rest wird gewarnt). Die **PK-Einzahlung** steht bewusst
|
||||
in einem **eigenen** Block mit dem Hinweis, dass sie vom **Bruttolohn** bezahlt wird – also
|
||||
**vor** dem Nettoeinkommen – und die Sparquote deshalb **nicht** schmälert. Das deckt sich exakt
|
||||
mit dem Rechenkern, wo der PK-Beitrag nicht zur Quote zählt ([4.6.3](#463-pension_fund)). Der
|
||||
Schritt entfällt fachlich nie, aber wenn keine Spar-/Vorsorgeposten angehakt sind, weist er nur
|
||||
darauf hin, dass der ganze Betrag auf dem Cash-Konto wächst.
|
||||
|
||||
Zwei bewusste Entscheide bleiben:
|
||||
- **Einkommen wird pro Person erfasst**, nie als «Gemeinsam» – in Paar-Plänen zählt
|
||||
@@ -1273,13 +1291,31 @@ Neuaufbau des Formulars wie zuvor bei den Dialogen.
|
||||
Der frühere Dialog «Plan-Einstellungen» heisst im Panel korrekt **«Szenario-Profil»** – er
|
||||
bearbeitet seit V6 das Szenario, nicht den Plan.
|
||||
|
||||
**Aufbau der Szenario-Ansicht (seit 0.28):** von oben nach unten eine schlanke
|
||||
**Funktions-Leiste** (Änderungshistorie · Tour · Neues Szenario aus diesem · Rechenwege ·
|
||||
CSV-Export · Szenario löschen · Abweichungs-Badge), dann **Nächste Schritte**, das
|
||||
**Grundprofil**, die **Zeitachse**, der **Anzeige-Umschalter** (Nominal/Beide/Real, Plan/Ist)
|
||||
und zuunterst die **Matrix** mit ihren «Element»-/«Lebensphase»-Knöpfen. Die Analyse-Werkzeuge
|
||||
(Grafiken, Live-Simulation, Monte-Carlo, Einflussfaktoren) und die Effektiven Werte sind hier
|
||||
bewusst **nicht** mehr verlinkt – sie laufen ausschliesslich über ihre eigenen Menüpunkte
|
||||
([3.10](#310-navigation-auf-plan-ebene-und-gespeicherte-analysen)), damit es je Funktion genau
|
||||
einen Ort gibt.
|
||||
|
||||
### 3.7.8 Tour und «Nächste Schritte»
|
||||
|
||||
Die **Tour** (`Tour.tsx`) startet einmalig beim ersten Öffnen eines Plans mit Phasen
|
||||
(localStorage `fpt-tour-done`) und führt in bis zu sechs Schritten über Profil, Zeitachse,
|
||||
Matrix, Übergänge, Cash und Analysen – als Karte am unteren Rand plus pulsierender Rahmen um
|
||||
das Ziel (`data-tour`-Attribute). Schritte ohne vorhandenes Ziel werden übersprungen; der
|
||||
«Tour»-Knopf in der Werkzeugleiste startet sie jederzeit neu. Grenze: 9.24.
|
||||
Die **Tour** (`Tour.tsx`) führt in bis zu sechs Schritten über Profil, Zeitachse, Matrix,
|
||||
Übergänge, Cash und Analysen – als Karte am unteren Rand plus pulsierender Rahmen um das Ziel
|
||||
(`data-tour`-Attribute). Schritte ohne vorhandenes Ziel werden übersprungen; der «Tour»-Knopf
|
||||
in der oberen Funktions-Leiste startet sie jederzeit neu. Grenze: 9.24.
|
||||
|
||||
Sie liegt seit 0.28 in `AppShell` (nicht mehr in `PlanView`), weil dort die Plan-Erstellung
|
||||
zusammenläuft, und hat **zwei Auslöser**: Nach **jeder** Plan-Erstellung (Assistent,
|
||||
Beispielplan, leerer Plan) startet sie **einmal** – unabhängig davon, ob sie schon beendet
|
||||
wurde (die Erfolgsmeldung «die Tour zeigt dir gleich …» hält damit ihr Versprechen). Zusätzlich
|
||||
startet sie beim ersten Öffnen eines bestehenden Plans mit Phasen, solange sie noch nie beendet
|
||||
wurde (localStorage `fpt-tour-done`). Ein aus dem DOM gelesenes Ziel setzt voraus, dass die
|
||||
Szenario-Ansicht bereits gerendert ist; der Auslöser feuert deshalb erst, wenn das Szenario
|
||||
geladen ist.
|
||||
|
||||
Die Karte **«Nächste Schritte»** über der Matrix leitet aus den vorhandenen Daten ab, was
|
||||
sinnvollerweise als Nächstes ansteht – offene Übergangs-Entscheide (mit Direktsprung in den
|
||||
@@ -2455,6 +2491,7 @@ Zentral in `src/lib/constants.ts` geführt, weil sie sich periodisch durch Bunde
|
||||
| `AHV_FULL_CONTRIBUTION_YEARS` | 44 | Volle Beitragsdauer (Rentenskala 44) |
|
||||
| `AHV_REFERENCE_AGE` | 65 | Referenzalter – ab hier fliesst die Rente, **unabhängig vom Pensionsalter** ([4.4.7](#447-referenzalter-die-rente-beginnt-mit-65-nicht-mit-der-pensionierung)) |
|
||||
| `PILLAR_3A_MAX_ANNUAL` | 7'258 | Max. 3a-Beitrag/Jahr für PK-Versicherte (2026) |
|
||||
| `PILLAR_3A_MAX_SELF_EMPLOYED` | 36'288 | Max. 3a-Beitrag/Jahr «grosse Säule 3a» (Selbstständige ohne PK). **2026-Wert zu verifizieren** (2025: 36'288) |
|
||||
| `DEFAULT_PK_CONVERSION_RATE` | 6 % | Umwandlungssatz |
|
||||
| `DEFAULT_CAPITAL_TAX_RATE` | 8 % | Kapitalbezugssteuer |
|
||||
| `DEFAULT_PROPERTY_GAINS_TAX_RATE` | 20 % | Grundstückgewinnsteuer |
|
||||
@@ -3338,6 +3375,7 @@ Referenz: `prisma/schema.prisma` Zeilen 4–6, `src/lib/elements.ts` Zeilen 48
|
||||
| `startValue` | OTHER_ASSET, OTHER_DEBT | ≥ 0 |
|
||||
| `expectedReturn` | PK, 3a, OTHER_ASSET | −50 bis 100 |
|
||||
| `annualContribution` | PK, 3a, OTHER_ASSET | ≥ 0 |
|
||||
| `selfEmployed3a` | PILLAR_3A – «grosse Säule 3a» (Selbstständige ohne PK) → höhere Obergrenze | Boolean |
|
||||
| `annualWithdrawal` | OTHER_ASSET | ≥ 0 |
|
||||
| `additionalInvestment` | PK, 3a, OTHER_ASSET (ab Phase 2) | ≥ 0 |
|
||||
| `purchasePrice` | REAL_ESTATE | ≥ 0 |
|
||||
|
||||
Reference in New Issue
Block a user