feat(bisaya-course): expand exercises for shopping, neighborhood visits, conflict resolution, and free speaking
All checks were successful
Deploy to production / deploy (push) Successful in 2m57s

- Added new exercises in multiple-choice, gap-fill, and situational response formats for categories including 'Einkaufen vertiefen', 'Nachbarschaft & Besuche', 'Rollenspiel - Konflikt und Hilfe', and 'Freies Sprechen - Alltag ohne Stütze'.
- Each exercise includes detailed instructions, question data, answer data, and explanations to enhance the learning experience for Bisaya language learners.
- Focused on practical scenarios to improve conversational skills and vocabulary retention.
This commit is contained in:
Torsten Schulz (local)
2026-03-31 09:04:24 +02:00
parent 53f0745faf
commit 6b3aee458a
2 changed files with 706 additions and 0 deletions

View File

@@ -0,0 +1,178 @@
# Falukant: Geplante Schwangerschaft & Geburt Daemon- und Datenbankkonzept
Dieses Dokument beschreibt das **vereinheitlichte Konzept** für Schwangerschaft, die der **externe Daemon** (`UserCharacterWorker`, C++) verarbeiten soll, sowie die **Datenbank** und die **Abgrenzung zur bestehenden Zufallslogik**. Ziel ist, dass gesetzte Termine (`pregnancy_due_at`) und der gewählte Vater (`pregnancy_father_character_id`) u.a. aus dem Admin-Tool **tatsächlich zu Geburten führen**, ohne dass nur die Node-API „Geburt erzwingen“ funktioniert.
---
## 1. Ist-Zustand (Problem)
### 1.1 Datenbank (bereits vorhanden)
Auf `falukant_data."character"` existieren (siehe `backend/sql/add_character_pregnancy.sql`):
| Spalte | Typ | Bedeutung |
|--------|-----|-----------|
| `pregnancy_due_at` | `TIMESTAMPTZ` NULL | Erwarteter Geburtstermin |
| `pregnancy_father_character_id` | `INTEGER` NULL, FK auf `character(id)` | Vater-Charakter |
Die **Node-Backend**-Logik (Admin, `falukantService`) **liest und schreibt** diese Felder.
### 1.2 Daemon aktuelles Verhalten
In `src/usercharacterworker.cpp` / `src/usercharacterworker.h`:
- `processPregnancies()` führt **`QUERY_GET_PREGNANCY_CANDIDATES`** aus.
- Diese Query:
- bezieht sich **nur** auf Ehen (`falukant_type.relationship.tr = 'married'`),
- nutzt **keine** `pregnancy_*`-Spalten,
- modelliert Geburten **per Zufallsprozess** (altersabhängige Wahrscheinlichkeit),
- setzt implizit **`character1_id` = Vater** und **`character2_id` = Mutter** (fest verdrahtet, ohne Geschlechts- oder Rollenprüfung).
**Folge:** Wer im Spiel oder per Admin als „schwanger“ mit Termin und Vater gespeichert wird, **wird vom Daemon nicht erkannt**. Geburten aus diesem Konzept passieren nur, wenn sie **manuell** per Node (z.B. Admin „Geburt erzwingen“) ausgelöst werden.
**Zusätzlich:** `QUERY_AUTOBATISM` setzt nur `child_relation.name_set` nach einigen Tagen hat **nichts** mit Schwangerschafts-Spalten zu tun.
---
## 2. Soll-Konzept (Zwei parallele Wege, eine klare Priorität)
### 2.1 Weg A **Geplante Schwangerschaft** (DB-gesteuert, neu für den Daemon)
**Auslöser:** `pregnancy_due_at` ist gesetzt und der Zeitpunkt ist **fällig**.
**Regeln (Vorschlag):**
1. **Eine** Mutter ist immer der Datensatz in `character`, auf dem `pregnancy_due_at` und die Schwangerschaft „liegen“.
2. **Vater:** `pregnancy_father_character_id`
- Wenn gesetzt: muss ein existierender Charakter sein, **nicht** `mother.id`.
- Wenn `NULL`: Policy festlegen (siehe Abschnitt 8).
3. **Fälligkeit:** z.B. `date_trunc('day', pregnancy_due_at AT TIME ZONE 'Europe/Berlin') <= current_date` (oder einheitlich **UTC** wichtig ist **eine** Definition im Team).
4. Nach erfolgreicher Geburt: **`pregnancy_due_at` und `pregnancy_father_character_id` auf NULL** setzen (Schwangerschaft beendet).
Dieser Weg entspricht dem, was Admin und Spieler erwarten, wenn ein **Termin** existiert.
### 2.2 Weg B **Legacy: Zufallsgeburten bei Ehe** (bestehende Query)
Die Query `QUERY_GET_PREGNANCY_CANDIDATES` modelliert **„natürliche“** Zufallsgeburten ohne `pregnancy_*`-Felder.
**Entscheidung für die Umsetzung:**
- **Option B1:** Weg B **abschalten** oder stark reduzieren, wenn Weg A das offizielle Modell ist.
- **Option B2:** Weg B **beibehalten** für Atmosphäre, aber **nur**, wenn **keine** aktive geplante Schwangerschaft auf den betroffenen Charakteren existiert (doppelte Geburten vermeiden).
- **Option B3:** Weg B nur noch **Simulation**, bis Spiel-Logik „Konzeption“ explizit setzt (größerer Umbau).
**Empfehlung:** Mindestens **B2** oder **B1**, damit keine zwei Geburten pro Tag für dieselbe Ehe aus unterschiedlichen Regeln entstehen.
---
## 3. Datenbank Erweiterungen (Vorschlag)
Die Minimalvariante kommt **ohne** neue Spalten aus (nur Daemon-Logik). Für Robustheit und spätere Features sind **optionale** Erweiterungen sinnvoll:
### 3.1 Pflicht (kein Schema-Zwang, aber empfohlen)
- **Index** für den Daemon-Tick, z.B.:
```sql
CREATE INDEX IF NOT EXISTS idx_character_pregnancy_due
ON falukant_data."character" (pregnancy_due_at)
WHERE pregnancy_due_at IS NOT NULL;
```
### 3.2 Optional Metadaten
| Spalte | Typ | Zweck |
|--------|-----|--------|
| `pregnancy_source` | `TEXT` oder `ENUM` | z.B. `admin`, `gameplay`, `npc` für Logging und Regeln |
| `pregnancy_conception_at` | `TIMESTAMPTZ` | optional, für Anzeige/Quests |
| `pregnancy_birth_context` | `TEXT` | `marriage` | `lover` für korrekten `child_relation.birth_context` ohne Heuristik |
Wenn `pregnancy_birth_context` **nicht** eingeführt wird, leitet der Daemon den Kontext aus der **Beziehung** zwischen Mutter und Vater ab (verheiratet → `marriage`, Liebhaber → `lover`, sonst Default `marriage` oder Policy).
### 3.3 `child_relation` Parität mit Node
Das Sequelize-Modell erwartet u.a. `father_name`, `mother_name`, `legitimacy`, `birth_context`, `public_known`. Die **Daemon-INSERT**-Query (`QUERY_INSERT_CHILD_RELATION`) muss mit der **realen DB** übereinstimmen (Pflichtfelder, Defaults). Falls nötig:
- INSERT um **Namen** (aus Vordefiniert-Tabellen) und **legitimacy / birth_context / public_known** erweitern,
- oder DB-Defaults / Trigger ergänzen,
- **gleiche Semantik** wie `adminForceFalukantBirth` in `adminService.js` anstreben.
---
## 4. Daemon Umsetzung (technisch)
### 4.1 Neue SQL-Query: „fällige geplante Geburten“
**Skizze (logisch):**
- SELECT Mutter-`character` `c` mit:
- `c.pregnancy_due_at IS NOT NULL`
- `c.pregnancy_due_at` fällig (siehe Zeitzone)
- JOIN Vater `c_father` auf `c.pregnancy_father_character_id = c_father.id` **wenn** Vater Pflicht ist
- Pro Zeile: `father_cid`, `mother_cid`, `region_id`, `title_of_nobility` (vom passenden Elternteil), `last_name`, `father_uid`, `mother_uid` analog zur bestehenden Schleife.
**Wichtig:** Vater/Mutter **nicht** aus `relationship.character1/2` ableiten, sondern aus **expliziten IDs** (`pregnancy_father_character_id` + Zeilen-ID der Mutter).
### 4.2 Ablauf in `processPregnancies()`
1. `QUERY_AUTOBATISM` wie bisher (optional, Reihenfolge beachten).
2. **Neu:** Transaktion oder feste Reihenfolge:
- Kandidaten für **geplante Geburt** laden
- **pro Kandidat:** Kind einfügen (`QUERY_INSERT_CHILD` oder gemeinsame Funktion), `child_relation` einfügen, **Schwangerschaft** auf der Mutter **leeren**
- Benachrichtigungen (`children_update`, `falukantUpdateStatus`) wie bei bestehender Schleife
3. **Legacy-Query** nur ausführen, wenn nach Absprache (Option B1B3).
**Idempotenz:** Pro Tick darf dieselbe schwangere Zeile **nicht** zweimal gebären. Am sichersten: **UPDATE … RETURNING** oder **DELETE** der Schwangerschaftsdaten in derselben Transaktion wie das Kind.
### 4.3 Geschlecht der Eltern
Optional: Plausibilitätsprüfung (`gender` Mutter/Vater) kann im ersten Schritt weggelassen werden, sollte aber langfristig mit dem Spielregelwerk übereinstimmen.
---
## 5. Backend (Node) Abstimmung
- **Zeitzonen:** `pregnancy_due_at` wird in JS als `Date` gesetzt; Daemon muss **dieselbe** Fälligkeitsdefinition nutzen wie die UI („heute“ = 0 Tage).
- **WebSocket:** Nach Daemon-Geburt dieselben Events wie bei Admin-Geburt, damit Clients die Familie aktualisieren.
---
## 6. Frontend
- Hinweis in der Familien-Ansicht: „Geburt erfolgt automatisch am Termin“ (wenn Daemon aktiv), sonst „nur nach Admin-Aktion“ je nach Rollout.
---
## 7. Test-Checkliste
- [ ] Admin: Schwangerschaft mit Termin **heute** und Vater nach Daemon-Lauf: Kind existiert, Schwangerschaft weg.
- [ ] Kein Vater (`NULL`) definiertes Verhalten (Fehler loggen / überspringen / NPC-Vater **Policy**).
- [ ] Doppel-Tick: keine doppelte Geburt.
- [ ] Legacy-Zufallsgeburt: keine Kollision mit aktivem `pregnancy_due_at` auf derselben Mutter.
- [ ] `child_relation` und `character`-Kind konsistent mit Node-Admin-Geburt.
---
## 8. Offene Policy-Fragen (bitte vor Implementierung festlegen)
1. **Vater `NULL`:** Geburt abbrechen, stillen Vater aus Beziehung erraten, oder festen Platzhalter?
2. **Legacy-Query:** komplett entfernen oder nur noch unter Bedingungen?
3. **Zeitzone** für „Termin ist heute“: Server-UTC, Europe/Berlin, oder Nutzer-TZ?
4. **Liebschaftsgeburten:** nur über `pregnancy_*` + `birth_context`/`pregnancy_birth_context`, nie über reine Ehe-Query?
---
## 9. Referenzdateien im Repo
| Bereich | Datei |
|---------|--------|
| Daemon | `src/usercharacterworker.cpp` (`processPregnancies`) |
| SQL-Strings | `src/usercharacterworker.h` (`QUERY_GET_PREGNANCY_CANDIDATES`, `QUERY_INSERT_CHILD`, `QUERY_INSERT_CHILD_RELATION`) |
| DB-Spalten Schwangerschaft | `backend/sql/add_character_pregnancy.sql` |
| Modell Character | `backend/models/falukant/data/character.js` |
| Admin / Geburt Node | `backend/services/adminService.js` (`adminForceFalukantPregnancy`, `adminForceFalukantBirth`) |
| Familie API | `backend/services/falukantService.js` (`_getCharacterPregnancyOptional`, `getFamily`) |
---
*Stand: technische Analyse des Repos; zur Abstimmung mit Game-Design und Deployment des Daemons.*