{ "exportedFrom": "docs/openup/model/skara-brae.eapx (Requirements/Use Case Model)", "actors": [ { "name": "Administrator", "notes": "Player with elevated rights (role = admin); may view any user\u0027s and any character\u0027s resources read-only." }, { "name": "Guest", "notes": "Unauthenticated caller; only register/login are open." }, { "name": "Player", "notes": "Authenticated user owning one or more characters (JWT role player)." } ], "useCases": [ { "name": "UC-01 Register Account", "notes": "Open registration. No precondition.", "actors": [ "Guest" ], "scenarios": [ { "name": "Main Success Scenario", "type": "Basic Path", "notes": "", "steps": [ { "actor": 0, "text": "Guest submits name (3-32 chars) and password (\u003e= 6 chars)." }, { "actor": 0, "text": "System verifies the name is unused -\u003e 409 CONFLICT if taken." }, { "actor": 0, "text": "System hashes the password (argon2), assigns the player role and the next id, persists the user." }, { "actor": 0, "text": "System issues a JWT (HS256, player role) and returns {token, user_id, name, role}." } ] }, { "name": "Alternate flows", "type": "Alternate", "notes": "name length invalid -\u003e 400; password too short -\u003e 400; name taken -\u003e 409; hashing/token failure -\u003e 500.", "steps": [ ] } ] }, { "name": "UC-02 Authenticate", "notes": "Login with name and password; issues a JWT with the user\u0027s real role.", "actors": [ "Guest" ], "scenarios": [ { "name": "Main Success Scenario", "type": "Basic Path", "notes": "", "steps": [ { "actor": 0, "text": "Guest submits name and password." }, { "actor": 0, "text": "System finds the user (401 if unknown) and verifies the password hash (401 on mismatch)." }, { "actor": 0, "text": "System issues a JWT carrying the user\u0027s real role (admin/player) and returns {token, user_id, name, role}." } ] }, { "name": "Alternate flows", "type": "Alternate", "notes": "unknown name or wrong password -\u003e 401 UNAUTHORIZED; token creation failure -\u003e 500.", "steps": [ ] } ] }, { "name": "UC-03 Manage Characters", "notes": "Create, list and view characters. Admin may act for any user (read-only view).", "actors": [ "Player", "Administrator" ], "scenarios": [ { "name": "Main Success Scenario (create)", "type": "Basic Path", "notes": "Admin may act for any user.", "steps": [ { "actor": 0, "text": "Player submits character name, race, class for their user id." }, { "actor": 0, "text": "System validates the target user exists (404) and the trimmed name is 1-32 chars (400)." }, { "actor": 0, "text": "System rolls stats (d6+5 base 6-16 per stat +/- race modifiers), computes max HP/energy/nerve from class, grants starting gold (50) and level-1 class spells to casters." }, { "actor": 0, "text": "System assigns the next character id, stores and persists the character; returns it fully." } ] }, { "name": "list/view", "type": "Alternate", "notes": "Player lists their characters (Admin: any user\u0027s); the system applies Regenerate Resources to each returned character and returns them. Viewing one character applies regen then returns it.", "steps": [ ] }, { "name": "Alternate flows", "type": "Alternate", "notes": "foreign user/character without admin role -\u003e 403 FORBIDDEN; user/character not found -\u003e 404; invalid name -\u003e 400.", "steps": [ ] } ] }, { "name": "UC-04 Browse Game Catalogue", "notes": "Races, classes, items (type/quality/slot filters), enemies, adventure zones from static game data.", "actors": [ "Player" ], "scenarios": [ { "name": "Main Success Scenario", "type": "Basic Path", "notes": "", "steps": [ { "actor": 0, "text": "Player requests the catalogue: races, classes, items (optional type/quality/slot filters), enemies, or adventure zones." }, { "actor": 0, "text": "System returns static game data loaded from skara-brae-common JSON (class info is enriched with is_caster)." } ] }, { "name": "Alternate flows", "type": "Alternate", "notes": "single item by unknown id -\u003e 404; filters may return an empty list (not an error).", "steps": [ ] } ] }, { "name": "UC-05 Train Stat", "notes": "Train a stat at a training ground; costs 1 energy + gold. Includes Regenerate Resources.", "actors": [ "Player" ], "scenarios": [ { "name": "Main Success Scenario", "type": "Basic Path", "notes": "Precondition: character exists and caller may act on it.", "steps": [ { "actor": 0, "text": "Player selects a training ground (strength / dexterity / constitution / intelligence / luck) and submits the stat name." }, { "actor": 0, "text": "System applies Regenerate Resources." }, { "actor": 0, "text": "System checks energy \u003e= 1 and gold \u003e= training cost (cost grows ~1.3x per 10 stat points)." }, { "actor": 0, "text": "System deducts 1 energy and the gold cost, increments the stat; constitution training recomputes max HP (current HP clamped)." }, { "actor": 0, "text": "System persists and returns {success, message, character}." } ] }, { "name": "Alternate flows", "type": "Alternate", "notes": "foreign character -\u003e 403; character not found -\u003e 404; not enough energy -\u003e 422; not enough gold -\u003e 422; unknown stat name -\u003e 400.", "steps": [ ] } ] }, { "name": "UC-06 Manage Equipment", "notes": "Equip from inventory / unequip back to inventory.", "actors": [ "Player" ], "scenarios": [ { "name": "Main Success Scenario (equip)", "type": "Basic Path", "notes": "", "steps": [ { "actor": 0, "text": "Player submits an item id from their inventory." }, { "actor": 0, "text": "System moves the item from inventory to its slot; a previously equipped item in that slot returns to inventory." }, { "actor": 0, "text": "System persists and returns the updated character." } ] }, { "name": "unequip", "type": "Alternate", "notes": "Player submits a slot name; the system moves the equipped item back to inventory.", "steps": [ ] }, { "name": "Alternate flows", "type": "Alternate", "notes": "foreign character -\u003e 403; character/item not found -\u003e 404; item not in inventory -\u003e 400; nothing equipped in slot -\u003e 400.", "steps": [ ] } ] }, { "name": "UC-07 Trade at Shop", "notes": "Buy from (always-stocked + rotating) shop stock or sell inventory items.", "actors": [ "Player" ], "scenarios": [ { "name": "Main Success Scenario (buy)", "type": "Basic Path", "notes": "", "steps": [ { "actor": 0, "text": "Player views the shop: always-stocked items plus rotating stock (with quantities) alongside their inventory." }, { "actor": 0, "text": "Player submits buy + item id." }, { "actor": 0, "text": "System checks gold \u003e= price (422), and for non-always-in-stock items decrements the limited stock (410 GONE if 0)." }, { "actor": 0, "text": "System deducts gold, adds the item to inventory, persists character and stock; returns {success, message, gold}." } ] }, { "name": "sell", "type": "Alternate", "notes": "Player submits sell + item id; system removes the first matching inventory item, pays half the item value, increments shop stock for non-permanent items.", "steps": [ ] }, { "name": "Alternate flows", "type": "Alternate", "notes": "unknown action or item not owned (sell) -\u003e 400; item not found -\u003e 404; insufficient gold -\u003e 422; stock exhausted -\u003e 410.", "steps": [ ] } ] }, { "name": "UC-08 Run Adventure", "notes": "Zone adventure with weighted enemy pick and turn-based combat. Includes Regenerate Resources, Resolve Combat. Exception: encounter references an unknown enemy -\u003e 500 (post WI-2; previously a panic). WI-2 design driver (sb_core::adventure extraction).", "actors": [ "Player" ], "scenarios": [ { "name": "Main Success Scenario", "type": "Basic Path", "notes": "Precondition: character exists and caller may act on it.", "steps": [ { "actor": 0, "text": "Player requests an adventure for a zone (default skara_brae_streets)." }, { "actor": 0, "text": "System validates the zone (404) and applies Regenerate Resources." }, { "actor": 0, "text": "System refuses incapacitated characters (HP \u003c= 0 -\u003e 400) and characters with nerve below the zone cost (422); otherwise deducts the nerve cost." }, { "actor": 0, "text": "System draws one enemy from the zone\u0027s weighted encounter table." }, { "actor": 0, "text": "System resolves turn-based combat: open-ended d100 attack rolls, OB vs DB, RoleMaster crit tables with level-gap damage caps, active bard song effects, active spell damage/heal per round." }, { "actor": 0, "text": "On player victory: XP and gold per the enemy definition, character HP set to the last round\u0027s defender HP, and loot dropped per-item chance rolls (only items existing in the catalogue)." }, { "actor": 0, "text": "On defeat: character HP set to 0; no rewards." }, { "actor": 0, "text": "Spell-point upkeep is charged whenever a spell was active, win or lose." }, { "actor": 0, "text": "System persists the character and returns {zone, enemy, combat_log, loot} (loot = item display names)." } ] }, { "name": "Alternate flows", "type": "Alternate", "notes": "foreign character -\u003e 403; character/zone not found -\u003e 404; incapacitated -\u003e 400; insufficient nerve -\u003e 422.", "steps": [ ] }, { "name": "Exception", "type": "Exception", "notes": "encounter references an unknown enemy (data error) -\u003e 500 (post WI-2; previously a panic).", "steps": [ ] } ] }, { "name": "UC-09 Heal at Temple", "notes": "Full or partial healing, cost = amount healed, minimum 1 gold.", "actors": [ "Player" ], "scenarios": [ { "name": "Main Success Scenario", "type": "Basic Path", "notes": "", "steps": [ { "actor": 0, "text": "Player requests healing, optionally partial." }, { "actor": 0, "text": "System computes missing HP; full heals all, partial heals half (rounded up); cost = amount healed, minimum 1 gold." }, { "actor": 0, "text": "System checks gold (422), deducts it, restores HP, persists; returns {hp, max_hp, gold, healed: true}." } ] }, { "name": "Alternate flows", "type": "Alternate", "notes": "foreign character -\u003e 403; not found -\u003e 404; already at full HP -\u003e 400; insufficient gold -\u003e 422.", "steps": [ ] } ] }, { "name": "UC-10 Practice Bard Song", "notes": "Set or clear the active bard song (Bard only, level-gated).", "actors": [ "Player" ], "scenarios": [ { "name": "Main Success Scenario", "type": "Basic Path", "notes": "Precondition: character class is Bard.", "steps": [ { "actor": 0, "text": "Player views available songs (level-gated, with combat effect descriptions) and the active song." }, { "actor": 0, "text": "Player submits a song id; system validates level requirement (422) and sets it active; returns {success, message, active_song}." } ] }, { "name": "clear", "type": "Alternate", "notes": "submitting no song id clears the active song.", "steps": [ ] }, { "name": "Alternate flows", "type": "Alternate", "notes": "non-Bard -\u003e 403; unknown song -\u003e 404; level too low -\u003e 422; foreign character -\u003e 403; not found -\u003e 404.", "steps": [ ] } ] }, { "name": "UC-11 Study Magic", "notes": "View spellbook, learn spell levels (1-7, gold cost), activate/clear the active spell. Caster classes only; spell level = (character level / 3) + 1, uncapped by code.", "actors": [ "Player" ], "scenarios": [ { "name": "Main Success Scenario (view spellbook)", "type": "Basic Path", "notes": "Precondition: character belongs to a caster class (Mage-\u003emagician, Wizard, Conjurer, Sorcerer). Spell level = (character level / 3) + 1 - uncapped by code (level 100 -\u003e spell level 34); learn requests are validated to 1-7.", "steps": [ { "actor": 0, "text": "Player requests their spellbook: caster class, current spell level, spell points, spells up to the achievable level (each marked known), and the learn-cost table for levels 2-7." } ] }, { "name": "learn spell level", "type": "Alternate", "notes": "", "steps": [ { "actor": 0, "text": "Player submits a spell level (1-7)." }, { "actor": 0, "text": "System validates caster class (403), level range (400), level not above the character\u0027s current spell level (422), gold \u003e= learn cost (422), and that new spells exist (400)." }, { "actor": 0, "text": "System deducts gold, adds all unknown spell ids of that level, recomputes and refills max spell points; returns {learned_count, spell_points, max_spell_points, gold}." } ] }, { "name": "activate/clear active spell", "type": "Alternate", "notes": "", "steps": [ { "actor": 0, "text": "Player submits a spell id (or empty to clear)." }, { "actor": 0, "text": "System validates the spell is known (403), exists (404), and spell points suffice (422); deducts the spell\u0027s points and sets it active; returns {active_spell, spell_points}." } ] } ] }, { "name": "UC-12 Level Up at Review Board", "notes": "Manual level-up: XP threshold + gold cost (500 per next level), full resource restore on level-up.", "actors": [ "Player" ], "scenarios": [ { "name": "Main Success Scenario", "type": "Basic Path", "notes": "", "steps": [ { "actor": 0, "text": "Player requests a level-up." }, { "actor": 0, "text": "System validates: below max level 100, XP \u003e= 18*100*(level)^2 for the next level (i.e. xp_for_level(next)), gold \u003e= 500*next level." }, { "actor": 0, "text": "System deducts the gold cost, increments the level, recomputes and fully restores HP/energy/nerve and max spell points; persists; returns {success, message, character}." } ] }, { "name": "Alternate flows", "type": "Alternate", "notes": "already at max level; not enough XP; not enough gold -\u003e all 422. Foreign character -\u003e 403; not found -\u003e 404.", "steps": [ ] } ] } ] }