Files
yourpart3/docs/FALUKANT_SERVANTS_IMPLEMENTATION_SPEC.md

14 KiB
Raw Blame History

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 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:

titleBonus = floor(level / 3), mindestens 0
expectedMin = baseMin + titleBonus
expectedMax = baseMax + titleBonus

4.3 Zustandsklassen

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

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

targetHouseholdOrder = clamp(
  55 + qualityPart + payPart - fitPenalty,
  0,
  100
)

5.4 Daily-Drift der Haushaltsordnung

Die Ordnung springt nicht hart, sondern driftet langsam:

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:

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.

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:

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:

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

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:

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

{
  "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:

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.