diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..a853fd4 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,1175 @@ +# AGENTS.md — Ashen Realms + +## Purpose + +This file defines the default working rules for AI coding agents contributing to **Ashen Realms**. + +Ashen Realms is a modern, browser-based dark-fantasy PvE RPG inspired by the structure and long-term progression of classic browser MMORPGs, while using a modern UI, server-authoritative game logic, and a data-driven architecture. + +Agents must treat the existing project documentation and implemented code as the source of truth. Do not redesign core systems, introduce new architecture, or generalize systems beyond current requirements unless explicitly requested. + +--- + +# 1. Project Priorities + +When making implementation decisions, use this priority order: + +1. Preserve the core gameplay loop. +2. Preserve server authority and data integrity. +3. Keep systems simple enough for the current development stage. +4. Prefer reusable domain systems over content-specific special cases. +5. Maintain UI consistency with the existing visual language. +6. Keep implementation testable and understandable. +7. Avoid speculative architecture for future MMO-scale requirements. + +Core gameplay loop: + +```text +Explore +→ Travel +→ Hunt / Search +→ Choose encounter +→ Fight +→ Receive loot / progression +→ Improve character +→ Defeat stronger challenges +→ Discover new locations +``` + +The project should first be a good RPG and only later become a larger MMO. + +--- + +# 2. Required Reading Before Major Changes + +Before implementing or changing a larger gameplay, architecture, persistence, or UI feature, inspect the relevant documentation in `docs/`. + +Important project documents include: + +```text +docs/design-manifest.md +docs/vertical-slice-world-content-design.md +docs/balancing-items-loot-design.md +docs/ui-visual-design-specification.md +``` + +Additional feature specifications may exist in `docs/` and override older assumptions where they explicitly redefine a system. + +Do not rely only on this file when a more specific feature specification exists. + +--- + +# 3. Source-of-Truth Order + +If multiple sources conflict, use the following precedence unless the task explicitly says otherwise: + +1. Explicit requirements in the current task. +2. Newer dedicated feature specification. +3. Newer project documentation. +4. Existing implemented behavior and tests. +5. `AGENTS.md`. +6. Older design documents. + +Do not silently reconcile conflicting requirements. + +If a conflict affects behavior or data design, point it out before making a broad architectural reinterpretation. + +--- + +# 4. Current Technical Architecture + +Ashen Realms is implemented as a **modular monolith**. + +## Stack + +```text +Frontend: Angular +Backend: NestJS +Language: TypeScript +Database: PostgreSQL +ORM: TypeORM +Monorepo: npm Workspaces +API: REST +Deployment: one Ashen Realms application container +Database: separate persistent PostgreSQL service +``` + +Typical repository structure: + +```text +apps/ + web/ + api/ + +packages/ + shared/ + game-content/ + +docs/ +``` + +Production behavior: + +```text +Browser + ↓ +NestJS + ├── /api/* → REST API + └── /* → built Angular application + ↓ +PostgreSQL +``` + +NestJS is the only runtime process in the application container. + +Do not introduce a second production web server for Angular. + +--- + +# 5. Server Authority Is Mandatory + +Critical gameplay logic is server-authoritative. + +The client may display state and send intentions, but must not decide authoritative gameplay results. + +The server owns at least: + +- character state +- current HP +- effective stats +- combat state +- combat results +- damage +- enemy actions +- loot rolls +- inventory +- equipment +- currencies +- reputation / progression +- travel state +- travel completion +- encounter generation +- quest progress +- item ownership +- regeneration state + +Client requests should express actions, not results. + +Good: + +```json +{ + "action": "ATTACK" +} +``` + +Bad: + +```json +{ + "action": "ATTACK", + "damage": 42 +} +``` + +Never trust client-provided values that the server can calculate or validate itself. + +--- + +# 6. API Rules + +All API routes use the prefix: + +```text +/api +``` + +Frontend requests must use relative URLs. + +Good: + +```ts +this.http.get('/api/characters/me'); +``` + +Bad: + +```ts +this.http.get('http://localhost:3000/api/characters/me'); +``` + +Use consistent domain errors. + +Example: + +```json +{ + "statusCode": 400, + "code": "INVALID_TRAVEL_TARGET", + "message": "The selected location is not connected to the current location." +} +``` + +Prefer stable machine-readable error codes over UI-dependent text matching. + +--- + +# 7. Data and Persistence Rules + +## TypeORM + +Use TypeORM migrations for schema changes. + +Production must not use: + +```ts +synchronize: true +``` + +Schema workflow: + +```text +change entity +→ create/generate migration +→ inspect migration +→ run migration +→ run tests +``` + +Never accept unexpected destructive migration output without reviewing it. + +## Content vs Player State + +Keep static or semi-static game content separate from player-specific persistent state. + +Examples of content definitions: + +```text +LocationDefinition +LocationConnection +MonsterDefinition +ItemDefinition +LootTable +NPC definition +Quest definition +Shop definition +``` + +Examples of player state: + +```text +User +Character +CharacterItem +CharacterEquipment +Travel +Hunt +HuntEncounter +Combat +CombatEvent +QuestProgress +Reputation +``` + +Do not duplicate content definitions into every player record. + +--- + +# 8. Stable Content Keys + +Content should have stable human-readable keys in addition to database IDs where appropriate. + +Examples: + +```text +south-gate +burned-road +ash-rat +road-bandit +worn-short-sword +``` + +Use stable keys for seeds, cross-content references, configuration, and tests where this improves maintainability. + +Do not hard-code random UUIDs across fixtures or content definitions. + +Seeds must be idempotent whenever practical. + +Running a seed repeatedly must not create duplicate content. + +--- + +# 9. Gameplay Systems Should Be Data-Driven + +Repeated game content should be modeled as data rather than one-off code. + +This applies especially to: + +- locations +- travel connections +- monsters +- encounter pools +- items +- loot +- NPCs +- shops +- abilities +- quests +- reputation requirements +- enemy categories +- drop categories + +Prefer: + +```text +shared mechanic + content configuration +``` + +over: + +```text +if monster == "special-monster-x" then custom branch +``` + +However, do not over-generalize before multiple real use cases exist. + +A special case is acceptable when the abstraction would be more complex than the current requirement. + +--- + +# 10. Combat Design Rules + +Combat is round-based. + +The player chooses one main action per turn. + +The combat system should remain deterministic where the current rules define deterministic behavior. + +Core values currently revolve around: + +```text +HP +Attack +Weapon Damage +Armor +``` + +The original V1 combat model uses: + +```text +Raw Damage = Weapon Damage + Attack +``` + +and armor mitigation based on: + +```text +Damage = Raw Damage × 60 / (60 + Armor) +``` + +Minimum successful damage: + +```text +1 +``` + +Do not add systems such as critical hits, dodge, accuracy, random damage ranges, elemental resistance, mana, or complex action points unless a newer dedicated specification introduces them. + +Enemy difficulty should come primarily from: + +- meaningful stats +- telegraphed actions +- status effects +- defensive states +- interrupts +- phase behavior +- encounter composition + +not hidden randomness. + +--- + +# 11. Combat Engine Separation + +Pure combat rules should be kept separate from persistence and HTTP concerns. + +Preferred structure: + +```text +CombatController + ↓ +CombatService + ↓ +CombatEngineService +``` + +`CombatEngineService` should ideally: + +- receive game state +- receive an action +- return resulting state/events +- avoid direct database access +- be easy to unit test + +`CombatService` should: + +- load persistent state +- validate ownership and turn rules +- invoke the engine +- persist events/state +- handle victory/defeat +- trigger loot/progression +- commit atomically where necessary + +Do not bury combat formulas inside controllers or Angular components. + +--- + +# 12. Realtime and Event Delivery + +Realtime communication is an event transport layer, not the authoritative game state itself. + +The project is moving toward a central game-event connection suitable for systems such as: + +- multiplayer combat +- delayed NPC actions +- pets / companions +- turn notifications +- combat state changes +- selected character-state updates + +Prefer one authenticated realtime connection with typed event channels/messages rather than one independent socket connection per feature. + +Examples of event families: + +```text +combat.* +character.* +travel.* +system.* +``` + +The server remains authoritative. + +The client must still be able to recover state through normal APIs after reconnecting. + +Do not make correctness depend solely on receiving every realtime event. + +--- + +# 13. Travel Rules + +Travel is server-authoritative. + +The server calculates: + +```text +startedAt +arrivesAt +origin +target +travel state +possible encounter +``` + +The client may render a countdown using the server-provided timestamp. + +Never move the character merely because a browser timer reached zero. + +Travel completion must be validated or finalized by the server. + +Travel duration is part of the game-world feeling, not just an arbitrary cooldown. + +--- + +# 14. Hunting and Encounters + +The player does not directly request arbitrary monsters to fight. + +Preferred flow: + +```text +start hunt/search +→ server creates valid encounter choices +→ player selects one encounter +→ combat starts from that persisted encounter +``` + +Use encounter IDs or equivalent server-issued references. + +Do not allow: + +```text +POST /combat +{ + "monsterId": "anything-the-client-wants" +} +``` + +without server-side validation that the encounter is actually available to that character. + +--- + +# 15. Progression Direction + +Ashen Realms is evolving away from a classic: + +```text +kill monster +→ receive XP + money +→ level up +``` + +model. + +Current project direction emphasizes: + +- reputation / renown +- region reputation +- world-level progression +- monster materials +- exchanging materials through NPCs / merchants +- reputation-gated offers +- meaningful inventory/bag constraints +- loot and equipment as primary combat progression + +When touching XP, direct monster currency rewards, level gating, merchants, drops, or progression, inspect the newest progression/reputation specifications before using older V1 assumptions. + +Do not reintroduce old XP-based progression just because older design documents still contain it. + +--- + +# 16. Item and Loot Philosophy + +Items must be understandable and meaningful. + +Prefer handcrafted items with fixed identity over random-affix chaos. + +A good item should create a visible upgrade or gameplay decision. + +Loot should be targeted enough that the player can understand why a specific enemy is worth fighting. + +General principle: + +```text +Drops create excitement. +Deterministic progression prevents frustration. +``` + +Bosses and important content should not regularly produce meaningless rewards. + +Avoid huge undifferentiated loot tables. + +--- + +# 17. Bags and Material Categories + +The project uses or plans constrained bags for certain material categories. + +This system is intended to make carrying capacity part of progression without turning the full inventory into weight micromanagement. + +When implementing drops and inventory: + +- distinguish normal inventory from specialized material storage where specified +- support monster/drop categories as data +- do not hard-code category behavior into individual monsters +- keep quest/story items separate from normal inventory capacity where appropriate + +Inspect the dedicated bag-system specification before implementing or modifying this system. + +--- + +# 18. NPC Model + +NPCs may combine multiple capabilities. + +Avoid rigid inheritance such as: + +```text +BaseNpc + ├── MerchantNpc + └── QuestGiverNpc +``` + +when an NPC can logically be both. + +Prefer composition/capabilities, for example: + +```text +NPC ++ dialogue ++ merchant capability ++ quest capability ++ reputation relationship ++ location presence +``` + +Shared NPC data may include: + +- stable key +- name +- location +- portrait/artwork +- dialogue +- availability +- reputation relationship +- interaction capabilities + +Use the dedicated NPC specification where available. + +--- + +# 19. UI Design Direction + +Ashen Realms must not look like a generic web dashboard or mobile game. + +The intended style is: + +```text +classic browser RPG structure ++ +modern premium dark-fantasy presentation +``` + +Key characteristics: + +- desktop-first +- persistent top bar +- left-side navigation +- large central artwork/content area +- contextual right-side panel +- restrained footer/status area +- dark metal / stone / leather materials +- muted colors +- limited functional accents +- strong fantasy artwork +- readable information density +- clear interaction states + +Avoid: + +- SaaS dashboard visuals +- white cards +- glassmorphism +- neon cyberpunk styling +- generic Angular Material appearance +- excessive rounded mobile cards +- stacked mobile-game popups +- arbitrary component-specific visual languages + +--- + +# 20. UI Reuse Rules + +Before creating a new screen or component: + +1. inspect existing shared layout/components +2. inspect similar screens +3. inspect design tokens/styles +4. reuse existing UI primitives where appropriate + +Likely reusable components include concepts such as: + +```text +AppShell +TopBar +SideNavigation +Footer +Panel +PanelHeader +Button variants +HealthBar +CharacterHeader +DangerBadge +EncounterCard +ItemIcon +ItemTooltip +CombatActionButton +CombatLog +PotionSlot +StatusEffectIcon +``` + +Do not duplicate the same visual pattern independently in multiple feature folders. + +--- + +# 21. Artwork Is Part of the Product + +Large artworks are a primary part of the game experience. + +UI layout should preserve visual space for: + +- locations +- monsters +- characters +- NPCs +- combat scenes +- items + +Do not convert major game screens into dense tables or grids merely because that is easier to implement. + +Gameplay information must be clear, but the world should remain visually dominant. + +--- + +# 22. Frontend Responsibilities + +Angular is responsible for: + +- rendering server state +- user input +- local UI state +- routing +- animations +- countdown display +- displaying realtime events +- presenting combat events +- accessibility and interaction states + +Angular is not authoritative for: + +- damage +- loot +- inventory ownership +- travel completion +- combat results +- stat calculation +- progression rewards +- encounter validity + +Prefer typed API contracts. + +Do not leak TypeORM entities directly into frontend assumptions. + +--- + +# 23. Shared Package Rules + +`packages/shared` should contain only genuine cross-boundary contracts and shared enums/types. + +Good examples: + +```text +DTO contracts +shared enums +event message contracts +API-facing types +``` + +Do not place: + +- NestJS services +- Angular components +- TypeORM entities +- repository implementations +- backend-only business logic + +inside `packages/shared`. + +`packages/game-content` may contain shared content schemas/enums where this is genuinely useful. + +--- + +# 24. Testing Expectations + +Changes to domain logic require tests. + +High-value test targets include: + +- combat calculations +- character effective stats +- travel validation +- regeneration logic +- encounter generation +- loot rolls +- inventory/equipment rules +- reputation changes +- bag capacity rules +- quest progression +- realtime event handling + +Use deterministic random sources in tests for random game systems. + +Do not write tests that rely on uncontrolled `Math.random()` behavior. + +For API flows, prefer integration tests around real validation boundaries. + +For frontend features, test behavior and state handling rather than fragile implementation details. + +--- + +# 25. Bug-Fix Workflow + +When fixing a bug: + +1. understand the actual failure +2. identify the authoritative layer +3. reproduce with a focused test where practical +4. implement the smallest correct fix +5. run relevant tests +6. run lint/build where appropriate +7. verify no adjacent behavior regressed + +Do not treat symptoms in Angular if the actual bug is an invalid backend state transition. + +Do not disable validation merely to make an API call pass. + +--- + +# 26. Feature Workflow + +For non-trivial features: + +1. read the relevant spec +2. inspect the current implementation +3. identify affected domain boundaries +4. define the smallest complete slice +5. add/adjust tests +6. implement backend/domain behavior +7. add persistence/migration if needed +8. expose API/realtime contract +9. implement frontend behavior +10. verify end-to-end behavior +11. update documentation if behavior or architecture changed + +Prefer vertical slices over large disconnected infrastructure work. + +--- + +# 27. Scope Discipline + +Do not add systems merely because they may be useful later. + +For V1 and early development, avoid introducing without explicit need: + +- microservices +- Kafka +- RabbitMQ +- Redis +- event sourcing +- CQRS frameworks +- GraphQL +- Kubernetes-specific architecture +- generic plugin systems +- unnecessary abstraction layers +- premature distributed locking +- generic workflow engines +- complex state machines when simple domain state is enough + +The default question is: + +```text +What is the smallest correct design for the current feature? +``` + +--- + +# 28. Avoid Premature MMO Architecture + +Future features may include: + +- parties +- multiplayer combat +- companions +- pets +- chat +- guilds +- trading +- PvP +- auctions +- crafting +- admin balancing tools + +Current code should avoid blocking those ideas, but should not fully implement infrastructure for them before needed. + +Design extensible domain boundaries, not speculative subsystems. + +--- + +# 29. Transaction Boundaries + +Use database transactions for operations that must succeed atomically. + +Examples: + +```text +combat victory +→ reward generation +→ inventory grant +→ reputation/material changes +→ combat completion +``` + +or: + +```text +equip item +→ validate ownership +→ replace current slot +→ persist equipment state +``` + +Do not leave the character in partially updated gameplay states. + +--- + +# 30. Concurrency and Idempotency + +Assume clients may retry requests or send duplicate requests. + +Important state-changing actions should reject or safely handle duplicates. + +Examples: + +- completing the same travel twice +- resolving the same combat turn twice +- claiming the same reward twice +- submitting the same quest completion twice +- buying the same transaction twice because of retry + +Where useful, enforce correctness with: + +- explicit status transitions +- database constraints +- version checks +- unique keys +- transaction locking + +Do not rely solely on the UI disabling a button. + +--- + +# 31. Character Stats + +Effective character stats must have a clear authoritative calculation path. + +Prefer a dedicated service such as: + +```text +CharacterStatsService +``` + +It should combine: + +```text +base character values ++ equipment ++ item bonuses ++ active effects ++ future set bonuses/buffs where applicable +``` + +Do not independently calculate effective stats in combat, profile, inventory, and UI code. + +Use one domain source of truth. + +--- + +# 32. HP and Regeneration + +Persistent HP and regeneration are server-owned state. + +If regeneration is timestamp-based, calculate authoritative HP using server timestamps and persisted regeneration anchors/state. + +Realtime updates may improve the UI, but must not be required for correctness. + +A reconnect or normal API refresh must be able to reconstruct the correct current HP. + +Do not implement HP regeneration as a browser-only interval. + +--- + +# 33. Naming and Language + +Code, API contracts, identifiers, database names, and new game-content source text should default to **English** unless an existing subsystem explicitly uses another convention. + +Prefer clear domain names over abbreviations. + +Good: + +```text +currentLocationId +reputationRequirement +travelDurationSeconds +monsterCategory +``` + +Avoid unclear names such as: + +```text +loc +repReq +dur +mc +``` + +Public-facing gameplay text should move toward English consistently as the project is migrated. + +--- + +# 34. TypeScript Rules + +Prefer: + +- strict types +- explicit domain types +- discriminated unions where useful +- enums/unions for finite domain states +- immutable inputs for pure engines where practical +- dependency injection for external/random/time sources when testing benefits + +Avoid: + +- `any` +- magic strings scattered across services +- duplicated status literals +- deeply nested untyped JSON blobs for core domain state + +JSONB is acceptable for flexible snapshots/events when the schema is still clearly typed in TypeScript. + +--- + +# 35. Time Handling + +Use server timestamps for authoritative gameplay timing. + +Examples: + +- travel +- cooldowns +- HP regeneration +- timed encounter state +- buffs/debuffs +- scheduled NPC/combat actions + +Prefer storing absolute timestamps such as: + +```text +startedAt +arrivesAt +expiresAt +lastRegeneratedAt +``` + +The frontend may derive display countdowns from those values. + +Do not persist countdown seconds that decrement every second unless there is a strong domain reason. + +--- + +# 36. Logging + +Use structured backend logging for meaningful domain and infrastructure failures. + +Useful context may include: + +- character ID +- combat ID +- travel ID +- encounter ID +- action +- domain error code + +Do not log secrets, tokens, passwords, or full sensitive authentication payloads. + +Avoid noisy per-frame or per-second logs. + +--- + +# 37. Security Basics + +Never trust client ownership claims. + +Always verify: + +- the authenticated user owns the character +- the character owns the item +- the encounter belongs to the character +- the combat belongs to the character +- the requested transition is currently legal + +Secrets belong in environment variables. + +Never commit real secrets. + +Do not expose internal stack traces or database details as user-facing API errors. + +--- + +# 38. Documentation Updates + +Update documentation when a change: + +- alters architecture +- changes a core gameplay rule +- replaces an older system +- introduces a reusable domain pattern +- creates a new persistent data model +- changes API/realtime conventions +- invalidates an existing implementation spec + +Do not update documentation for trivial refactors that do not change behavior. + +When replacing an old system, prefer clearly marking the old assumption obsolete rather than leaving contradictory active docs. + +--- + +# 39. Do Not Silently Change Game Design + +Coding agents may identify possible improvements, but they should not silently: + +- rebalance items +- change travel times +- change drop chances +- change combat formulas +- alter progression rules +- replace reputation requirements +- redesign UI flows +- add/remove player capabilities + +unless the requested task includes that design change. + +If implementation requires choosing an unspecified behavior, choose the smallest reversible option and make the assumption explicit. + +--- + +# 40. Definition of Done + +A feature is complete when applicable: + +- requirements from the relevant spec are implemented +- authoritative logic is on the server +- persistence is correct +- migrations exist and were reviewed +- ownership and transition validation exists +- tests cover important domain behavior +- frontend uses the authoritative API/state +- realtime is recoverable after reconnect where used +- build passes +- lint passes +- relevant tests pass +- no unrelated architecture was introduced +- documentation is updated when behavior changed + +Do not claim completion if relevant tests or builds are failing. + +--- + +# 41. Final Decision Filter + +Before adding code, ask: + +1. Does this improve the current core loop? +2. Is this required by the current specification? +3. Is the server still authoritative? +4. Can this be modeled as reusable data instead of a one-off? +5. Am I solving a current problem rather than a hypothetical future problem? +6. Does this fit the existing architecture? +7. Does the UI still feel like Ashen Realms rather than a generic web app? +8. Can the implementation be tested cleanly? +9. Does this preserve player progress and data integrity? +10. Is there a smaller correct implementation? + +When in doubt: + +> Prefer the smallest server-authoritative, data-driven solution that fits the current specification. diff --git a/apps/web/public/images/character/female-portrait-256.png b/apps/web/public/images/character/female-portrait-256.png new file mode 100644 index 0000000..5725068 Binary files /dev/null and b/apps/web/public/images/character/female-portrait-256.png differ diff --git a/apps/web/public/images/character/male-portrait-256.png b/apps/web/public/images/character/male-portrait-256.png new file mode 100644 index 0000000..1ef6683 Binary files /dev/null and b/apps/web/public/images/character/male-portrait-256.png differ diff --git a/apps/web/src/app/layout/top-bar/top-bar.component.html b/apps/web/src/app/layout/top-bar/top-bar.component.html index eb34269..3f37567 100644 --- a/apps/web/src/app/layout/top-bar/top-bar.component.html +++ b/apps/web/src/app/layout/top-bar/top-bar.component.html @@ -1,6 +1,6 @@
- + @if (character(); as character) {
{{ character.name }} diff --git a/art/sprites/player/female/female-portrait.png b/art/sprites/player/female/female-portrait.png new file mode 100644 index 0000000..2d27cb8 Binary files /dev/null and b/art/sprites/player/female/female-portrait.png differ diff --git a/art/sprites/player/male/male-portrait.png b/art/sprites/player/male/male-portrait.png new file mode 100644 index 0000000..38a3b59 Binary files /dev/null and b/art/sprites/player/male/male-portrait.png differ diff --git a/docs/playable-slices/Ashen Realms – Playable Slice 0.13_ Realtime Game Events Foundation.md b/docs/playable-slices/Ashen Realms – Playable Slice 0.13_ Realtime Game Events Foundation.md new file mode 100644 index 0000000..dad1c2e --- /dev/null +++ b/docs/playable-slices/Ashen Realms – Playable Slice 0.13_ Realtime Game Events Foundation.md @@ -0,0 +1,1738 @@ +# Ashen Realms – Playable Slice 0.13 + +## Realtime Game Events Foundation + +**Status:** Implementation Specification +**Slice:** 0.13 +**Scope:** Zentraler WebSocket-Kanal für serverinitiierte Game Events +**Primary Use Case:** Combat Events +**Architecture:** REST Commands + WebSocket Events + server authoritative state + +--- + +# 1. Ziel + +Slice 0.13 führt eine zentrale Realtime-Kommunikationsschicht für Ashen Realms ein. + +Bis einschließlich Slice 0.12 funktioniert das Spiel primär request-basiert: + +```text +Client +→ REST Request +→ Server verarbeitet +→ Response +``` + +Das reicht für: + +- Reisen +- Jagd +- Einzelspieler-Kämpfe +- Inventar +- Equipment +- Quests +- Händler +- Charakterverwaltung + +Langfristig entstehen jedoch Situationen, bei denen sich der Spielzustand verändern kann, **ohne dass der aktuelle Client selbst einen Request ausgelöst hat**. + +Beispiele: + +- ein anderer Spieler führt im gemeinsamen Kampf eine Aktion aus +- ein NPC führt verzögert eine Kampfaktion aus +- ein anderer Spieler ist nun am Zug +- ein Gruppenmitglied tritt einem Kampf bei +- ein Begleiter oder Pet führt eine Aktion aus +- der Kampf endet durch die Aktion eines anderen Beteiligten +- später verändert ein externer Effekt Charakterwerte +- Gruppen-, Quest- oder Weltzustände ändern sich + +Dafür wird ein zentraler WebSocket-Kanal eingeführt. + +Grundsatz: + +> **REST beschreibt, was der Spieler tun möchte. WebSocket Events beschreiben, was im Spiel passiert ist.** + +--- + +# 2. Nicht-Ziel dieses Slices + +Slice 0.13 führt **kein vollständiges Multiplayer-Kampfsystem** ein. + +Noch nicht Teil dieses Slices: + +- mehrere menschliche Spieler im selben Kampf +- mehrere Gegner in einem Kampf +- Pets +- NPC-Begleiter +- Party-System +- PvP +- Chat +- Location Presence +- Welt-Events +- globale Tick-Simulation +- WebSocket-basierte HP-Regeneration +- vollständige Umstellung bestehender REST-Endpunkte auf WebSockets + +Der bestehende 1-vs-1-Combat bleibt funktional bestehen. + +0.13 schafft ausschließlich die technische Grundlage, auf der spätere Mehrteilnehmer-Systeme aufbauen können. + +--- + +# 3. Architekturprinzip + +Ashen Realms verwendet ab Slice 0.13 drei unterschiedliche Mechanismen für unterschiedliche Arten von Zustand. + +## 3.1 REST – Commands und Reads + +REST bleibt verantwortlich für explizite Spieleraktionen. + +Beispiele: + +```text +POST /api/travel +POST /api/hunts +POST /api/combats/:id/actions +POST /api/equipment + +GET /api/characters/me +GET /api/inventory +GET /api/combats/:id +``` + +Der Client sendet weiterhin keine berechneten Spielwerte an den Server. + +Beispiel: + +```json +{ + "action": "ATTACK" +} +``` + +Nicht: + +```json +{ + "action": "ATTACK", + "damage": 27 +} +``` + +--- + +## 3.2 WebSocket – diskrete serverseitige Ereignisse + +WebSocket wird verwendet, wenn der Server einen Client über ein Ereignis informieren muss. + +Beispiele: + +```text +combat.action.resolved +combat.turn.changed +combat.finished + +später: +character.vitals.changed +party.member.joined +quest.updated +location.player.joined +world.event.started +``` + +--- + +## 3.3 Zeitstempel – kontinuierlich ableitbarer Zustand + +Zeitabhängige Werte werden weiterhin nicht permanent übertragen. + +Beispiele: + +- HP-Regeneration +- Reisezeit +- Cooldowns +- Buff-Dauer +- Respawn-Zeit + +Diese Systeme verwenden weiterhin: + +```text +Basiszustand ++ +Zeitstempel ++ +Regel +``` + +Der Client darf daraus die Darstellung interpolieren. + +Der Server bleibt für den tatsächlichen Zustand autoritativ. + +--- + +# 4. Zentrale Regel + +Es gibt **eine WebSocket-Verbindung pro eingeloggtem Client**. + +Nicht: + +```text +/combat websocket +/character websocket +/party websocket +``` + +Sondern: + +```text +/events +``` + +Darüber werden verschiedene fachliche Event-Typen transportiert. + +--- + +# 5. Zielarchitektur + +```text +Angular Client + | + | REST Commands + v +NestJS Controllers + | + v +Domain Services + | + +--------------------------+ + | | + v v +PostgreSQL GameEventPublisher + | + v + EventsGateway + | + | WebSocket + v + Angular Client +``` + +Beispiel Combat: + +```text +Spieler klickt Angriff + | + v +POST /api/combats/:id/actions + | + v +CombatService + | + ├── CombatEngine + ├── State speichern + ├── CombatEvents speichern + └── Transaction Commit + | + v + CombatEventPublisher + | + v + EventsGateway + | + v + combat.action.resolved +``` + +--- + +# 6. Wichtigste Architekturregel + +Ein WebSocket-Event darf erst veröffentlicht werden, **nachdem der zugehörige persistente Zustand erfolgreich gespeichert wurde**. + +Nicht: + +```text +Event senden +→ danach DB speichern +``` + +Sondern: + +```text +DB Transaction +→ Commit +→ Event veröffentlichen +``` + +Dadurch gilt: + +> Wenn ein Client ein Event erhält, existiert der gemeldete Zustand bereits autoritativ auf dem Server. + +--- + +# 7. WebSocket-Verbindung + +Endpoint: + +```text +/events +``` + +Die konkrete technische Umsetzung darf beispielsweise mit NestJS WebSocket Gateway und Socket.IO oder nativen WebSockets erfolgen. + +Für V1 sollte die einfachere, robuste NestJS-Integration bevorzugt werden. + +--- + +# 8. Authentifizierung + +Die WebSocket-Verbindung muss authentifiziert sein. + +Der Server muss aus der Verbindung mindestens bestimmen können: + +```text +userId +characterId +``` + +Ein Client darf niemals selbst angeben: + +```text +Ich bin Character X. +``` + +ohne dass der Server diese Zuordnung aus der Authentifizierung validiert. + +--- + +# 9. Connection Lifecycle + +Der Client baut nach erfolgreicher Authentifizierung eine Verbindung auf. + +```text +Login +→ Character laden +→ WebSocket /events verbinden +``` + +Bei Logout: + +```text +WebSocket trennen +``` + +Bei Verbindungsverlust: + +```text +Reconnect versuchen +``` + +Der WebSocket darf niemals Voraussetzung dafür sein, dass der persistente Spielzustand korrekt bleibt. + +--- + +# 10. Reconnect-Prinzip + +Ein WebSocket ist ein Benachrichtigungskanal, nicht die Source of Truth. + +Wenn der Client die Verbindung verliert: + +```text +WebSocket disconnected +``` + +läuft das Spiel serverseitig weiter. + +Nach Wiederherstellung: + +```text +WebSocket reconnect +→ aktuellen Zustand per REST synchronisieren +``` + +Beispielsweise: + +```text +GET /api/characters/me +GET /api/combats/:id +``` + +Der Client darf niemals annehmen, dass er während des Disconnects keine Events verpasst hat. + +--- + +# 11. Event Envelope + +Alle Events verwenden eine gemeinsame Grundstruktur. + +Beispiel: + +```ts +export interface GameEvent { + id: string; + sequence?: number; + type: GameEventType; + occurredAt: string; + payload: TPayload; +} +``` + +Beispiel: + +```json +{ + "id": "event-uuid", + "sequence": 42, + "type": "combat.action.resolved", + "occurredAt": "2026-08-21T15:00:00.000Z", + "payload": { + "combatId": "combat-uuid" + } +} +``` + +--- + +# 12. Event Naming + +Event-Namen verwenden: + +```text +domain.entity-or-action.event +``` + +Für Slice 0.13: + +```text +combat.action.resolved +combat.turn.changed +combat.finished +combat.state.changed +``` + +Später möglich: + +```text +character.vitals.changed +character.stats.changed + +party.member.joined +party.member.left + +quest.updated + +location.player.joined +location.player.left +``` + +--- + +# 13. Keine technischen Event-Namen + +Nicht: + +```text +UPDATE_COMBAT +REFRESH_UI +DB_CHANGED +SYNC_PLAYER +``` + +Events beschreiben fachlich, was passiert ist. + +Gut: + +```text +combat.turn.changed +``` + +Schlecht: + +```text +refreshCombatScreen +``` + +--- + +# 14. Rooms / Channels + +Die zentrale WebSocket-Verbindung verwendet serverseitige Rooms. + +Vorgesehene Room-Typen: + +```text +user: +character: +combat: +``` + +Später: + +```text +party: +location: +guild: +``` + +--- + +# 15. User Room + +Jeder eingeloggte Client wird automatisch Mitglied von: + +```text +user: +``` + +Dieser Room ist geeignet für: + +- globale persönliche Benachrichtigungen +- Account-bezogene Ereignisse +- spätere systemweite Hinweise + +--- + +# 16. Character Room + +Der Client tritt zusätzlich bei: + +```text +character: +``` + +Geeignet für: + +- Charakteränderungen +- Statusänderungen +- später Buffs +- später Ruf +- später externe Heilung + +--- + +# 17. Combat Room + +Wenn ein Charakter einen aktiven Kampf besitzt: + +```text +combat: +``` + +Der Server fügt den Client diesem Room hinzu. + +Beim Verlassen oder Ende des Kampfes wird die Subscription entfernt. + +Später können mehrere Spieler gleichzeitig Mitglied desselben Combat Rooms sein. + +--- + +# 18. Kein frei wählbares Room Joining + +Der Client darf nicht einfach senden: + +```text +join combat:xyz +``` + +und dadurch beliebige Kämpfe beobachten. + +Der Server validiert immer: + +```text +Ist dieser Charakter Teilnehmer dieses Kampfes? +``` + +Erst danach darf der Socket dem Room beitreten. + +--- + +# 19. Game Events Backend-Struktur + +Vorgesehene Struktur: + +```text +apps/api/src/events/ +├── events.module.ts +├── events.gateway.ts +├── game-event.types.ts +├── game-event-publisher.service.ts +├── event-room.service.ts +└── events.gateway.spec.ts +``` + +Optional fachlich getrennt: + +```text +apps/api/src/combat/ +└── combat-event.publisher.ts +``` + +--- + +# 20. `EventsGateway` + +Verantwortlich für: + +- WebSocket-Verbindungen +- Authentifizierung +- Disconnect +- Reconnect-Unterstützung +- Room-Mitgliedschaften +- Senden von Events + +Nicht verantwortlich für: + +- Combat-Regeln +- Schadensberechnung +- Charakterwerte +- Loot +- Questlogik + +--- + +# 21. `GameEventPublisher` + +Der Domain-Code soll nicht direkt mit dem WebSocket-Gateway kommunizieren. + +Nicht: + +```ts +this.eventsGateway.server + .to(room) + .emit(...); +``` + +innerhalb des CombatService. + +Stattdessen: + +```ts +this.gameEventPublisher.publishToCombat( + combatId, + event, +); +``` + +Dadurch bleibt der Transport austauschbar und die Domain-Logik kennt keine Socket.IO-Details. + +--- + +# 22. Beispiel Publisher Interface + +Konzeptionell: + +```ts +export interface GameEventPublisher { + publishToUser( + userId: string, + event: GameEvent, + ): void; + + publishToCharacter( + characterId: string, + event: GameEvent, + ): void; + + publishToCombat( + combatId: string, + event: GameEvent, + ): void; +} +``` + +--- + +# 23. Combat als erster Use Case + +Slice 0.13 verwendet Combat als ersten realen Event-Produzenten. + +Der bestehende Combat-Flow bleibt: + +```text +Client +→ POST Combat Action +→ Server berechnet Resultat +→ Server persistiert Resultat +→ Response +``` + +Zusätzlich: + +```text +→ Server veröffentlicht Combat Events +→ WebSocket liefert sie an Combat Room +``` + +--- + +# 24. `combat.action.resolved` + +Wird veröffentlicht, wenn eine Combat Action serverseitig vollständig verarbeitet wurde. + +Beispiel: + +```json +{ + "type": "combat.action.resolved", + "payload": { + "combatId": "abc", + "round": 4, + "events": [ + { + "sequence": 21, + "type": "PLAYER_ATTACK", + "actorId": "player", + "targetId": "monster", + "amount": 20 + } + ] + } +} +``` + +Der Client verwendet dieses Event für: + +- Animationen +- Damage Numbers +- Combat Log +- UI-State + +--- + +# 25. `combat.turn.changed` + +Wird veröffentlicht, sobald sich der aktive Actor ändert. + +Payload: + +```ts +interface CombatTurnChangedPayload { + combatId: string; + actorId: string; + startedAt: string; + expiresAt?: string; +} +``` + +Für den aktuellen 1-vs-1-Combat kann dieses Event zunächst nur begrenzt genutzt werden. + +Die Struktur wird jedoch bereits für spätere Mehrteilnehmer-Kämpfe vorbereitet. + +--- + +# 26. `combat.finished` + +Wird bei Sieg, Niederlage oder später Flucht veröffentlicht. + +Beispiel: + +```json +{ + "type": "combat.finished", + "payload": { + "combatId": "abc", + "result": "WON" + } +} +``` + +Später können weitere Informationen ergänzt werden: + +```text +loot +reputation +questProgress +``` + +Diese Daten müssen jedoch weiterhin serverseitig autoritativ sein. + +--- + +# 27. `combat.state.changed` + +Optionales allgemeines Sync-Event. + +Es darf verwendet werden, wenn der Client wissen soll: + +> Der Combat-State hat sich geändert; lade bei Bedarf den aktuellen Zustand neu. + +Beispiel: + +```json +{ + "type": "combat.state.changed", + "payload": { + "combatId": "abc", + "revision": 17 + } +} +``` + +Es soll nicht jede spezialisierte Combat-Nachricht ersetzen. + +--- + +# 28. HTTP Response und WebSocket Event + +Für die Aktion des lokalen Spielers darf die HTTP Response weiterhin das Resultat enthalten. + +Das erzeugt bewusst mögliche doppelte Information: + +```text +HTTP Response ++ +WebSocket Broadcast +``` + +Der Client muss damit umgehen können. + +Deshalb brauchen Events stabile IDs oder Sequenzen. + +--- + +# 29. Event-Deduplizierung + +Der Client darf dasselbe Combat Event nicht zweimal animieren. + +CombatEvents besitzen bereits beziehungsweise erhalten eine stabile Reihenfolge. + +Beispiel: + +```text +combatId +sequence +``` + +Client speichert: + +```text +lastProcessedSequence +``` + +Wenn: + +```text +sequence <= lastProcessedSequence +``` + +wird das Event nicht erneut abgespielt. + +--- + +# 30. Event-Reihenfolge + +Innerhalb eines Combat Rooms muss die Reihenfolge serverseitig eindeutig sein. + +Beispiel: + +```text +41 PLAYER_ATTACK +42 DAMAGE_APPLIED +43 MONSTER_ATTACK +44 DAMAGE_APPLIED +45 TURN_CHANGED +``` + +Der Client spielt diese Reihenfolge ab. + +Nicht die Empfangszeit entscheidet über die fachliche Reihenfolge. + +--- + +# 31. Persistierte CombatEvents bleiben Source of Truth + +WebSocket Events ersetzen nicht die persistierten `CombatEvent`-Datensätze. + +Die Datenbank bleibt maßgeblich. + +Dadurch werden später möglich: + +- Reconnect +- Combat Log +- Debugging +- Replay +- nachträgliches Nachladen verpasster Events + +--- + +# 32. Resync nach Event-Lücke + +Wenn ein Client erkennt: + +```text +letzte bekannte Sequence = 40 +neues Event = 44 +``` + +existiert eine Lücke. + +Dann darf der Client nicht raten. + +Er synchronisiert: + +```text +GET /api/combats/:id +``` + +oder später: + +```text +GET /api/combats/:id/events?after=40 +``` + +Der konkrete Events-After-Endpunkt muss in 0.13 noch nicht zwingend implementiert werden. + +--- + +# 33. Frontend-Struktur + +Vorgeschlagene Struktur: + +```text +apps/web/src/app/core/events/ +├── game-events.service.ts +├── game-events.models.ts +├── game-events.store.ts +└── game-events.service.spec.ts +``` + +--- + +# 34. `GameEventsService` + +Verantwortlich für: + +- Verbindung herstellen +- Reconnect +- eingehende Events empfangen +- Event-Typen verteilen +- Lifecycle verwalten + +Nicht verantwortlich für: + +- Combat-State +- Character-State +- Quest-State + +--- + +# 35. Event-Verteilung im Frontend + +Der zentrale Event-Service verteilt Events fachlich. + +Konzeptionell: + +```ts +combatEvents$ +characterEvents$ +partyEvents$ +``` + +oder mit Angular Signals: + +```ts +combatEvent +characterEvent +``` + +Feature Stores abonnieren nur relevante Eventtypen. + +--- + +# 36. CombatStore Integration + +Der CombatStore reagiert auf: + +```text +combat.action.resolved +combat.turn.changed +combat.finished +``` + +Der Store darf daraus: + +- Events in Animationsqueue einreihen +- Aktionen aktivieren/deaktivieren +- Combat-State aktualisieren +- bei Unsicherheit REST-Resync auslösen + +--- + +# 37. WebSocket Event ≠ Animation + +Das Backend definiert fachliche Events. + +Nicht: + +```text +PLAY_SWORD_ANIMATION +WAIT_800_MS +SHOW_RED_NUMBER +``` + +Sondern: + +```text +ATTACK +DAMAGE +HEAL +STATUS_APPLIED +TURN_CHANGED +``` + +Der Client entscheidet, wie diese visuell dargestellt werden. + +Damit bleibt die Trennung erhalten: + +> Server entscheidet, was passiert. Client entscheidet, wie es aussieht. + +--- + +# 38. Keine WebSocket-HP-Ticks + +Das bestehende HP-Regenerationsmodell bleibt unverändert. + +Weiterhin: + +```text +currentHp +hpRegenSince +hpRegenPerSecond +``` + +Der Client berechnet die sichtbare Regeneration lokal. + +Nicht implementieren: + +```text +character.hp.changed 71 +character.hp.changed 72 +character.hp.changed 73 +``` + +pro Sekunde. + +--- + +# 39. Spätere Character Events + +Die Architektur soll jedoch ermöglichen: + +```text +character.vitals.changed +``` + +wenn eine **diskrete externe Veränderung** eintritt. + +Beispiele: + +- ein anderer Spieler heilt +- ein Gruppenbuff verändert Max HP +- ein Debuff verursacht Schaden +- eine externe Spielaktion verändert HP + +Beispiel: + +```json +{ + "type": "character.vitals.changed", + "payload": { + "characterId": "abc", + "currentHp": 84, + "hpRegenSince": "2026-08-21T15:10:20.000Z" + } +} +``` + +Danach läuft die bestehende lokale Regeneration weiter. + +Dieses Event muss in Slice 0.13 noch nicht produktiv verwendet werden. + +--- + +# 40. Keine globale Server-Tick-Schleife + +Slice 0.13 führt ausdrücklich keinen zentralen: + +```text +10 Hz +20 Hz +60 Hz +``` + +Game Loop ein. + +Ashen Realms bleibt: + +```text +event-driven ++ +turn-based ++ +timestamp-based +``` + +Server-Ticks werden erst eingeführt, wenn ein konkretes zukünftiges Feature sie tatsächlich benötigt. + +--- + +# 41. Vorbereitung für verzögerte NPC-Aktionen + +Die Event-Infrastruktur muss ermöglichen, dass später folgendes passiert: + +```text +Player Action +→ Commit +→ Combat Event +→ NPC Turn geplant +→ HTTP Request ist längst beendet +→ NPC Action wird ausgeführt +→ Commit +→ WebSocket Combat Event +``` + +Der Client muss dadurch nicht mehr selbst warten und anschließend eine NPC-Aktion simulieren. + +Die tatsächliche serverseitige NPC-Turn-Scheduling-Logik ist nicht Teil von 0.13. + +--- + +# 42. Keine `sleep()`-Requests + +Nicht implementieren: + +```ts +await sleep(1000); +performNpcAttack(); +return response; +``` + +HTTP Requests dürfen nicht künstlich offen gehalten werden, um Kampftiming zu simulieren. + +Spätere AI-Turns müssen unabhängig vom ursprünglichen Request verarbeitet werden können. + +--- + +# 43. Vorbereitung auf Combat Participants + +0.13 muss noch keine vollständige `CombatParticipant`-Migration durchführen, darf die Event Contracts aber nicht hart auf: + +```text +PLAYER +MONSTER +``` + +begrenzen. + +Events sollten allgemein mit: + +```text +actorId +targetId +``` + +arbeiten. + +Nicht: + +```text +playerDamage +monsterDamage +``` + +Dadurch können spätere Teilnehmer sein: + +```text +PLAYER +NPC +PET +COMPANION +BOSS +``` + +--- + +# 44. Beispiel zukünftiger Kampf + +Die 0.13-Architektur soll später ohne neuen Transportmechanismus ermöglichen: + +```text +TEAM A +- Player A +- Player B +- Pet + +TEAM B +- Bandit +- Wolf +- Bandit +``` + +Ablauf: + +```text +Player A handelt +→ Event + +Wolf handelt +→ Event + +Player B ist dran +→ Event + +Player B Client erhält: +combat.turn.changed +``` + +--- + +# 45. Fehlerbehandlung + +WebSocket-Fehler dürfen keinen falschen Spielzustand erzeugen. + +Bei: + +```text +Disconnect +invalid event +sequence gap +parse error +``` + +gilt: + +```text +UI als unsynchronisiert markieren +→ REST Resync +``` + +Nicht: + +```text +lokal weitersimulieren +``` + +--- + +# 46. Client-Verbindungsstatus + +Optional sichtbar oder intern: + +```ts +type EventConnectionState = + | 'DISCONNECTED' + | 'CONNECTING' + | 'CONNECTED' + | 'RECONNECTING'; +``` + +Bei kurzfristigem Disconnect soll nicht sofort eine störende Fehlermeldung erscheinen. + +Erst wenn Realtime tatsächlich für eine aktive Funktion nötig ist, muss der Zustand prominent dargestellt werden. + +--- + +# 47. Security + +Der Server muss prüfen: + +- gültige Authentifizierung +- Socket gehört zum User +- Character gehört zum User +- Combat gehört zum Character +- Room-Mitgliedschaft ist erlaubt + +Der Client darf: + +- keine fremden Combat Rooms abonnieren +- keine fremden Character Rooms abonnieren +- keine Server Events fälschen + +--- + +# 48. Rate Limits + +Für 0.13 ist kein komplexes WebSocket Rate Limiting notwendig. + +Dennoch gilt: + +Client-Nachrichten über den Socket sollten möglichst minimal bleiben. + +Da Commands weiterhin über REST laufen, ist der WebSocket in 0.13 fast ausschließlich: + +```text +Server → Client +``` + +--- + +# 49. Warum trotzdem WebSocket statt SSE + +Obwohl Slice 0.13 hauptsächlich Server-Push benötigt, wird direkt WebSocket verwendet. + +Grund: + +Spätere Systeme benötigen voraussichtlich bidirektionale Echtzeitkommunikation: + +- Multiplayer Combat +- Parties +- Chat +- Presence +- Social Systems + +Dadurch wird vermieden: + +```text +REST ++ SSE ++ später zusätzlich WebSocket +``` + +Ziel bleibt: + +```text +REST ++ +WebSocket +``` + +--- + +# 50. Shared Contracts + +Cross-Boundary Contracts gehören nach: + +```text +packages/shared +``` + +Geeignet: + +```ts +GameEvent +GameEventType +CombatActionResolvedPayload +CombatTurnChangedPayload +CombatFinishedPayload +``` + +Nicht dort ablegen: + +- NestJS Gateway +- Socket.IO Server +- Angular Services +- TypeORM Entities + +--- + +# 51. Vorgeschlagene Dateien Backend + +```text +packages/shared/src/events/ +├── game-event.ts +├── game-event-type.ts +└── combat-events.ts + +apps/api/src/events/ +├── events.module.ts +├── events.gateway.ts +├── event-room.service.ts +├── game-event-publisher.service.ts +├── events.gateway.spec.ts +└── game-event-publisher.service.spec.ts +``` + +Zusätzlich Änderungen in: + +```text +apps/api/src/combat/ +``` + +--- + +# 52. Vorgeschlagene Dateien Frontend + +```text +apps/web/src/app/core/events/ +├── game-events.service.ts +├── game-events.service.spec.ts +└── game-events.models.ts +``` + +Änderungen: + +```text +CombatStore +App initialization +Authentication lifecycle +``` + +--- + +# 53. Implementierungsreihenfolge + +## Task 1 – Shared Event Contracts + +Implementieren: + +```text +GameEvent +GameEventType +Combat Event Payloads +``` + +Tests: + +- TypeScript compile +- Contract consistency + +--- + +## Task 2 – WebSocket Gateway + +Implementieren: + +```text +/events +Authentication +Connect +Disconnect +``` + +Tests: + +- unauthenticated rejected +- authenticated accepted + +--- + +## Task 3 – Room Infrastructure + +Implementieren: + +```text +user room +character room +combat room +``` + +Tests: + +- nur berechtigte Membership +- kein fremder Combat Room + +--- + +## Task 4 – GameEventPublisher + +Domain-unabhängige Publish API implementieren. + +Tests: + +```text +publishToUser +publishToCharacter +publishToCombat +``` + +--- + +## Task 5 – Combat Integration + +Nach erfolgreichem Combat Commit: + +```text +combat.action.resolved +combat.turn.changed +combat.finished +``` + +veröffentlichen. + +--- + +## Task 6 – Frontend GameEventsService + +Implementieren: + +```text +connect +disconnect +reconnect +event parsing +``` + +--- + +## Task 7 – CombatStore Integration + +CombatEvents empfangen und in bestehende Combat-Darstellung integrieren. + +Bestehende REST-Funktionalität muss weiterhin funktionieren. + +--- + +## Task 8 – Reconnect & Resync + +Bei Reconnect: + +```text +Character neu laden +aktiven Combat prüfen +Combat State neu laden +Rooms erneut herstellen +``` + +--- + +# 54. Testing Backend + +Mindestens folgende Tests: + +### Gateway + +- nicht authentifizierte Verbindung wird abgelehnt +- authentifizierte Verbindung wird akzeptiert +- User Room wird automatisch verbunden +- Character Room wird korrekt verbunden +- fremder Combat Room wird abgelehnt + +### Publisher + +- Combat Event geht nur an Combat Room +- Character Event geht nur an Character Room + +### Combat + +- Action wird persistiert +- erst danach Event veröffentlicht +- Kampfende veröffentlicht `combat.finished` +- Event-Sequenz entspricht persistierter Reihenfolge + +--- + +# 55. Testing Frontend + +Mindestens: + +- Verbindung wird nach Login aufgebaut +- Verbindung wird bei Logout geschlossen +- Reconnect wird versucht +- unbekannte Event-Typen crashen den Client nicht +- Combat Event erreicht CombatStore +- doppelte Sequence wird ignoriert +- Sequence Gap löst Resync aus +- Disconnect zerstört lokalen Spielzustand nicht + +--- + +# 56. End-to-End-Test + +Minimaler E2E-Flow: + +```text +Client verbindet /events + +→ Hunt starten +→ Combat starten +→ Combat Room betreten +→ ATTACK per REST senden + +Server: +→ Action validieren +→ Combat berechnen +→ Combat speichern +→ Transaction committen +→ combat.action.resolved senden + +Client: +→ Event empfangen +→ Combat UI aktualisieren +→ Animation ausführen +``` + +Bei letztem Treffer: + +```text +→ Combat WON +→ combat.finished +→ Combat Room verlassen +``` + +--- + +# 57. Migration Requirement + +Slice 0.13 sollte möglichst **keine neue Datenbankmigration nur für WebSockets** benötigen. + +Persistierte CombatEvents bleiben bestehen. + +Falls für Event-Reihenfolge bereits ein geeignetes Feld existiert, wird dieses weiterverwendet. + +Nur wenn eine stabile Sequenz heute technisch nicht vorhanden ist, darf eine kleine CombatEvent-Sequenzmigration ergänzt werden. + +--- + +# 58. Performance-Grundsatz + +Keine globalen Broadcasts. + +Nicht: + +```text +send to all connected clients +``` + +Sondern: + +```text +send to combat room +send to character room +send to user room +``` + +Damit wächst das System später mit der Anzahl aktiver Spieler besser mit. + +--- + +# 59. Observability + +Für Development Logging vorsehen: + +```text +socket connected +socket disconnected +room joined +room left +event published +``` + +Keine vollständigen sensiblen Payloads ungefiltert loggen. + +Besonders hilfreich: + +```text +event type +combatId +room +sequence +``` + +--- + +# 60. Definition of Done + +Slice 0.13 ist abgeschlossen, wenn: + +- ein authentifizierter zentraler `/events` WebSocket existiert +- der Client genau eine zentrale Verbindung verwendet +- Reconnect funktioniert +- User-, Character- und Combat-Room-Konzept existiert +- Clients keine fremden Rooms abonnieren können +- ein gemeinsames `GameEvent`-Format existiert +- Combat Event Contracts in `packages/shared` liegen +- Combat-Aktionen weiterhin per REST ausgelöst werden +- Combat-Änderungen zusätzlich per WebSocket veröffentlicht werden +- Events erst nach erfolgreichem DB Commit gesendet werden +- Combat Events geordnet und deduplizierbar sind +- der Frontend CombatStore Events empfangen kann +- Disconnect und Reconnect keinen Spielzustand beschädigen +- HP-Regeneration unverändert timestamp-basiert funktioniert +- keine globale Server-Tick-Schleife eingeführt wurde +- bestehende Slice-0.12-Funktionalität weiterhin funktioniert +- Backend- und Frontendtests grün sind + +--- + +# 61. Architektur nach Slice 0.13 + +Nach erfolgreicher Implementierung gilt: + +```text + Ashen Realms Client + / \ + / \ + REST Commands WebSocket Events + | ^ + v | + NestJS API EventsGateway + | ^ + v | + Domain Services ---- EventPublisher + | + v + PostgreSQL +``` + +Grundregel: + +> **REST: Ich möchte etwas tun.** + +> **WebSocket: Etwas ist passiert.** + +> **Zeitstempel: Etwas verändert sich vorhersehbar mit der Zeit.** + +--- + +# 62. Vorbereitung für Slice 0.14+ + +Die Architektur soll insbesondere folgende nächsten Schritte ermöglichen: + +### Slice 0.14 +Combat Participants / mehrere Kampfteilnehmer + +### Slice 0.15 +Erster Mehrgegnerkampf + +Beispiel: + +```text +1 Spieler +vs. +3 NPCs +``` + +### Später + +```text +2 Spieler +vs. +3 NPCs +``` + +sowie: + +```text +Pets +NPC-Begleiter +Party Combat +PvP +``` + +Diese Systeme dürfen denselben: + +```text +/events WebSocket +``` + +weiterverwenden. + +Es wird kein separates Realtime-System für jeden neuen Featurebereich aufgebaut. + +--- + +# 63. Leitentscheidung + +Die wichtigste Entscheidung von Slice 0.13 lautet: + +> **Ashen Realms erhält keine klassische permanente Realtime-Simulation, sondern eine serverautoritative, ereignisgetriebene Realtime-Schicht.** + +Damit bleibt das Spiel technisch passend zu seiner Identität: + +- browserbasiert +- rundenbasiert +- persistent +- serverautoritativ +- später multiplayerfähig +- ohne unnötigen permanenten Game-Server-Tick \ No newline at end of file