Files
yourpart3/docs/FALUKANT_POLITICAL_BENEFITS_DAEMON_UI_SPEC.md
Torsten Schulz (local) 56be4b76c0
All checks were successful
Deploy to production / deploy (push) Successful in 3m3s
feat(political-benefits): implement political powers and benefits system
- Added new political powers and benefits functionalities, including reputation ticks, tax jurisdiction management, and appointment capabilities.
- Introduced a new job for periodic reputation updates and created necessary database tables for tracking political benefits.
- Enhanced the FalukantController and services to support new endpoints for managing political powers and appointments.
- Updated localization files to reflect new features and improve user experience across multiple languages.
- Modified the UI to display new political powers and benefits, ensuring accurate representation in the PoliticsView.
2026-04-02 16:00:29 +02:00

12 KiB
Raw Blame History

Falukant: Konzept — Daemon, Backend und UI für politische Amtsvorteile

Dieses Dokument beschreibt die noch nicht implementierten Teile zu den Amtsvorteilen (reputation_periodic, appoint_politicians, set_regional_tax, free_lover_slots, sowie optional guard_protection / court_immunity als Spielwirkung). Die Anzeige in der Politik-Übersicht existiert bereits; hier geht es um Ausführung, Persistenz und Bedienoberfläche.


1. Ausgangslage im Code

Bereich Stand
Predefine falukant_predefine.political_office_benefit + Typen in falukant_type.political_office_benefit_type; JSON value pro Amt.
Auslesen / Anzeige FalukantService.politicsBenefitEntriesFromRows, Frontend PoliticsView.vue.
Bereits mechanisch daily_salary (beim Laden der Politik-Übersicht, last_political_daily_salary_on am FalukantUser); Steuerbefreiung in getCumulativeTaxPercentForCharacter (SQL mit exempt types).
Daemon (C++) PoliticsWorker läuft täglich nach 03:00 (src/politics_worker.cpp): Wahlen, Nachbesetzung, Benachrichtigungen — kein Bezug zu den neuen JSON-Vorteilen.
Node-Daemon backend/daemonServer.js ist ein WebSocket-Relay, kein Spiel-Ticker.
Steuern im Spiel Regionen haben tax_percent; kumulativ über Eltern-Regionen; Verkaufsbuchung in falukantService (Steueranteil).

Empfehlung zur Architektur: zeitkritische Batch-Jobs (täglich, idempotent) entweder im bestehenden C++-PoliticsWorker direkt nach den bestehenden Schritten ausführen oder einen kleinen Node-Cron-Job (z. B. node backend/jobs/politicalBenefitsTick.js + systemd timer), der Sequelize nutzt. C++ vermeidet doppelte DB-Logik; Node vermeidet C++-Deploy für reine Sequelize-Regeln. Für synchrone API-Aktionen (Steuern setzen, Ernennungen) ist ausschließlich das Node-Backend sinnvoll.


2. Zielbild pro Vorteilstyp

2.1 reputation_periodic (Ansehen alle x Tage)

Ziel: Charaktere mit aktivem Amt erhalten in einem festen Intervall gain Ansehenspunkte (oberhalb 0, Cap z. B. 100), höchstens einmal pro Intervall pro (Charakter × konkreter Benefit-Zeile).

Persistenz (neu):

  • Tabelle z. B. falukant_data.political_benefit_last_tick
    • id, character_id, political_office_benefit_id (FK auf Predefine-Zeile), last_tick_at (timestamptz), optional ticks_count.
    • Unique (character_id, political_office_benefit_id).

Logik:

  1. Alle political_office-Zeilen mit character_id IS NOT NULL laden (oder seit letztem Lauf geänderte).
  2. Pro Zeile zugehörige office_type_id → alle PoliticalOfficeBenefit mit benefitDefinition.tr = 'reputation_periodic'.
  3. Für jede Kombination: last_tick_at lesen; wenn now - last_tick_at >= intervalDays (Kalendertage Spielzeit oder UTC-Echtzeit — festlegen; konsistent mit daily_salary ist UTC-Datum einfacher), dann character.reputation erhöhen, last_tick_at = now, Eintrag ins Money-/Activity-Log optional (political_reputation_tick).
  4. Mehrere Ämter: mehrere Benefit-Zeilen = mehrere mögliche Ticks (jede mit eigenem Intervall), so wie konfiguriert.
  5. Idempotenz: Pro Lauf nur ein Tick pro Unique-Key; Worker max. 1× täglich wie PoliticsWorker reicht, wenn Intervall ≥ 1 Tag; bei intervalDays < 1 separaten Stunden-Job definieren (nicht empfohlen ohne Bedarf).

Daemon-Ort: neuer Schritt performPoliticalBenefitTicks() am Ende von PoliticsWorker::performDailyPoliticsTask() oder Node-Job 03:05 UTC.

Push: nach Tick falukantUpdateStatus an betroffene User (wie bei anderen Politics-Events).


2.2 free_lover_slots (kostenfreie Liebschaften / Mätressen)

