Pensionierungs-Bildschirm, Ampel mit drei Zustaenden, Planungshorizont

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-26 13:37:08 +02:00
parent 9907fda6f4
commit 1865db5de7
12 changed files with 1181 additions and 130 deletions
@@ -0,0 +1,41 @@
import { NextRequest, NextResponse } from "next/server";
import { prisma } from "@/lib/db";
import { getOwnedElement } from "@/lib/queries";
import { getCurrentUserId } from "@/lib/session";
import { touchScenario } from "@/lib/versioning-db";
import { RETIREMENT_CATEGORIES, retirementDecisionSchema } from "@/lib/retirement-decision";
// Speichert den Pensionierungs-Entscheid eines Elements (AHV, PK, Säule 3a).
//
// Bewusst OHNE Phasenbezug in der Route: Der Entscheid gilt für die Pensionierung des
// Besitzers, wo immer die auf der Zeitachse gerade liegt. Genau das unterscheidet ihn vom
// Übergangs-Entscheid (`/transition/<fromPhaseId>`), der an einer konkreten Grenze hängt.
export async function PUT(
request: NextRequest,
{ params }: { params: Promise<{ elementId: string }> }
) {
const userId = await getCurrentUserId();
if (!userId) return NextResponse.json({ error: "Nicht authentifiziert." }, { status: 401 });
const { elementId } = await params;
const element = await getOwnedElement(elementId, userId);
if (!element) return NextResponse.json({ error: "Element nicht gefunden." }, { status: 404 });
if (!RETIREMENT_CATEGORIES.includes(element.category)) {
return NextResponse.json(
{ error: "Nur AHV, Pensionskasse und Säule 3a kennen einen Pensionierungs-Entscheid." },
{ status: 400 }
);
}
const body = await request.json();
const parsed = retirementDecisionSchema.safeParse(body);
if (!parsed.success) return NextResponse.json({ error: "Ungültige Eingabe." }, { status: 400 });
await prisma.financialElement.update({
where: { id: elementId },
data: { retirementDecision: parsed.data },
});
await touchScenario(element.scenarioId, userId);
return NextResponse.json({ ok: true });
}