Files
FPT/prisma/schema.prisma
T

160 lines
4.8 KiB
Plaintext

// FPT (Financial Planning Tool) — Datenmodell.
// Kernkonzept (Rework 07/2026): finanzielle Elemente leben auf PLAN-Ebene und sind
// ueber alle Lebensphasen hinweg dieselbe Entitaet. Pro Element existiert je Lebensphase
// ein Werte-Datensatz (ElementPhaseValue) und je Uebergang ein Entscheid-Datensatz
// (ElementTransitionValue). Die kategorie-/kontextspezifischen Felder liegen als JSON,
// validiert und typisiert in der Applikationsschicht (lib/elements.ts).
generator client {
provider = "prisma-client"
output = "../src/generated/prisma"
}
datasource db {
provider = "postgresql"
}
model User {
id String @id @default(cuid())
username String @unique
passwordHash String
createdAt DateTime @default(now())
households Household[]
}
enum HouseholdType {
SINGLE
COUPLE
}
enum PersonRole {
PERSON_A
PERSON_B
}
enum OwnerRole {
PERSON_A
PERSON_B
HOUSEHOLD
}
enum ElementCategory {
INCOME
EXPENSE
AHV
PENSION_FUND
PILLAR_3A
REAL_ESTATE
OTHER_ASSET
OTHER_DEBT
}
// Ein Haushalt (1 oder 2 Personen), gehoert genau einem Benutzer.
model Household {
id String @id @default(cuid())
userId String
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
householdType HouseholdType
inflationRateDefault Float
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
persons Person[]
plans Plan[]
}
// Einzelperson im Haushalt. retirementAge ist die Standard-Annahme (im Plan uebersteuerbar).
model Person {
id String @id @default(cuid())
householdId String
household Household @relation(fields: [householdId], references: [id], onDelete: Cascade)
role PersonRole
age Int
retirementAge Int
@@unique([householdId, role])
}
// Eine vollstaendige Phasenkette; kann Szenario eines anderen Plans sein.
// retirementAgeA/B uebersteuern das Pensionsalter der jeweiligen Person NUR fuer diesen
// Plan (null = Standard aus Person.retirementAge) -- ermoeglicht Fruehpensions-Szenarien.
model Plan {
id String @id @default(cuid())
householdId String
household Household @relation(fields: [householdId], references: [id], onDelete: Cascade)
name String
retirementAgeA Int?
retirementAgeB Int?
parentPlanId String?
parentPlan Plan? @relation("PlanScenarios", fields: [parentPlanId], references: [id], onDelete: SetNull)
scenarios Plan[] @relation("PlanScenarios")
branchFromPhaseId String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
phases Phase[]
elements FinancialElement[]
}
// Ein Lebensabschnitt innerhalb eines Plans. Der Phasentyp (Erwerb/Pension/Mischung)
// wird NICHT gespeichert, sondern aus Alter + Pensionsalter abgeleitet (lib/calculations).
model Phase {
id String @id @default(cuid())
planId String
plan Plan @relation(fields: [planId], references: [id], onDelete: Cascade)
sequenceNumber Int
name String
durationYears Int
inflationRate Float?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
phaseValues ElementPhaseValue[]
transitionValues ElementTransitionValue[] @relation("TransitionFromPhase")
@@unique([planId, sequenceNumber])
}
// Ein finanzielles Element (plan-weit): Kategorie + optionale Personenzuordnung.
model FinancialElement {
id String @id @default(cuid())
planId String
plan Plan @relation(fields: [planId], references: [id], onDelete: Cascade)
category ElementCategory
name String
ownerRole OwnerRole?
orderIndex Int @default(0)
createdAt DateTime @default(now())
phaseValues ElementPhaseValue[]
transitionValues ElementTransitionValue[]
}
// Werte eines Elements INNERHALB einer Lebensphase (kategorie-/kontextspezifisch, JSON).
model ElementPhaseValue {
id String @id @default(cuid())
elementId String
element FinancialElement @relation(fields: [elementId], references: [id], onDelete: Cascade)
phaseId String
phase Phase @relation(fields: [phaseId], references: [id], onDelete: Cascade)
data Json
@@unique([elementId, phaseId])
}
// Entscheid/Werte eines Elements beim UEBERGANG nach der Phase fromPhase (JSON).
model ElementTransitionValue {
id String @id @default(cuid())
elementId String
element FinancialElement @relation(fields: [elementId], references: [id], onDelete: Cascade)
fromPhaseId String
fromPhase Phase @relation("TransitionFromPhase", fields: [fromPhaseId], references: [id], onDelete: Cascade)
data Json
@@unique([elementId, fromPhaseId])
}