Ziel: Die ersten N aktiven Liebschaften (Relationship-Typ lover + sichtbarer relationship_state, Rolle z. B. lover oder mistress_or_favorite) verursachen keinen monatlichen Unterhalt (monthly_base_cost effektiv 0 für diese Slots).

Kein eigener Daemon nötig — Anwendung beim bestehenden monatlichen Abrechnungslauf (C++ UserCharacterWorker oder Sequelize-Äquivalent), der relationship_state und Kosten verarbeitet.

Backend-Mechanik:

  1. Hilfsfunktion getFreePoliticalLoverSlotCount(characterId)
    • Aktive PoliticalOffice des Charakters → office_type_id → Summe free_lover_slots.count aus Benefits (max oder Summe — Spec-Empfehlung: Summe, Deckel optional maxTotalFreeSlots: 5 in Config).
  2. Liebschaften nach Erstellungsdatum oder fester Priorität sortieren; die ersten N erhalten effectiveMonthlyCost = 0 für diese Abrechnung.
  3. Optional: Flag in relationship_state.flags_json (political_free_slot: true) setzen/aktualisieren für Transparenz und UI — oder rein berechnet ohne Persistenz.

Fairness: Nur Charaktere, die Inhaber sind (nicht nur Kandidaten).


2.3 appoint_politicians (Ernennungsrecht)

Ziel: Amtsträger dürfen unter definierten Regeln andere Ämter in ihrer Zuständigkeit besetzen (NPC oder Spieler), ohne vollständige Wahl — oder: Sonderwahl / Nachrücker auslösen.

Varianten (Priorisierung empfohlen):

Variante Beschreibung Aufwand
A — Nachbesetzung Bei vakantem political_office in erlaubter Region: Appointer wählt einen Kandidaten aus Pool (nur Charaktere mit Titel/Alter wie bei Wahl); Server erstellt Eintrag political_office + Log. Mittel
B — Nur NPC Appointer „ernennt“ nur NPCs (bestehende NPC-Erzeugung); kein PvP-Konflikt. Geringer
C — Einladung appointment_invite an Spieler; Annahme erstellt Amt. Höher

Persistenz (neu):

  • falukant_data.political_appointment
    • id, appointer_character_id, target_character_id (nullable bei NPC), office_type_id, region_id, status (pending, accepted, rejected, expired, completed), created_at, expires_at, completed_office_id (nullable).

Regeln:

  • Appointer muss aktuelles Amt haben, dessen Benefit officeTrs das Zielamt enthält.
  • Zielregion muss zur Kompetenz passen (z. B. gleiche Stadt/Grafschaft wie Appointer-Amt oder laut scope aus JSON erweitert).
  • Anti-Spam: Cooldown, max. offene Ernennungen pro Appointer.

Daemon: optional nur Ablauf (expired) einmal täglich im PoliticsWorker oder Node.


2.4 set_regional_tax (Steuersätze festlegen)

Ziel: Berechtigte setzen tax_percent (oder einen Aufschlag) für Regionen innerhalb ihrer Kompetenz (scope: local, shire, duchy, national).

Datenmodell:

  • Option A (minimal): direkt falukant_data.region.tax_percent ändern + Audit-Tabelle region_tax_history (region_id, old_value, new_value, setter_character_id, office_id, created_at).
  • Option B (flexibler): region_political_tax_modifier (additiv), Basis bleibt in region; effektive Steuer = Basis + Summe gültiger Modifier (mit TTL). Für „Rücknahme nach Amtsende“ einfacher.

Backend-Mechanik:

  1. GET /api/falukant/politics/tax-jurisdiction — Regionen, für die der Charakter nach aktuellem Amt + set_regional_tax schreiben darf, inkl. aktuellem Wert und Grenzen.
  2. PUT /api/falukant/politics/region/:regionId/tax — Body { percent } oder { delta }; Server prüft:
    • Charakter hat passendes Amt;
    • Region liegt in erlaubter Hierarchie (lokal = nur Amtsregion; shire = Teilbaum unter shire; …);
    • Clamp min/max (global config, z. B. 025 %).
  3. Verkaufs-/Steuer-SQL unverändert nutzen, sofern weiterhin tax_percent auf region liegt (bei Option B SQL um Modifier erweitern).

Daemon: nicht nötig; bei Amtsende optional Modifier entfernen oder auf Historie zurücksetzen (täglicher Job oder Trigger auf political_office delete).


2.5 guard_protection / court_immunity (Spielwirkung)

Optional, später:

  • guard_protection: Reduktion von Untergrund-Erfolgswahrscheinlichkeit gegen den Charakter oder geringerer visibility-Anstieg bei Affären (wenn solche Formeln existieren).
  • court_immunity: Abschwächung bestimmter Rechts-/Straf-Events (sobald es dafür Services gibt).

Konkrete Zahlen als JSON in value (attackMitigationPercent, …). Daemon: nicht zwingend; eher bei Event-Auswertung abfragen.


