Einmalige Sonderein-/ausgaben am Cash-Uebergang (Roadmap Nr. 1)
Deploy App / deploy (push) Successful in 1m51s

Der Cash-Uebergang zwischen zwei Phasen ist neu ein eigener Entscheid:
1:1 uebernehmen / einmaliger Zufluss / einmalige Kosten / beides. Die Betraege
gehen direkt aufs Cash-Konto und bleiben aus der Spar-/Verzehrquote heraus.

- Zufluss NOMINAL erfasst, real angezeigt (wie Einkommen), optionaler Steuersatz
  (Default 0 %). Kosten REAL erfasst, nominal angezeigt (wie Ausgaben).
  Umrechnung ueber den Bestands-Deflator an der Phasengrenze.
- Entscheid startet unbeantwortet und zaehlt im "offen"-Badge mit; eine neue Phase
  erzeugt damit automatisch einen offenen Cash-Entscheid am neuen Uebergang.
- Eigene Kopf-Kennzahlen statt Vermischung mit Kapitalzufluss/-investitionen:
  eine Erbschaft ist kein Verkaufserloes, ein Poolbau keine Investition.
- Cash ist kein FinancialElement -> der Entscheid haengt als JSON an der Von-Phase
  (neue Spalte Phase.cashTransition + Migration). Szenario-Kopie nimmt ihn mit.

Fuenf Regressionstests ergaenzt (13 -> 18). Spezifikation auf v0.3.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-17 08:14:44 +02:00
parent 87e6a5f564
commit 9f5bd754eb
12 changed files with 665 additions and 30 deletions
+29
View File
@@ -97,10 +97,39 @@ export interface TransitionData {
immediateRepayment?: number;
}
// --- Cash-Uebergang: einmalige Sonderein-/ausgaben ---
// Entscheid am UEBERGANG zwischen zwei Phasen, direkt auf dem Cash-Konto (Cash ist kein
// Element, der Entscheid haengt darum an der Von-Phase). Erfassungs-Konventionen analog zu
// den laufenden Flows: Zufluss NOMINAL (wie Einkommen), Kosten REAL (wie Ausgaben).
export type CashTransitionMode = "NONE" | "INFLOW" | "OUTFLOW" | "BOTH";
export interface CashTransitionData {
mode?: CashTransitionMode;
// Einmaliger Zufluss (z. B. Erbschaft): NOMINAL erfasst, Steuersatz optional (Default 0 %).
inflowLabel?: string;
inflowAmount?: number;
inflowTaxRate?: number;
// Einmalige Kosten (z. B. Poolbau): REAL erfasst (heutige Kaufkraft).
outflowLabel?: string;
outflowAmount?: number;
}
// --- Zod-Schemas (nachsichtig: unbekannte Felder werden verworfen) ---
const nonNeg = z.number().min(0);
export const cashTransitionSchema = z
.object({
mode: z.enum(["NONE", "INFLOW", "OUTFLOW", "BOTH"]).optional(),
inflowLabel: z.string().max(120).optional(),
inflowAmount: nonNeg.optional(),
inflowTaxRate: z.number().min(0).max(100).optional(),
outflowLabel: z.string().max(120).optional(),
outflowAmount: nonNeg.optional(),
})
.strip();
export const phaseDataSchema = z
.object({
amount: nonNeg.optional(),