Init: RoggioApp Architecture, Prisma Schema, API MVP

This commit is contained in:
Clara Zetkin
2026-04-26 19:42:42 +02:00
commit 193b29e8a9
5256 changed files with 1446953 additions and 0 deletions
+58
View File
@@ -0,0 +1,58 @@
# RoggioApp - Analyse: Die Person-Entität (Hard vs. Flexible)
## Die Herausforderung
Was gehört zwingend als harte, durchsuchbare SQL-Spalte in die Tabelle `Person`, und was lagern wir als flexible Eigenschaft (Trait) in das JSONB-Feld oder in Relationen aus?
## Sevs Entwurf & Claras Analyse
### 1. Originär (Die Person selbst)
* **Vorname & Nachname:** ✅ Absolut notwendig. Harte SQL-Spalten. (Ggf. um `nickname` als Spalte erweitern).
* **Geburtsdatum:** ✅ Harte Spalte (für Altersberechnungen, Kurtaxe, Meldescheine extrem wichtig).
* **Mobile-Nr & Private E-Mail:** ⚠️ *Diskussion:* Sind die eindeutig?
* *Realität:* Oft buchen Ehepaare oder Familien mit nur *einer* gemeinsamen Mailadresse oder Handynummer.
* *Lösung:* Wir dürfen `email` und `phone` **nicht** auf `UNIQUE` (Einzigartig) in der Datenbank setzen! Sie bleiben harte SQL-Spalten für die schnelle Suche, aber Doppelungen sind erlaubt.
### 2. Relational / Flexibel (Die Eigenschaften)
* **Anrede (Pronouns / Title):** -> JSONB (`traits`). (Ändert sich gesellschaftlich, JSONB ist hier flexibler als ein harter SQL-Enum).
* **Identity-Dokument (Perso/Passport):** -> JSONB (`traits`).
* *Warum:* Die Felder variieren stark je nach Land (Ausgestellt in, Gültig bis, Behörde). Ein JSONB-Objekt `identity_document: { type: "passport", number: "...", valid_until: "..." }` ist hier perfekt.
* **Geburtsort:** -> JSONB (`traits`).
* **Adresse (Wohnort):** -> ⚠️ *Eigene Tabelle!*
* *Warum:* Eine Adresse (Straße, Stadt, Land) kann von 5 Familienmitgliedern oder einer Firma geteilt werden. Wir bauen eine Tabelle `Address` und verknüpfen die Person(en) per ID damit. Das spart immense Redundanz.
* **Finanz-Infos (IBAN etc.):** -> JSONB (`traits`).
### 3. Logisch durch den Graphen gelöst (Architektur-Bonus)
* **Buchungsverlauf:** Wird *nicht* in der Person gespeichert. Ergibt sich zu 100% aus den `Event`-Knoten, die mit der Person (oder ihrer Gruppe) verknüpft sind.
* **Loginrights:** Werden nicht gespeichert. Das übernimmt die Nextcloud (SSO). Wir speichern nur die `ssoId`.
* **Type (Kollektiv / Client / Personal):** Wird *nicht* als hartes Feld gespeichert! Ergibt sich aus den `GroupMembership`-Verknüpfungen (z.B. wenn Person A Mitglied in der Operator-Gruppe ist, ist sie Personal).
* **Groups & Groupfunction:** Wird 1:1 durch unsere Pivot-Tabelle `GroupMembership` (inkl. `role`) abgebildet.
## Claras Vorschlag für die finale Prisma-Tabelle `Person`
```prisma
model Person {
id String @id @default(uuid())
firstName String @db.VarChar(100)
lastName String @db.VarChar(100)
nickname String? @db.VarChar(100)
birthDate DateTime? @db.Date
// Kontaktdaten (NICHT UNIQUE!)
email String? @db.VarChar(255)
phone String? @db.VarChar(50)
// Verknüpfung zur Authentifizierung
ssoId String? @unique @db.VarChar(255)
// Die Wohnadresse (Relational)
addressId String?
address Address? @relation(fields: [addressId], references: [id])
// Alles andere (Pass, Finanzen, Anrede, Geburtsort, Allergien)
traits Json @default("{}")
groupMemberships GroupMembership[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
```