Navigation auf Plan-Ebene und gespeicherte Analysen (Roadmap-Redesign)
Deploy App / deploy (push) Successful in 1m45s

Sidebar zweistufig: pro Plan die Unterpunkte Szenarien / Effektive Werte /
Analysen; Klick auf Plan-Name oeffnet ein Plan-Dashboard.

Plan-Dashboard: Kennzahlen, gerechnete Werte ausdruecklich "laut
Basisszenario", Ist-Abweichung falls erfasst.

Szenario-Liste: Version, Elementzahl, Endvermoegen, Ruinalter + Aktionen
Historie und Matrix. Baum in der Sidebar bleibt.

Analysen: vier umklappende Kacheln (auch per Antippen). Grafiken oeffnen
neu mit Auswahl EINER Grafik. Szenario-Vergleich zu den Grafiken,
CSV-Export auf die Matrix.

Gespeicherte Analysen: Grafik/MC/Einflussfaktoren als ZAHLEN einfrieren
(read-only, nichts wird neu gerechnet) -- druckfaehig fuer den spaeteren
PDF-Bericht, ohne finalWealthSorted. Einheitliche generische Ergebnisform.

Neue Tabelle SavedAnalysis, Endpunkte /analyses und /dashboard, Module
analyses.ts, Komponenten PlanViews/SavedAnalysisView/SaveAnalysisButton.
Kein Eingriff in den Rechenkern. Spezifikation 0.24 (3.10 und 9.30 neu).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-20 22:21:02 +02:00
parent ce5f83823f
commit fb70781e5b
19 changed files with 1720 additions and 113 deletions
@@ -0,0 +1,43 @@
-- Gespeicherte Analysen (SPEZIFIKATION 3.10).
--
-- Eingefroren werden EINGABEN und ERGEBNIS als Zahlen -- nicht als Bild. Beim Oeffnen wird
-- nichts neu gerechnet, die gespeicherten Werte werden nur gezeichnet. Zahlen statt Pixel,
-- weil der spaetere PDF-Bericht (Roadmap Nr. 11) daraus vektoriell und in Druckaufloesung
-- zeichnen kann; ein Bildschirm-Bitmap waere im Druck unscharf und im Format fix.
--
-- Bewusst NICHT gespeichert wird `finalWealthSorted` aus der Monte-Carlo-Simulation: ein
-- Eintrag je Lauf, bei 10'000 Laeufen also megabyteweise. Fuer die Anzeige genuegen die
-- abgelesenen Wahrscheinlichkeiten und die Baender.
CREATE TABLE "SavedAnalysis" (
"id" TEXT NOT NULL,
"planId" TEXT NOT NULL,
"name" TEXT NOT NULL,
-- CHART | MONTE_CARLO | SENSITIVITY. Als Text statt Enum, damit spaetere Typen (etwa
-- ein Berichts-Zusammenzug) keine Schema-Migration brauchen.
"type" TEXT NOT NULL,
-- Kerndaten fuer die Liste, denormalisiert: So laesst sich die Uebersicht anzeigen, ohne
-- die (groesseren) JSON-Felder zu laden.
"scenarioName" TEXT,
"versionLabel" TEXT,
"metric" TEXT NOT NULL DEFAULT 'nominal',
"source" TEXT NOT NULL DEFAULT 'PLAN',
"summary" TEXT,
"inputs" JSONB NOT NULL DEFAULT '{}',
"result" JSONB NOT NULL DEFAULT '{}',
"createdById" TEXT NOT NULL,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "SavedAnalysis_pkey" PRIMARY KEY ("id")
);
CREATE INDEX "SavedAnalysis_planId_createdAt_idx" ON "SavedAnalysis"("planId", "createdAt");
ALTER TABLE "SavedAnalysis" ADD CONSTRAINT "SavedAnalysis_planId_fkey"
FOREIGN KEY ("planId") REFERENCES "Plan"("id") ON DELETE CASCADE ON UPDATE CASCADE;
ALTER TABLE "SavedAnalysis" ADD CONSTRAINT "SavedAnalysis_createdById_fkey"
FOREIGN KEY ("createdById") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
+31
View File
@@ -35,6 +35,7 @@ model User {
plans Plan[]
versions ScenarioVersion[]
actuals ActualsSet[]
analyses SavedAnalysis[]
}
enum HouseholdType {
@@ -111,6 +112,36 @@ model Plan {
scenarios Scenario[]
actuals ActualsSet[]
persons PlanPerson[]
analyses SavedAnalysis[]
}
// Eine festgehaltene Analyse (Roadmap Nr. 5 / Analysen-Ansicht). Haelt EINGABEN und ERGEBNIS
// als Zahlen fest -- read-only, es wird nichts neu gerechnet. Zahlen statt Bild, damit der
// spaetere PDF-Bericht daraus vektoriell zeichnen kann.
model SavedAnalysis {
id String @id @default(cuid())
planId String
plan Plan @relation(fields: [planId], references: [id], onDelete: Cascade)
name String
type String // CHART | MONTE_CARLO | SENSITIVITY
// Denormalisierte Kerndaten fuer die Liste.
scenarioName String?
versionLabel String?
metric String @default("nominal")
source String @default("PLAN")
summary String?
inputs Json @default("{}")
result Json @default("{}")
createdById String
createdBy User @relation(fields: [createdById], references: [id], onDelete: Cascade)
createdAt DateTime @default(now())
@@index([planId, createdAt])
}
// Ein erfasster Stand der WIRKLICHKEIT zu einem Stichtag (Roadmap Nr. 5).