3. Daemon — Gesamtüberblick

03:00 (bestehend) PoliticsWorker
  ├─ … Wahlen, Nachbesetzung, Notifications …
  ├─ NEU: politicalBenefitReputationTicks()
  └─ NEU: politicalAppointmentExpiry() [optional]

Monatlich / bestehender Character-Tick
  └─ relationship monthly cost ← berücksichtigt free_lover_slots

Idempotenz-Prinzip: Jeder Batch-Job nutzt klare Unique-Keys und Transaktionen; bei Crash-Wiederholung keine Doppel-Ticks (Reputation).

Observability: strukturierte Logs [PoliticalBenefits] characterId=… officeBenefitId=… action=reputation_tick.


4. Backend-API (Node) — Übersicht

Endpoint Zweck
GET /api/falukant/politics/my-powers Für eingeloggten Charakter: Liste aktionabler Vorteile inkl. Parameter, nächster reputation-Tick (read-only aus political_benefit_last_tick), freie Liebschaft-Slots-Zahl.
GET /api/falukant/politics/tax-jurisdiction Regionen + aktuelle Steuer + erlaubter Bereich.
PUT /api/falukant/politics/region/:id/tax Steuer setzen (siehe oben).
GET /api/falukant/politics/appointable-offices Vakante oder ernennbare Posten + erlaubte Ziel-officeTrs.
POST /api/falukant/politics/appointments Ernennung anstoßen (Body: targetCharacterId, officeTypeId, regionId).
POST /api/falukant/politics/appointments/:id/accept Optional für Ziel-Spieler.

Service-Schicht: falukantPoliticalPowersService.js (oder Erweiterung falukantService) mit klaren Guards und Wiederverwendung der Benefit-Loader aus PoliticalOfficeBenefit.

Sicherheit: Alle Routen mit getFalukantUserByHashedId + Charakter-Inhaber-Check; keine Überschreibung fremder Regionen.


5. UI-Konzept (Vue)

5.1 Einstieg

  • In Politik neuer Unter-Tab oder Sektion „Amtsbefugnisse“ (sichtbar nur, wenn my-powers nicht leer).
  • Kurzinfo in „Aktuelle Position“: neben der Vorteilsliste ein Link „Befugnisse ausüben“.

5.2 Steuern (set_regional_tax)

  • Ansicht: Tabelle Region (Name, Typ, aktueller Steuersatz, Slider oder Zahleneingabe).
  • Validierung clientseitig spiegelt Server-Clamps.
  • Speichern ruft PUT auf; Erfolgstoast; ggf. Eintrag in lokaler Historie (letzte 5 Änderungen aus region_tax_history).

5.3 Ernennungen (appoint_politicians)

  • Schritt 1: Amt + Region wählen (nur erlaubte Kombinationen).
  • Schritt 2: Ziel-Charakter suchen (Autocomplete über Community/Falukant-Suche) oder „NPC vorschlagen“ (Variante B).
  • Schritt 3: Bestätigung, Anzeige der Regeln (Titel, Alter, Cooldown).
  • Einladungs-Variante: Posteingang / Notification mit Annehmen/Ablehnen.

5.4 reputation_periodic / Meta

  • Anzeige: „Nächster Ansehens-Bonus: in X Tagen“ aus last_tick_at + intervalDays (nur lesend; Ausführung durch Daemon).
  • Optional: Eintrag im Tagebuch / Notification nach Tick.

5.5 free_lover_slots

  • In Familie → Affären (oder Liebschaften): Badge „Amt: X Plätze ohne Unterhalt“; in der Kostenübersicht pro Beziehung Kennzeichnung „politisch freigestellt“.
  • Kein eigener Daemon-Dialog nötig.

5.6 Internationalisierung

  • Alle neuen Strings unter falukant.politics.powers.* (de/en/es/ceb analog zu benefits).

6. Migrations-Reihenfolge (empfohlen)

  1. political_benefit_last_tick (+ FKs, Indizes).
  2. region_tax_history oder Modifier-Tabelle.
  3. political_appointment (+ Indizes auf status, appointer_character_id).
  4. Daemon-/Job-Implementierung Reputation.
  5. API Steuern + UI.
  6. API Ernennungen + UI.
  7. Monatliche Kostenanpassung free_lover_slots.

7. Offene Produktentscheidungen

  • Echtzeit vs. Spielzeit für intervalDays (aktuell Mischung möglich mit daily_salary auf UTC-Datum).
  • Summe vs. Maximum bei mehreren Ämtern für free_lover_slots.
  • Ernennung: nur innerhalb der eigenen Region oder auch in Unterregionen?
  • Steuer: darf derselbe Region mehrfach von verschiedenen Ämtern gesetzt werden? (Empfehlung: letzte schreibende Instanz mit höherer scope-Priorität gewinnt, oder explizite Hierarchie-Regel.)

Dokumentstand: abgestimmt auf Repository mit C++-PoliticsWorker, Sequelize-Falukant-Backend und bestehenden political_office_benefit-Seeds.