Files
yourpart3/docs/FALUKANT_SERVANTS_IMPLEMENTATION_SPEC.md

629 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Falukant: Dienerschaft Daemon-, Technik- und Umsetzungs-Spezifikation
Dieses Dokument bündelt die umsetzungsreife Spezifikation für das Dienerschaftssystem in einer Datei.
Es ersetzt für die technische Umsetzung die sonst übliche Aufteilung in:
- Daemon-Spec
- Daemon-Handoff
- technisches Konzept
- Implementierungs-Backlog
Die fachliche Grundidee bleibt in [FALUKANT_SERVANTS_CONCEPT.md](/mnt/share/torsten/Programs/YourPart3/docs/FALUKANT_SERVANTS_CONCEPT.md) beschrieben. Dieses Dokument hier ist die Arbeitsgrundlage für Implementierung und Daemon-Anbindung.
## 1. Zielbild
Die Dienerschaft ist ein Haussystem mit vier Kernwerten:
- `servantCount`
- `servantQuality`
- `servantPayLevel`
- `householdOrder`
Diese Werte wirken auf:
- monatliche Kosten
- Repräsentation und Ansehen
- Komfort und Ordnung des Haushalts
- Ehezufriedenheit und Haushaltsfrieden
- Diskretion bei Liebschaften
- spätere Untergrund-Aufdeckungen
## 2. Systemgrenzen
In Scope der ersten Version:
- Dienerschaft hängt an `user_house`
- House-UI zeigt und verändert Dienerwerte
- externer Daemon verarbeitet Daily- und Monthly-Effekte
- Familie, Liebschaften und Untergrund nutzen die resultierenden Werte mit
Nicht in Scope der ersten Version:
- einzelne benannte Diener
- eigene Dienerrollen wie Küchenpersonal, Wachen, Zofen
- eigene Eventketten nur für Diener
- finales Balancing
## 3. Datenmodell
### 3.1 Bereits vorhandene Hausfelder
In `falukant_data.user_house`:
- `servant_count integer not null default 0`
- `servant_quality integer not null default 50`
- `servant_pay_level varchar(20) not null default 'normal'`
- `household_order integer not null default 55`
### 3.2 Wertebereiche
- `servant_count`: `0..999`
- `servant_quality`: `0..100`
- `servant_pay_level`: `low | normal | high`
- `household_order`: `0..100`
### 3.3 Abgeleitete Werte
Diese Werte müssen nicht persistent gespeichert werden, sondern können im Backend oder Daemon berechnet werden:
- `expectedServantsMin`
- `expectedServantsMax`
- `staffingState`
- `orderState`
- `monthlyServantCost`
- `discretionModifier`
- `servantReputationModifier`
- `marriageComfortModifier`
## 4. Erwartungswert der Dienerschaft
Die Sollgröße hängt von Haus und Stand ab.
### 4.1 Basis nach Hausposition
`house.house_type.position` ist die grobe Hausklasse.
Empfohlene erste Regel:
| Hausposition | Basis Min | Basis Max |
|-------------|-----------|-----------|
| `<= 2` | 0 | 1 |
| `3` | 1 | 2 |
| `4` | 2 | 4 |
| `5` | 3 | 6 |
| `>= 6` | 4 | 8 |
### 4.2 Standesbonus
Aus `character.noble_title.level`:
```text
titleBonus = floor(level / 3), mindestens 0
expectedMin = baseMin + titleBonus
expectedMax = baseMax + titleBonus
```
### 4.3 Zustandsklassen
```text
if servantCount < expectedMin => understaffed
if servantCount > expectedMax => overstaffed
sonst => fitting
```
## 5. Daily-Regeln für den externen Daemon
## 5.1 Daily-Input
Pro Falukant-User mit Haus braucht der Daemon:
- `falukant_user.id`
- `user.id` bzw. `user.hashed_id` für Benachrichtigung
- `character.id`
- `character.reputation`
- `character.noble_title_id` und idealerweise `character.nobleTitle.level`
- `user_house.house_type_id`
- `house_type.position`
- `house_type.cost`
- `servant_count`
- `servant_quality`
- `servant_pay_level`
- `household_order`
- optional für Verknüpfungen:
- `marriage_satisfaction` oder `relationship_state.marriage_satisfaction`
- aktive Liebschaften mit `visibility`, `discretion`, `risk`
## 5.2 Daily-Hilfswerte
```text
payShift(low) = -6
payShift(normal) = 0
payShift(high) = +6
missing = max(0, expectedMin - servantCount)
excessive = max(0, servantCount - expectedMax)
qualityPart = round((servantQuality - 50) * 0.35)
payPart = payShift(servantPayLevel)
fitPenalty = missing * 10 + excessive * 4
```
## 5.3 Daily-Zielwert für Haushaltsordnung
```text
targetHouseholdOrder = clamp(
55 + qualityPart + payPart - fitPenalty,
0,
100
)
```
## 5.4 Daily-Drift der Haushaltsordnung
Die Ordnung springt nicht hart, sondern driftet langsam:
```text
newHouseholdOrder = oldHouseholdOrder
if oldHouseholdOrder < targetHouseholdOrder:
newHouseholdOrder += min(2, targetHouseholdOrder - oldHouseholdOrder)
if oldHouseholdOrder > targetHouseholdOrder:
newHouseholdOrder -= min(2, oldHouseholdOrder - targetHouseholdOrder)
```
Zusatzregel:
- bei `servantPayLevel = low` und `servantCount < expectedMin` zusätzlich `-1`
- bei `servantPayLevel = high` und `servantQuality >= 65` zusätzlich `+1`
Danach clamp auf `0..100`.
## 5.5 Daily-Drift der Dienerqualität
Die Qualität ändert sich langsam:
```text
qualityDelta = 0
if servantPayLevel = low: qualityDelta -= 1
if servantPayLevel = high: qualityDelta += 1
if servantCount < expectedMin: qualityDelta -= 1
if servantCount > expectedMax + 2: qualityDelta -= 1
if householdOrder >= 80: qualityDelta += 1
if householdOrder <= 30: qualityDelta -= 1
```
Danach:
- auf `-2..+2` pro Tag begrenzen
- `servantQuality = clamp(servantQuality + qualityDelta, 0, 100)`
## 5.6 Daily-Effekt auf Ansehen
Der Daily-Rufeffekt ist klein, damit Monats- und Ereigniseffekte wichtiger bleiben.
```text
reputationDelta = 0
if titleLevel >= 4 and servantCount < expectedMin:
reputationDelta -= 0.15 * missing
if titleLevel <= 1 and servantCount > expectedMax:
reputationDelta -= 0.10 * excessive
if householdOrder >= 85 and servantCount between expectedMin and expectedMax:
reputationDelta += 0.05
if householdOrder <= 25:
reputationDelta -= 0.20
```
Rundung:
- intern als Dezimalwert möglich
- falls nur Ganzzahlen gespeichert werden, über Tagespuffer oder Rundungsregel aggregieren
## 5.7 Daily-Effekt auf Ehe / Haushalt
Wenn ein Ehe-Zufriedenheitssystem vorhanden ist:
```text
marriageDelta = 0
if householdOrder >= 75: marriageDelta += 0.10
if householdOrder <= 35: marriageDelta -= 0.15
if servantCount < expectedMin: marriageDelta -= 0.10
```
Wenn noch kein eigener Wert gespeichert wird:
- diese Regel für später vormerken
- aktuell nur `householdTension` oder UI-Ableitungen beeinflussen
## 5.8 Daily-Effekt auf Liebschaften / Diskretion
Der Daemon berechnet einen Diskretionsmodifikator:
```text
discretionModifier = 0
if servantQuality >= 70 and servantPayLevel = high and servantCount <= expectedMax:
discretionModifier -= 8
if servantPayLevel = low:
discretionModifier += 6
if servantCount > expectedMax + 1:
discretionModifier += 4
if householdOrder <= 35:
discretionModifier += 5
```
Bedeutung:
- negativer Wert verbessert Geheimhaltung
- positiver Wert erhöht Entdeckungsrisiko
Anwendung:
- bei aktiven Liebschaften auf Sichtbarkeit/Skandalchance
- bei Untergrundaktivitäten als Erfolgsmodifikator
## 5.9 Daily-Notifications
Daily sendet nicht für jede Teildrift ein eigenes Event.
Wenn sich einer dieser Punkte relevant verändert:
- `household_order`
- `servant_quality`
- `reputation`
- Ehe-/Liebschaftsfolgen über Diener
dann:
- `falukantUpdateFamily` mit `reason: "daily"`
- danach `falukantUpdateStatus`
Es gibt keinen separaten `reason` für Dienerschaft.
## 6. Monthly-Regeln für den externen Daemon
## 6.1 Monthly-Input
Wie Daily, zusätzlich:
- aktuelles Geld `falukant_user.money`
## 6.2 Monatskosten
```text
basePerServant = max(20, round((houseType.cost / 1000) + 40))
qualityFactor = 1 + ((servantQuality - 50) / 200)
payFactor(low) = 0.8
payFactor(normal) = 1.0
payFactor(high) = 1.3
monthlyServantCost = servantCount * basePerServant * qualityFactor * payFactor
```
Auf 2 Nachkommastellen runden.
## 6.3 Abbuchung
Wenn genügend Geld vorhanden:
- Geld abziehen
- Aktivität z. B. `servants_monthly`
Wenn nicht genügend Geld vorhanden:
- so viel wie möglich abziehen oder auf 0 fallen lassen, je nach vorhandener Gesamtlogik
- Unterversorgung markieren
Empfehlung für die erste Version:
- vollständige Abbuchung nur wenn genug Geld da
- sonst `underfunded = true`
## 6.4 Folgen von Unterversorgung
Bei Unterversorgung im Monat:
```text
servantQuality -= 4
householdOrder -= 6
```
Zusätzlich:
- wenn `titleLevel >= 4`: `reputation -= 1`
- wenn aktive Liebschaften vorhanden: Diskretionsmalus für den Folgemonat
## 6.5 Monatsbonus bei gutem Haushalt
Wenn gleichzeitig:
- `servantCount` innerhalb Sollbereich
- `servantQuality >= 70`
- `householdOrder >= 80`
- `servantPayLevel != low`
dann:
- `reputation += 1` für hohe Stände ab `titleLevel >= 3`
- kleiner Ehe-/Komfortbonus, falls System vorhanden
## 6.6 Monthly-Notifications
Nach Monatsverarbeitung:
- `falukantUpdateFamily` mit `reason: "monthly"`
- danach `falukantUpdateStatus`
## 7. Handoff an den externen Daemon
## 7.1 Der externe Daemon muss lesen
Aus Backend/DB:
- `falukant_data.user_house`
- `falukant_type.house`
- `falukant_data.falukant_user`
- `falukant_data.character`
- Titel/Stand
- optional aktive Ehe-/Liebschaftsdaten
## 7.2 Der externe Daemon muss schreiben
Mindestens:
- `user_house.servant_quality`
- `user_house.household_order`
- `character.reputation` oder entsprechender Rufwert
Optional, falls vorhanden:
- `relationship_state.marriage_satisfaction`
- Hilfs-/Logtabellen für Monatskosten und Unterversorgung
## 7.3 Der externe Daemon muss senden
Bei relevanten Änderungen:
- `falukantUpdateFamily`
- `falukantUpdateStatus`
`reason` nur:
- `daily`
- `monthly`
Keine zusätzlichen Diener-Reason-Werte.
## 7.4 Idempotenz
Der Daemon muss verhindern, dass Daily/Monthly doppelt auf denselben Tick laufen.
Empfohlen:
- eigene Tick-Marker außerhalb dieses Projekts
- oder Zeitstempel in Worker-Logs
## 8. Backend-Aufgaben in diesem Projekt
## 8.1 Bereits erledigt
- Hausfelder in `user_house`
- Migration
- Produktions-SQL
- House-API mit Dienerwerten
- UI in `HouseView`
- direkte Spieleraktionen:
- einstellen
- entlassen
- Bezahlungsstufe ändern
## 8.2 Noch sinnvolle Backend-Nacharbeiten
- eigenes Money-Label für Monatskosten, z. B. `servants_monthly`
- optional eigener Read-Endpunkt nur für Dienerschaft
- optionale Validierungsgrenzen serverseitig weiter schärfen
- später: Ableitung von `householdTension` stärker an Diener koppeln
## 9. UI-Anforderungen
Die House-UI soll anzeigen:
- aktuelle Dienerzahl
- Sollbereich
- Monatskosten
- Qualität
- Haushaltsordnung
- Bezahlungsstufe
- Besetzungsstatus
- Ordnungsstatus
Die UI soll direkt erlauben:
- `+1` Diener
- `-1` Diener
- Pay-Level wechseln
Die UI braucht keine Daemon-Sonderlogik außer normalen House-/Status-Refresh.
## 10. API-Schnittstellen
Bereits vorgesehen:
- `GET /api/falukant/houses`
- `POST /api/falukant/houses/servants/hire`
- `POST /api/falukant/houses/servants/dismiss`
- `POST /api/falukant/houses/servants/pay-level`
### Beispiel-Response für `GET /houses`
```json
{
"roofCondition": 100,
"wallCondition": 100,
"floorCondition": 100,
"windowCondition": 100,
"servantCount": 3,
"servantQuality": 58,
"servantPayLevel": "normal",
"householdOrder": 63,
"houseType": {
"id": 5,
"position": 5,
"cost": 273000,
"labelTr": "family_house"
},
"servantSummary": {
"expectedMin": 3,
"expectedMax": 6,
"monthlyCost": 925.4,
"staffingState": "fitting",
"orderState": "stable"
}
}
```
## 11. Technische Architektur
### 11.1 Quelle der Wahrheit
Quelle der Wahrheit für:
- Stammdaten und persistente Hauswerte: dieses Backend / Datenbank
- Tick-Ausführung: externer Daemon
### 11.2 Verantwortungstrennung
Dieses Projekt:
- speichert Werte
- bietet UI und API
- berechnet einfache Hilfswerte für Anzeige
Externer Daemon:
- tägliche und monatliche Veränderung
- Kostenabbuchung
- Reputationseffekte
- Verknüpfung mit Familie, Liebschaften und Untergrund
### 11.3 Warum so
Damit:
- Spiellogik nicht doppelt tickt
- UI trotzdem schon benutzbar ist
- der Daemon später nur auf stabile Felder aufsetzen muss
## 12. Implementierungs-Backlog
## B1 Datenbasis
Status: erledigt
Aufgaben:
- Hausfelder in `user_house`
- Migration
- Produktions-SQL
Done:
- Felder vorhanden
- Model aktualisiert
## B2 Haus-Service
Status: erledigt
Aufgaben:
- Sollbereich berechnen
- Monatskosten berechnen
- Zustandslabels ableiten
Done:
- `servantSummary` wird im House-Read geliefert
## B3 Spieleraktionen
Status: erledigt
Aufgaben:
- einstellen
- entlassen
- Bezahlung ändern
Done:
- Endpunkte vorhanden
- UI verdrahtet
## B4 House-UI
Status: erledigt
Aufgaben:
- Anzeige in `HouseView`
- Aktionen
- Locale-Texte
Done:
- HouseView zeigt den Dienerblock
## B5 Daemon Daily
Status: offen
Aufgaben:
- `expectedMin/Max` im Worker berechnen
- `householdOrder` driften
- `servantQuality` driften
- kleinen Reputationseffekt anwenden
- Diskretionsmodifikator für Liebschaften ableiten
- `daily`-Refresh senden
Done-Kriterien:
- täglicher Tick verändert Hauswerte nachvollziehbar
- keine zusätzlichen UI-Reason-Werte nötig
## B6 Daemon Monthly
Status: offen
Aufgaben:
- Monatskosten berechnen
- Geld abbuchen
- Unterversorgung behandeln
- Monatsrufeffekte anwenden
- `monthly`-Refresh senden
Done-Kriterien:
- Monatskosten und Unterversorgung sind im Spiel spürbar
## B7 Integration mit Familie / Liebschaften
Status: offen
Aufgaben:
- `householdOrder` auf Ehekomfort mappen
- Diskretionsmodifikator in Skandal-/Liebschaftslogik einbeziehen
- schlechte Bezahlung oder Überbesetzung als Gerüchtefaktor nutzen
Done-Kriterien:
- Dienerschaft beeinflusst Familien- und Liebschaftssystem real
## B8 Integration mit Untergrund
Status: offen
Aufgaben:
- `investigate_affair` nutzt Dienerwerte
- schlechter Haushalt erhöht Aufdeckungschance
- guter, diskreter Haushalt senkt Erfolgswahrscheinlichkeit
Done-Kriterien:
- Untergrund spürt Dienerschaft in Erfolgsmodifikatoren
## B9 Balancing
Status: offen, bewusst spätere Phase
Aufgaben:
- Kosten, Rufwerte, Driftgeschwindigkeiten und Schwellwerte feinjustieren
## 13. Produktionshinweise
Wenn keine Migrationen laufen:
- [add_servants_to_user_house.sql](/mnt/share/torsten/Programs/YourPart3/backend/sql/add_servants_to_user_house.sql) ausführen
Der externe Daemon muss erst danach aktiviert werden, damit die Felder sicher vorhanden sind.
## 14. Empfehlung für die nächste Reihenfolge
Empfohlene Reihenfolge ab jetzt:
1. Produktions-SQL einspielen
2. B5 Daily im externen Daemon
3. B6 Monthly im externen Daemon
4. B7 Familie/Liebschaften anbinden
5. B8 Untergrund anbinden
6. B9 Balancing
## 15. Kurzfazit
Die Haus- und UI-Basis ist bereits eingebaut. Für eine vollständige Spielwirkung fehlen jetzt vor allem die beiden externen Worker-Blöcke:
- tägliche Drift
- monatliche Kosten und Folgen
Mit dieser Datei sollte der externe Daemon direkt implementierbar sein, ohne weitere Konzeptdokumente zu benötigen.