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:
@@ -4,6 +4,7 @@ import { useState } from "react";
|
||||
import { Trash2 } from "lucide-react";
|
||||
import { AlertTriangle } from "lucide-react";
|
||||
import { FieldLabel, InheritableField, MoneyField, NumberField, SelectField, TextField } from "@/components/FormField";
|
||||
import { InfoBubble } from "@/components/InfoBubble";
|
||||
import { formatChf } from "@/lib/format";
|
||||
import { api } from "@/lib/api-client";
|
||||
// Die reinen Uebergangs-Regeln liegen in lib/transitions.ts (auch serverseitig nutzbar) und
|
||||
@@ -31,6 +32,7 @@ import {
|
||||
DEFAULT_PK_CONVERSION_RATE,
|
||||
DEFAULT_PROPERTY_GAINS_TAX_RATE,
|
||||
PILLAR_3A_MAX_ANNUAL,
|
||||
PILLAR_3A_MAX_SELF_EMPLOYED,
|
||||
} from "@/lib/constants";
|
||||
import type {
|
||||
CashTransitionData,
|
||||
@@ -664,10 +666,12 @@ export function ElementPhaseFields({
|
||||
)}
|
||||
</>
|
||||
);
|
||||
case "PILLAR_3A":
|
||||
case "PILLAR_3A": {
|
||||
if (!context.ownerWorking) {
|
||||
return <p className="col-span-2 text-sm text-muted">Die Säule 3a wird beim Pensions-Übergang vollständig bezogen.</p>;
|
||||
}
|
||||
// «Grosse Säule 3a» für Selbstständige ohne PK: höhere Obergrenze (Roadmap-Feedback C7c).
|
||||
const max3a = pd.selfEmployed3a ? PILLAR_3A_MAX_SELF_EMPLOYED : PILLAR_3A_MAX_ANNUAL;
|
||||
return (
|
||||
<>
|
||||
{carried ? (
|
||||
@@ -677,21 +681,30 @@ export function ElementPhaseFields({
|
||||
label="Zusatzeinlage aus Kapital (CHF)"
|
||||
help="Aufstockung aus dem verfügbaren Kapital dieser Phase."
|
||||
value={num(pd.additionalInvestment)}
|
||||
|
||||
|
||||
onChange={(v) => setP({ additionalInvestment: v })}
|
||||
/>
|
||||
</>
|
||||
) : (
|
||||
<MoneyField label="Aktueller 3a-Wert (CHF)" value={num(pd.currentValue)} onChange={(v) => setP({ currentValue: v })} />
|
||||
)}
|
||||
<label className="col-span-2 flex cursor-pointer items-center gap-2 text-xs text-muted">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={!!pd.selfEmployed3a}
|
||||
onChange={(e) => setP({ selfEmployed3a: e.target.checked })}
|
||||
/>
|
||||
Selbstständig ohne Pensionskasse («grosse Säule 3a»)
|
||||
<InfoBubble text={`Selbstständigerwerbende ohne PK dürfen bis 20 % des Nettoerwerbseinkommens einzahlen, gedeckelt auf ca. ${PILLAR_3A_MAX_SELF_EMPLOYED.toLocaleString("de-CH")} CHF – statt der ${PILLAR_3A_MAX_ANNUAL.toLocaleString("de-CH")} CHF mit PK.`} />
|
||||
</label>
|
||||
{inh(
|
||||
"annualContribution",
|
||||
"Jährliche Einzahlung (CHF)",
|
||||
(v, set) => (
|
||||
<MoneyField label="Jährliche Einzahlung (CHF)" value={v} max={PILLAR_3A_MAX_ANNUAL} onChange={set} />
|
||||
<MoneyField label="Jährliche Einzahlung (CHF)" value={v} max={max3a} onChange={set} />
|
||||
),
|
||||
asChf,
|
||||
`Maximal CHF ${PILLAR_3A_MAX_ANNUAL.toLocaleString("de-CH")} (2026, mit PK) und höchstens die Sparquote. Wird von der Sparquote abgezogen.`
|
||||
`Maximal CHF ${max3a.toLocaleString("de-CH")} (2026, ${pd.selfEmployed3a ? "Selbstständig ohne PK" : "mit PK"}) und höchstens die Sparquote. Wird von der Sparquote abgezogen.`
|
||||
)}
|
||||
{inh(
|
||||
"expectedReturn",
|
||||
@@ -701,6 +714,7 @@ export function ElementPhaseFields({
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
case "REAL_ESTATE": {
|
||||
// Zinsbetrag zu Phasenbeginn und -ende: die Restschuld sinkt mit der Amortisation,
|
||||
// der Zinsbetrag also mit. Am Nullpunkt gekappt (analog zur Berechnung).
|
||||
|
||||
Reference in New Issue
Block a user