# Ashen Realms – Playable Slice 0.5: First Upgrade **Status:** Ready for implementation **Prerequisite:** Playable Slice 0.4 – First Loot **Scope:** First usable inventory and equipment upgrade **Primary Upgrade:** Abgenutztes Kurzschwert → Räuberklinge **Primary Goal:** A looted item can be equipped and measurably changes the character's effective combat stats. --- # 1. Goal Playable Slice 0.5 completes the first full Ashen Realms progression loop. The existing playable flow: ```text World → Travel → Hunt → Encounter → Combat → Victory → Reward ``` becomes: ```text World → Travel → Hunt → Combat → Loot → Inventory → Equip upgrade → Character becomes stronger → next combat becomes easier ``` This slice must prove that: - player-owned items are persistent - inventory is server-authoritative - equipment is server-authoritative - equipment slots are enforced - item ownership is validated - required level is validated - effective character stats are derived from character base stats plus equipment - equipping an upgrade changes combat-relevant stats - the frontend does not calculate authoritative character power - a newly obtained weapon produces a visibly meaningful improvement The primary demonstration is: ```text Abgenutztes Kurzschwert 8 Waffenschaden ``` becomes: ```text Räuberklinge 11 Waffenschaden +1 Angriff ``` and the next combat deals more damage. --- # 2. Core player flow The intended flow is: ```text Straßenräuber besiegen ↓ Räuberklinge erhalten ↓ Reward screen ↓ Inventar öffnen ↓ Räuberklinge auswählen ↓ current item and new item compared ↓ Ausrüsten ↓ server validates item ↓ server equips Räuberklinge in Waffe slot ↓ effective stats recalculated ↓ Topbar / character UI updates ↓ return to hunt ↓ fight another enemy ↓ player deals more damage ``` This moment is the first real proof of item-driven progression. --- # 3. Scope Implement: ```text Inventory API Equipment API CharacterEquipment persistence CharacterStatsService effective character stats weapon equipment slot basic armor equipment slots where already supported inventory page item selection item detail presentation simple equipped-item comparison equip action unequip/replace behavior as required equipped state display effective stat refresh ``` At minimum, the system must support: ```text Abgenutztes Kurzschwert Räuberklinge Räuberhaube ``` where those items already exist in content. --- # 4. Explicit non-goals Do not implement: ```text item selling merchants item durability repairs salvaging crafting socketing random affixes item upgrades +1 to +10 transmog set bonuses complex tooltips drag-and-drop inventory inventory sorting systems filters search bank/storage stash equipment presets multiple builds comparison against every possible slot ``` Do not expand the slice into a complete MMO inventory system. The goal is only: > obtain item → inspect item → equip item → become stronger. --- # 5. Equipment philosophy Ashen Realms uses equipment as the primary source of character power. The Vertical Slice targets roughly: ```text 20 % strength from level/base stats 80 % strength from equipment ``` Therefore equipment changes must be noticeable. The player should immediately understand: ```text old weapon ↓ new weapon ↓ more damage ``` Do not hide the effect behind tiny percentage changes. --- # 6. Equipment slots The final Vertical Slice uses: ```text WEAPON HEAD CHEST HANDS LEGS FEET AMULET ``` Slice 0.5 should support this enum/data model cleanly. However, the actual playable demonstration only requires: ```text WEAPON ``` and optionally: ```text HEAD ``` if Räuberhaube is already part of the first loot implementation. Do not build seven complex UI workflows if only one or two slots currently have content. --- # 7. ItemDefinition Reuse the existing `ItemDefinition`. Do not create a second item model. Relevant conceptual fields: ```ts id: uuid; key: string; name: string; description: string; type: ItemType; equipmentSlot?: EquipmentSlot; rarity: ItemRarity; tier: number; requiredLevel: number; weaponDamage: number; bonusHp: number; bonusAttack: number; bonusArmor: number; sellPrice: number; iconPath: string; ``` Only fields already supported by the existing architecture should be introduced. Do not add speculative attributes. --- # 8. Initial item content ## Abgenutztes Kurzschwert Stable key: ```text worn-short-sword ``` Stats: ```text equipmentSlot: WEAPON requiredLevel: 1 weaponDamage: 8 bonusAttack: 0 bonusHp: 0 bonusArmor: 0 ``` This is the starting weapon. --- # 9. Räuberklinge Stable key: ```text bandit-blade ``` Stats: ```text equipmentSlot: WEAPON requiredLevel: 1 weaponDamage: 11 bonusAttack: 1 ``` This item must be a clear upgrade from the starting weapon. If finalized content in the repository differs, preserve the established project values. --- # 10. Räuberhaube Stable key: ```text bandit-hood ``` Stats: ```text equipmentSlot: HEAD bonusArmor: 3 bonusHp: 5 ``` Only include this in the playable inventory if it already exists in Slice 0.4 content. The weapon upgrade remains the required core test. --- # 11. CharacterItem Reuse the persistent player-owned item entity introduced in Slice 0.4. Conceptually: ```ts id: uuid; characterId: uuid; itemDefinitionId: uuid; quantity: number; createdAt: timestamptz; updatedAt: timestamptz; ``` Equipment ownership must originate from `CharacterItem`. The frontend must not be able to equip arbitrary `ItemDefinition.id` values. --- # 12. CharacterEquipment Create or reuse: ```text apps/api/src/equipment/entities/character-equipment.entity.ts ``` Conceptual fields: ```ts id: uuid; characterId: uuid; slot: EquipmentSlot; characterItemId: uuid; createdAt: timestamptz; updatedAt: timestamptz; ``` Important invariants: ```text one equipped item per character per slot ``` and: ```text one CharacterItem cannot occupy multiple equipment slots simultaneously ``` Protect these through service validation and appropriate database constraints. --- # 13. Ownership rule The server must validate: ```text CharacterItem belongs to current character ``` before equipment changes. Never accept: ```text ItemDefinition.id ``` alone as sufficient proof of ownership. Equip requests should identify the owned item: ```text CharacterItem.id ``` --- # 14. Equip validation Before equipping: ```text CharacterItem exists ↓ belongs to current character ↓ ItemDefinition is equippable ↓ equipmentSlot exists ↓ requiredLevel <= character level ↓ item is valid for target slot ``` The client must not choose an arbitrary target slot if the item already defines its slot. Prefer: ```http POST /api/equipment ``` with: ```json { "characterItemId": "uuid" } ``` The server derives: ```text slot ``` from the item definition. --- # 15. Equip replacement behavior If the slot already contains an item: ```text current item ↓ new item equipped ↓ old item becomes unequipped ↓ old item remains in inventory ``` Do not destroy or delete the old CharacterItem. Example: ```text WEAPON: Abgenutztes Kurzschwert ``` then equip: ```text Räuberklinge ``` result: ```text WEAPON: Räuberklinge Inventory: Abgenutztes Kurzschwert still owned ``` --- # 16. Unequip behavior For Slice 0.5, an explicit unequip endpoint is optional. If implemented: ```http DELETE /api/equipment/:slot ``` It must remove only the equipped relation. The item remains owned. Do not make explicit unequip necessary for replacing an item. --- # 17. Starting equipment The demo character must begin with: ```text Abgenutztes Kurzschwert ``` actually represented through the same inventory/equipment model used for future loot. Do not keep the starting weapon as an unrelated hardcoded combat constant once equipment is implemented. The goal is to remove temporary Slice 0.3 combat-stat shortcuts where possible. --- # 18. CharacterStatsService Introduce or complete: ```text CharacterStatsService ``` This becomes the single authoritative source for effective character stats. Conceptual return type: ```ts interface EffectiveCharacterStats { maxHp: number; currentHp: number; attack: number; weaponDamage: number; armor: number; combatPower: number; } ``` The service calculates values from: ```text Character base stats + equipped ItemDefinitions ``` Do not calculate effective stats in: ```text Angular CombatController InventoryController ``` --- # 19. Base stats The starting level-1 character uses: ```text baseHp = 100 baseAttack = 6 ``` Equipment supplies: ```text weaponDamage armor bonusHp bonusAttack ``` Starting equipment target: ```text 100 HP 6 base attack 8 weapon damage 6 armor ``` if the corresponding starting armor pieces are already modeled. If not all armor items currently exist, do not fabricate an entire starter gear set merely for Slice 0.5. Preserve the existing demo balance as closely as the implemented content allows. --- # 20. Effective stat calculation Conceptually: ```text maxHp = baseHp + sum equipped bonusHp attack = baseAttack + sum equipped bonusAttack weaponDamage = equipped weapon weaponDamage armor = sum equipped bonusArmor ``` If no weapon is equipped: ```text weaponDamage = 0 ``` or use another existing explicit project rule. Do not silently inject a fake weapon value. --- # 21. Combat Power Calculate internal Combat Power using the established formula: ```text Combat Power = HP / 10 + Attack × 2 + Weapon Damage × 2 + Armor × 1.5 ``` This value remains internal for balancing unless the existing UI already exposes it. Do not add Combat Power to the player-facing UI just because the service now calculates it. --- # 22. Combat integration Slice 0.3 combat snapshots player stats when combat begins. After Slice 0.5: ```text Combat creation ↓ CharacterStatsService.calculate(...) ↓ snapshot current effective equipment-derived stats ``` Therefore equipping Räuberklinge affects: ```text future combats ``` but must not retroactively alter: ```text already-active combat ``` This snapshot behavior is important. --- # 23. Example power change Before upgrade: ```text Base attack: 6 Weapon damage: 8 ``` Raw attack damage: ```text 14 ``` After equipping Räuberklinge: ```text Attack: 6 + 1 = 7 Weapon damage: 11 ``` Raw attack damage: ```text 18 ``` Therefore the upgrade should be clearly noticeable. --- # 24. Inventory API Implement: ```http GET /api/inventory ``` The server resolves the current character. Do not send: ```text characterId ``` from Angular. Example response: ```json { "items": [ { "id": "character-item-uuid", "quantity": 1, "equipped": false, "item": { "key": "bandit-blade", "name": "Räuberklinge", "rarity": "COMMON", "equipmentSlot": "WEAPON", "requiredLevel": 1, "weaponDamage": 11, "bonusAttack": 1, "bonusHp": 0, "bonusArmor": 0, "iconPath": "/assets/items/bandit-blade.webp" } } ] } ``` Do not expose unnecessary persistence details. --- # 25. Equipment API Implement: ```http GET /api/equipment ``` Response conceptually: ```json { "slots": { "WEAPON": { "characterItemId": "uuid", "item": { "key": "worn-short-sword", "name": "Abgenutztes Kurzschwert" } }, "HEAD": null }, "stats": { "maxHp": 100, "attack": 6, "weaponDamage": 8, "armor": 6 } } ``` Only expose slots supported by the current shared enum. --- # 26. Equip API Implement: ```http POST /api/equipment ``` Request: ```json { "characterItemId": "uuid" } ``` Server determines: ```text character item equipment slot validity ``` Response should return authoritative updated equipment and effective stats. Do not require the frontend to manually reload multiple unrelated resources if one coherent response can provide the changed state. --- # 27. Domain errors Use stable errors. Examples: ```text CHARACTER_ITEM_NOT_FOUND ITEM_NOT_OWNED ITEM_NOT_EQUIPPABLE ITEM_LEVEL_REQUIREMENT_NOT_MET INVALID_EQUIPMENT_SLOT ``` If another item occupies the slot, replacement is valid and should not be an error. --- # 28. Transaction Equip operations must be transactional. Conceptually: ```text load/lock CharacterItem ↓ validate ownership ↓ load ItemDefinition ↓ validate level/slot ↓ remove/replace current CharacterEquipment relation ↓ create/update equipment relation ↓ commit ``` Concurrent equip requests must not create duplicate slot occupancy. --- # 29. Inventory page route Activate or create: ```text /inventory ``` Enable: ```text Inventar ``` in the left navigation. The screen must remain inside the existing AppShell. --- # 30. Inventory page layout The inventory page should preserve the Ashen Realms visual language. Recommended desktop composition: ```text left / center: inventory item slots/grid right: selected item details / comparison ``` Avoid: ```text generic ecommerce product grid admin table SaaS data table ``` The inventory should feel like RPG equipment management. --- # 31. Inventory grid The full Vertical Slice concept allows approximately: ```text 24 slots ``` However Slice 0.5 does not require enforcing capacity yet unless this already exists. The UI may visually establish a slot-based inventory. At minimum display: ```text item icon quantity rarity equipped indicator ``` Empty slots may be displayed for visual structure. --- # 32. Item selection Clicking an owned item selects it. Selected item details show: ```text name icon rarity equipment slot required level stats equipped state ``` Example: ```text Räuberklinge Waffe Stufe 1 11 Waffenschaden +1 Angriff ``` --- # 33. Item comparison When selecting an equippable item, compare it to the currently equipped item in the same slot. Example: ```text Räuberklinge 11 Waffenschaden +3 +1 Angriff +1 ``` compared to: ```text Abgenutztes Kurzschwert 8 Waffenschaden ``` The comparison exists for player clarity only. The backend remains authoritative over actual stat calculations. --- # 34. Comparison rules Use simple deterministic numeric comparison. For Slice 0.5, show only direct fixed stats: ```text weaponDamage bonusAttack bonusHp bonusArmor ``` Do not invent an opaque overall item score. Do not use Combat Power as the item comparison metric. --- # 35. Equip action Selected equippable, owned, level-valid items show: ```text Ausrüsten ``` Clicking it calls: ```http POST /api/equipment ``` After success: ```text inventory state refreshes equipment state refreshes effective stats refresh equipped indicator updates ``` --- # 36. Already equipped state If the selected item is already equipped: ```text Ausgerüstet ``` should be clearly visible. Do not show another active: ```text Ausrüsten ``` button for the same item. --- # 37. Required-level state If the player's level is too low: Display: ```text Benötigt Stufe X ``` and disable the equip action. Backend must still enforce the same validation. --- # 38. Equipment overview The inventory or right context area should show current equipped slots. At minimum: ```text Waffe Kopf Brust Handschuhe Beine Stiefel Amulett ``` Slots without items should clearly show: ```text Leer ``` Do not add fake starter gear to fill every visual slot. --- # 39. Effective stats presentation Display a small character stat summary: ```text Leben Angriff Waffenschaden Rüstung ``` These values must come from the backend. Example before: ```text Angriff: 6 Waffenschaden: 8 ``` after: ```text Angriff: 7 Waffenschaden: 11 ``` The visual update is important to make the upgrade obvious. --- # 40. Topbar integration If the TopBar displays HP or other affected values, refresh its authoritative character state after equipment changes. Do not create a second conflicting stat representation. Reuse the existing character/world store architecture where appropriate. --- # 41. Reward screen integration Slice 0.4 currently presents dropped items. Add a useful navigation path: ```text Inventar öffnen ``` when equipment loot is obtained. Example: ```text Räuberklinge erhalten [ Inventar öffnen ] [ Zur Jagd ] ``` Do not equip loot directly from the reward screen in this slice. The player should consciously inspect and equip the item. --- # 42. CharacterStatsService tests At minimum test: ## Starting weapon Given: ```text baseAttack = 6 baseHp = 100 worn-short-sword: weaponDamage = 8 ``` verify: ```text attack = 6 weaponDamage = 8 ``` --- ## Räuberklinge Given: ```text bandit-blade: weaponDamage = 11 bonusAttack = 1 ``` verify: ```text attack = 7 weaponDamage = 11 ``` --- ## Armor aggregation Given multiple armor items: ```text sum bonusArmor ``` must be correct. --- ## HP aggregation Given equipment with: ```text bonusHp ``` verify: ```text maxHp = baseHp + bonuses ``` --- ## Combat Power Verify formula: ```text HP / 10 + attack × 2 + weaponDamage × 2 + armor × 1.5 ``` --- # 43. Equipment service tests At minimum test: ## Equip owned weapon ```text owned Räuberklinge ↓ equip ↓ WEAPON = Räuberklinge ``` --- ## Replace weapon Given: ```text WEAPON = Abgenutztes Kurzschwert ``` equip Räuberklinge. Verify: ```text WEAPON = Räuberklinge old sword still owned ``` --- ## Item not owned Attempt to equip another character's item. Expected: ```text ITEM_NOT_OWNED ``` --- ## Required level Attempt to equip an item above character level. Expected rejection. --- ## Not equippable Attempt to equip material/trade good. Expected rejection. --- ## Duplicate slot protection Concurrent or repeated operations must not produce two equipped weapons. --- # 44. Inventory API tests Verify: ```text only current character items returned ``` and each item correctly reports: ```text definition data quantity equipped state ``` --- # 45. Combat integration tests This is a critical Slice 0.5 proof. Test: ```text combat with Abgenutztes Kurzschwert ↓ record player damage ``` then: ```text equip Räuberklinge ↓ start new combat ↓ record player damage ``` Expected: ```text new combat deals more damage ``` Do not assert only that a stat number changed. Prove the upgrade actually affects gameplay. --- # 46. Existing combat snapshots Also verify: ```text start combat with old weapon ↓ equip change occurs outside combat if technically possible ``` must not alter the already-created combat snapshot. Prefer preventing equipment changes while an active combat exists. This is simpler and fits the game model. Recommended rule: > Equipment cannot be changed during an active combat. Return: ```text CHARACTER_IN_COMBAT ``` if attempted. --- # 47. Travel restriction Prefer also preventing equipment changes while travelling if the current product design considers travelling an unavailable interaction state. However, do not introduce this rule solely by assumption if existing UI already permits inventory management during travel. Follow the established behavior of the application. --- # 48. Frontend tests At minimum cover: ## Inventory load Opening: ```text /inventory ``` loads server inventory and equipment. --- ## Item rendering Räuberklinge displays: ```text icon name weapon damage bonus attack ``` --- ## Comparison Given equipped: ```text Abgenutztes Kurzschwert ``` and selected: ```text Räuberklinge ``` show the direct stat improvements. --- ## Equip request Click: ```text Ausrüsten ``` verify request contains only: ```json { "characterItemId": "uuid" } ``` --- ## Updated state After success: ```text Räuberklinge marked equipped Abgenutztes Kurzschwert marked unequipped effective attack updated weapon damage updated ``` --- ## Invalid item Server validation errors display in-shell. No browser alerts. --- # 49. Visual requirements Follow the established Ashen Realms UI: ```text dark metal stone leather bronze borders high-quality item icons clear rarity styling large selected-item detail ``` The inventory must feel like an RPG screen. Avoid: ```text spreadsheet table white cards generic admin UI Material default list Bootstrap grid ``` --- # 50. Item rarity Use the established rarity levels: ```text COMMON / Basis RARE / Selten EPIC / Besonders ``` or the actual enum names already present in the repository. Do not add more rarity tiers. Rarity may affect: ```text border treatment name emphasis small accent ``` but must not override readability. --- # 51. Item icons Item icons are an important progression signal. Use the existing generated Ashen Realms item assets. Do not replace them with generic icon libraries if appropriate game-specific icons already exist. A weapon upgrade should visually feel valuable before reading every number. --- # 52. Accessibility Required: ```text keyboard-accessible item selection real buttons visible focus states textual equipped indicator textual rarity readable stat changes disabled action explanation ``` Do not encode improvements only through green/red color. Example: ```text Waffenschaden 11 (+3) ``` is preferable to color alone. --- # 53. Server-authority checklist Server decides: ```text which items character owns which item is equipped which equipment slot an item uses whether level requirement is met effective HP effective attack effective weapon damage effective armor Combat Power combat snapshot stats ``` Client decides only: ```text which owned item the player selects whether the player requests to equip it ``` --- # 54. Database changes Create or extend migrations for: ```text character_equipment ``` and any missing indexes/constraints for `character_item`. Required constraints include conceptually: ```text unique(characterId, slot) ``` and appropriate ownership relations. Do not drop or recreate existing loot/combat/hunt/world data. --- # 55. Seed changes Ensure the demo character starts with: ```text Abgenutztes Kurzschwert ``` as a real CharacterItem and equipped WEAPON item. The seed must remain idempotent. Re-running must not: ```text duplicate starting sword duplicate equipment row delete earned Räuberklinge reset player inventory reset rewards reset XP reset silver ``` Be especially careful not to turn the seed into a player-state reset. --- # 56. Definition of Done Playable Slice 0.5 is complete when this complete flow works: ```text start with Abgenutztes Kurzschwert ↓ travel to Verbrannte Straße ↓ hunt Straßenräuber ↓ win combat ↓ Räuberklinge drops ↓ reward persists ↓ open Inventar ↓ see Abgenutztes Kurzschwert equipped ↓ select Räuberklinge ↓ see stat comparison ↓ click Ausrüsten ↓ server replaces weapon ↓ Räuberklinge becomes equipped ↓ effective stats increase ↓ return to hunt ↓ start another combat ↓ player deals more damage than before ``` --- # 57. Required verification Before completion run: ```text API unit tests API integration tests Angular tests API build Angular build migration compilation migration execution seed execution ``` Perform manual browser walkthroughs for: ```text inventory with starting weapon inventory after item drop select Räuberklinge comparison against starting sword equip Räuberklinge refresh inventory page equipped state survives refresh start new combat verify increased player damage ``` Also verify error cases: ```text equip item not owned equip invalid item equip level-locked item equip while active combat exists ``` where applicable. --- # 58. Acceptance criteria The slice is accepted when: - inventory is backed by persistent CharacterItem data - starting weapon uses the same item/equipment model as loot - equipment state is persisted - only owned items can be equipped - equipment slots are validated server-side - required level is validated server-side - replacing an item does not delete the previous item - CharacterStatsService is the authoritative effective-stat source - combat creation uses CharacterStatsService - active combat keeps its stat snapshot - Räuberklinge increases weapon damage - Räuberklinge increases attack - next combat demonstrably deals more damage - Angular does not calculate authoritative stats - inventory screen matches the existing Ashen Realms visual language - item comparison is understandable - refresh preserves equipment state - all tests pass - frontend and backend builds succeed --- # 59. Handoff after Slice 0.5 At the end of Slice 0.5, Ashen Realms has proven its first complete gameplay loop: ```text Travel ↓ Hunt ↓ Choose enemy ↓ Combat ↓ Victory ↓ Loot ↓ Inventory ↓ Equip upgrade ↓ Become stronger ↓ Fight again ``` This is the first major Vertical Slice milestone. Before dramatically expanding the content, the next development step should build on this verified loop rather than introducing unrelated systems. Possible next slices include: ```text 0.6 – Full First Combat Actions ``` with: ```text Schwerer Hieb Schildstoß Verteidigen Trank ``` or: ```text 0.6 – Complete Verbrannte Straße ``` with additional enemies, content and first progression pacing. The decision should be based on which aspect of the core loop should be validated next. --- # 60. Key gameplay proof The most important acceptance test is not simply: ```text Räuberklinge is equipped. ``` It is: ```text Before: the enemy takes X damage. Player equips Räuberklinge. After: the same type of enemy takes visibly more damage. ``` If that works correctly, the first central Ashen Realms progression promise has been proven: > **A good item makes the player meaningfully stronger.**