Compare commits
No commits in common. "c92220b2a4680297e6f472547ade05ce22b6ba2d" and "93bb0347524ed642eb90e90c832153becbf37f51" have entirely different histories.
c92220b2a4
...
93bb034752
|
|
@ -213,35 +213,9 @@ associations); renders in this folder, generated by `scripts/openup/export-diagr
|
||||||
|
|
||||||
### 9.3 Interaction View
|
### 9.3 Interaction View
|
||||||
|
|
||||||
Design sequences for all twelve use-case realizations. Sources are the version-controlled
|
Not yet modeled: no sequence diagrams exist for the Skara Brae MVP (the EA model carries scenarios with
|
||||||
PlantUML files under `sequences/` (working copy per the PlantUML→EA workflow canon; the EA
|
per-step actors, not interactions). Candidate first sequences: UC-08 adventure request→combat→loot, and
|
||||||
model carries scenarios with per-step actors). Render: `java -jar plantuml.jar -tpng
|
UC-01/02 auth flows. Adding them is a future work item (PlantUML prototype → EA per the workflow canon).
|
||||||
-charset UTF-8 sequences/*.puml`; lifelines = the realization's analysis classes
|
|
||||||
(mapping §2), messages = the actual design elements (routes and domain functions).
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
### 9.4 Operational View
|
### 9.4 Operational View
|
||||||
|
|
||||||
|
|
@ -256,11 +230,10 @@ channel in the MVP (WebSocket notifications are a later-phase feature, vision.md
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| Use Case Overview | `../requirements/use-case-overview.png` | actors, use cases, associations |
|
| Use Case Overview | `../requirements/use-case-overview.png` | actors, use cases, associations |
|
||||||
| UC-01…UC-12 Realization | `uc-01-realization.png` … `uc-12-realization.png` | analysis classes + associations per UC |
|
| UC-01…UC-12 Realization | `uc-01-realization.png` … `uc-12-realization.png` | analysis classes + associations per UC |
|
||||||
| UC-01…UC-12 Sequence | `sequences/uc-01-register.png` … `sequences/uc-12-level-up.png` (sources: `sequences/*.puml`) | design interactions per UC |
|
|
||||||
| Component Architecture | `component-architecture.png` | joint component model, dependency rule |
|
| Component Architecture | `component-architecture.png` | joint component model, dependency rule |
|
||||||
|
|
||||||
EA model renders are produced by `scripts/openup/export-diagram-images.ps1`; sequence
|
All three sets are renders of the EA model (`docs/openup/model/skara-brae.eapx`) produced by
|
||||||
renders by PlantUML from the committed sources. Regenerate after changes (drift rule).
|
`scripts/openup/export-diagram-images.ps1`; regenerate after model changes (read-only, layout-preserving).
|
||||||
|
|
||||||
## 10. References
|
## 10. References
|
||||||
|
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 53 KiB |
|
|
@ -1,23 +0,0 @@
|
||||||
@startuml uc-01-register
|
|
||||||
autonumber
|
|
||||||
title UC-01 Register Account (design sequence)
|
|
||||||
actor Guest
|
|
||||||
participant "AuthBoundary\n«POST /api/auth/register»" as boundary <<boundary>>
|
|
||||||
participant "AccountRegistry\nsb-api::routes::register" as control <<control>>
|
|
||||||
participant "UserAccount\nsb-shared::user::User" as entity <<entity>>
|
|
||||||
|
|
||||||
== Register ==
|
|
||||||
Guest -> boundary : name (3-32), password (>= 6)
|
|
||||||
boundary -> control : register(name, password)
|
|
||||||
alt name invalid / password too short
|
|
||||||
control --> boundary : 400
|
|
||||||
else name taken
|
|
||||||
control --> boundary : 409 CONFLICT
|
|
||||||
else valid
|
|
||||||
control -> entity : hash password (argon2, sb-auth)
|
|
||||||
control -> entity : assign player role + next id
|
|
||||||
control -> entity : persist (sb-db)
|
|
||||||
control --> boundary : JWT HS256 (player role)
|
|
||||||
boundary --> Guest : {token, user_id, name, role}
|
|
||||||
end
|
|
||||||
@enduml
|
|
||||||
|
Before Width: | Height: | Size: 46 KiB |
|
|
@ -1,20 +0,0 @@
|
||||||
@startuml uc-02-authenticate
|
|
||||||
autonumber
|
|
||||||
title UC-02 Authenticate (design sequence)
|
|
||||||
actor Guest
|
|
||||||
participant "TokenService\n«POST /api/auth/login»" as boundary <<boundary>>
|
|
||||||
participant "Authenticator\nsb-api::routes::login" as control <<control>>
|
|
||||||
|
|
||||||
== Login ==
|
|
||||||
Guest -> boundary : name, password
|
|
||||||
boundary -> control : login(name, password)
|
|
||||||
alt unknown name or wrong password
|
|
||||||
control --> boundary : 401 UNAUTHORIZED
|
|
||||||
else valid
|
|
||||||
control -> control : verify_password (sb-auth::hash)
|
|
||||||
control -> control : create_token (sb-auth::jwt, real role)
|
|
||||||
control --> boundary : {token, user_id, name, role}
|
|
||||||
boundary --> Guest : {token, user_id, name, role}
|
|
||||||
end
|
|
||||||
note over boundary : auth_middleware guards\nUC-03..UC-12
|
|
||||||
@enduml
|
|
||||||
|
Before Width: | Height: | Size: 70 KiB |
|
|
@ -1,31 +0,0 @@
|
||||||
@startuml uc-03-manage-characters
|
|
||||||
autonumber
|
|
||||||
title UC-03 Manage Characters (design sequence)
|
|
||||||
actor Player
|
|
||||||
participant "CharacterCatalog\n«/api/users/{id}/characters»" as boundary <<boundary>>
|
|
||||||
participant "CharacterFactory\nsb-core::character::create_character" as control <<control>>
|
|
||||||
participant "Character\nsb-shared::character" as entity <<entity>>
|
|
||||||
participant "ResourceRegenerator\napply_regen" as regen <<entity>>
|
|
||||||
|
|
||||||
== Create ==
|
|
||||||
Player -> boundary : POST name, race, class (user id)
|
|
||||||
boundary -> control : create_character(rng, user, name, race, class)
|
|
||||||
alt user missing
|
|
||||||
control --> boundary : 404
|
|
||||||
else name invalid
|
|
||||||
control --> boundary : 400
|
|
||||||
else valid
|
|
||||||
control -> entity : roll stats (d6+5 +- race mods)
|
|
||||||
control -> entity : max HP/energy/nerve from class
|
|
||||||
control -> entity : gold 50 + level-1 spells (casters)
|
|
||||||
control -> entity : assign next character id, persist
|
|
||||||
control --> boundary : character
|
|
||||||
boundary --> Player : character (full)
|
|
||||||
end
|
|
||||||
|
|
||||||
== List / View ==
|
|
||||||
Player -> boundary : GET characters (own; admin: any)
|
|
||||||
boundary -> regen : apply_regen(character)
|
|
||||||
regen --> boundary : character (regenerated)
|
|
||||||
boundary --> Player : characters (regen applied)
|
|
||||||
@enduml
|
|
||||||
|
Before Width: | Height: | Size: 42 KiB |
|
|
@ -1,17 +0,0 @@
|
||||||
@startuml uc-04-browse-catalogue
|
|
||||||
autonumber
|
|
||||||
title UC-04 Browse Game Catalogue (design sequence)
|
|
||||||
actor Player
|
|
||||||
participant "CatalogueBrowser\n«/api/{races,classes,items,enemies,adventures}»" as boundary <<boundary>>
|
|
||||||
participant "GameData\nsb-core::data + items" as entity <<entity>>
|
|
||||||
|
|
||||||
== Browse ==
|
|
||||||
Player -> boundary : GET catalogue (optional type/quality/slot filters)
|
|
||||||
boundary -> entity : read LazyLock catalogue (sb-common JSON)
|
|
||||||
alt unknown item id
|
|
||||||
entity --> boundary : 404
|
|
||||||
else hit (possibly empty filter result)
|
|
||||||
entity --> boundary : static data (classes + is_caster)
|
|
||||||
boundary --> Player : races / classes / items / enemies / zones
|
|
||||||
end
|
|
||||||
@enduml
|
|
||||||
|
Before Width: | Height: | Size: 69 KiB |
|
|
@ -1,28 +0,0 @@
|
||||||
@startuml uc-05-train-stat
|
|
||||||
autonumber
|
|
||||||
title UC-05 Train Stat (design sequence)
|
|
||||||
actor Player
|
|
||||||
participant "GymBoundary\n«/api/characters/{id}/gym»" as boundary <<boundary>>
|
|
||||||
participant "TrainingService\nsb-core::services::train_stat" as control <<control>>
|
|
||||||
participant "ResourceRegenerator\napply_regen" as regen <<entity>>
|
|
||||||
participant "TrainingGrounds\nTRAINING_GROUNDS + training_cost" as entity <<entity>>
|
|
||||||
|
|
||||||
== Train ==
|
|
||||||
Player -> boundary : POST stat name
|
|
||||||
boundary -> regen : apply_regen(character)
|
|
||||||
regen --> boundary : character (regenerated)
|
|
||||||
boundary -> control : train_stat(character, stat)
|
|
||||||
control -> entity : cost = training_cost (x1.3 per 10 points)
|
|
||||||
alt not enough energy
|
|
||||||
control --> boundary : 422 (DomainError)
|
|
||||||
else not enough gold
|
|
||||||
control --> boundary : 422 (DomainError)
|
|
||||||
else unknown stat
|
|
||||||
control --> boundary : 400 (DomainError)
|
|
||||||
else ok
|
|
||||||
control -> entity : stat +1 (energy -1, gold -cost)
|
|
||||||
control -> entity : constitution: recompute max HP (clamp current)
|
|
||||||
control --> boundary : {success, message, character}
|
|
||||||
boundary --> Player : {success, message, character}
|
|
||||||
end
|
|
||||||
@enduml
|
|
||||||
|
Before Width: | Height: | Size: 62 KiB |
|
|
@ -1,30 +0,0 @@
|
||||||
@startuml uc-06-manage-equipment
|
|
||||||
autonumber
|
|
||||||
title UC-06 Manage Equipment (design sequence)
|
|
||||||
actor Player
|
|
||||||
participant "EquipmentBoundary\n«/api/characters/{id}/{equip,unequip}»" as boundary <<boundary>>
|
|
||||||
participant "EquipmentService\nsb-core::services::{equip,unequip}" as control <<control>>
|
|
||||||
participant "Equipment/Inventory\nCharacter.equipment/.inventory" as entity <<entity>>
|
|
||||||
|
|
||||||
== Equip ==
|
|
||||||
Player -> boundary : POST equip item id
|
|
||||||
boundary -> control : equip_item(character, item)
|
|
||||||
alt item not in inventory
|
|
||||||
control --> boundary : 400 (DomainError)
|
|
||||||
else ok
|
|
||||||
control -> entity : inventory -> slot\n(previous item returns to inventory)
|
|
||||||
control --> boundary : character
|
|
||||||
boundary --> Player : updated character
|
|
||||||
end
|
|
||||||
|
|
||||||
== Unequip ==
|
|
||||||
Player -> boundary : POST unequip slot
|
|
||||||
boundary -> control : unequip_item(character, slot)
|
|
||||||
alt slot empty
|
|
||||||
control --> boundary : 400 (DomainError)
|
|
||||||
else ok
|
|
||||||
control -> entity : slot -> inventory
|
|
||||||
control --> boundary : character
|
|
||||||
boundary --> Player : updated character
|
|
||||||
end
|
|
||||||
@enduml
|
|
||||||
|
Before Width: | Height: | Size: 75 KiB |
|
|
@ -1,37 +0,0 @@
|
||||||
@startuml uc-07-trade-at-shop
|
|
||||||
autonumber
|
|
||||||
title UC-07 Trade at Shop (design sequence)
|
|
||||||
actor Player
|
|
||||||
participant "ShopBoundary\n«/api/characters/{id}/shop»" as boundary <<boundary>>
|
|
||||||
participant "ShopService\nsb-api::routes::{shop_action,buy,sell}" as control <<control>>
|
|
||||||
participant "ShopStock\nAppState.shop_stock" as entity <<entity>>
|
|
||||||
|
|
||||||
== View ==
|
|
||||||
Player -> boundary : GET shop
|
|
||||||
boundary --> Player : always-stocked + rotating stock, inventory
|
|
||||||
|
|
||||||
== Buy ==
|
|
||||||
Player -> boundary : POST buy + item id
|
|
||||||
boundary -> control : buy_item(character, item)
|
|
||||||
control -> entity : check stock (non-permanent: decrement)
|
|
||||||
alt stock exhausted
|
|
||||||
entity --> control : 0 remaining
|
|
||||||
control --> boundary : 410 GONE
|
|
||||||
else gold < price
|
|
||||||
control --> boundary : 422
|
|
||||||
else ok
|
|
||||||
control -> entity : stock -1, gold -price, inventory +item
|
|
||||||
control --> boundary : {success, message, gold}
|
|
||||||
boundary --> Player : {success, message, gold}
|
|
||||||
end
|
|
||||||
|
|
||||||
== Sell ==
|
|
||||||
Player -> boundary : POST sell + item id
|
|
||||||
boundary -> control : sell_item(character, item)
|
|
||||||
alt item not owned / unknown action
|
|
||||||
control --> boundary : 400
|
|
||||||
else ok
|
|
||||||
control -> entity : inventory -item, gold +value/2, stock +1 (non-permanent)
|
|
||||||
boundary --> Player : {success, message, gold}
|
|
||||||
end
|
|
||||||
@enduml
|
|
||||||
|
Before Width: | Height: | Size: 119 KiB |
|
|
@ -1,52 +0,0 @@
|
||||||
@startuml uc-08-run-adventure
|
|
||||||
autonumber
|
|
||||||
title UC-08 Run Adventure (design sequence)
|
|
||||||
actor Player
|
|
||||||
participant "AdventureBoundary\n«/api/characters/{id}/adventure»" as boundary <<boundary>>
|
|
||||||
participant "AdventureService\nsb-core::adventure::run_adventure" as control <<control>>
|
|
||||||
participant "ResourceRegenerator\napply_regen" as regen <<entity>>
|
|
||||||
participant "CombatEngine\nsb-core::combat" as combat <<entity>>
|
|
||||||
participant "Combatant\nCombatStats" as combatant <<entity>>
|
|
||||||
participant "SpellEffect / BardSong\nsb-core::{spells,songs}" as fx <<entity>>
|
|
||||||
|
|
||||||
== Validate ==
|
|
||||||
Player -> boundary : POST adventure (zone, default skara_brae_streets)
|
|
||||||
boundary -> control : run_adventure(rng, character, zone)
|
|
||||||
alt zone unknown
|
|
||||||
control --> boundary : 404
|
|
||||||
else HP <= 0
|
|
||||||
control --> boundary : 400
|
|
||||||
else nerve < zone cost
|
|
||||||
control --> boundary : 422
|
|
||||||
else ok
|
|
||||||
end
|
|
||||||
control -> regen : apply_regen(character)
|
|
||||||
regen --> control : character (regenerated)
|
|
||||||
control -> control : nerve -= zone cost
|
|
||||||
|
|
||||||
== Encounter ==
|
|
||||||
control -> combatant : pick_enemy(rng, weighted table)
|
|
||||||
alt unknown enemy id (data error)
|
|
||||||
control --> boundary : 500 DomainError::UnknownEncounterEnemy
|
|
||||||
end
|
|
||||||
|
|
||||||
== Combat (rounds) ==
|
|
||||||
loop until one side falls
|
|
||||||
control -> combat : open_ended_roll(rng, attack)
|
|
||||||
combat -> combat : OB vs DB, crit table\n(level-gap damage caps)
|
|
||||||
combat -> fx : bard song effect, active spell dmg/heal
|
|
||||||
combat --> control : round result
|
|
||||||
end
|
|
||||||
|
|
||||||
== Resolve ==
|
|
||||||
alt player victory
|
|
||||||
control -> combatant : XP + gold per enemy def
|
|
||||||
control -> combatant : HP = last defender HP
|
|
||||||
control -> combatant : loot rolls (catalogue items only)
|
|
||||||
else defeat
|
|
||||||
control -> combatant : HP = 0, no rewards
|
|
||||||
end
|
|
||||||
control -> fx : spell-point upkeep (win or lose)
|
|
||||||
control --> boundary : {zone, enemy, combat_log, loot}
|
|
||||||
boundary --> Player : {zone, enemy, combat_log, loot}
|
|
||||||
@enduml
|
|
||||||
|
Before Width: | Height: | Size: 52 KiB |
|
|
@ -1,22 +0,0 @@
|
||||||
@startuml uc-09-heal-at-temple
|
|
||||||
autonumber
|
|
||||||
title UC-09 Heal at Temple (design sequence)
|
|
||||||
actor Player
|
|
||||||
participant "TempleBoundary\n«/api/characters/{id}/heal»" as boundary <<boundary>>
|
|
||||||
participant "HealingService\nsb-api::routes::heal_character" as control <<control>>
|
|
||||||
|
|
||||||
== Heal ==
|
|
||||||
Player -> boundary : POST heal (optionally partial)
|
|
||||||
boundary -> control : heal_character(character, partial)
|
|
||||||
control -> control : missing HP\nfull: all; partial: half (ceil)\ncost = healed, min 1 gold
|
|
||||||
alt already at full HP
|
|
||||||
control --> boundary : 400
|
|
||||||
else gold < cost
|
|
||||||
control --> boundary : 422
|
|
||||||
else ok
|
|
||||||
control -> control : gold -= cost, HP restored, persist
|
|
||||||
control --> boundary : {hp, max_hp, gold, healed: true}
|
|
||||||
boundary --> Player : {hp, max_hp, gold, healed: true}
|
|
||||||
end
|
|
||||||
note over control : handler-side logic - recorded debt\n(Architecture Notebook D1, Q3)
|
|
||||||
@enduml
|
|
||||||
|
Before Width: | Height: | Size: 63 KiB |
|
|
@ -1,29 +0,0 @@
|
||||||
@startuml uc-10-practice-bard-song
|
|
||||||
autonumber
|
|
||||||
title UC-10 Practice Bard Song (design sequence)
|
|
||||||
actor Player
|
|
||||||
participant "SongBoundary\n«/api/characters/{id}/songs»" as boundary <<boundary>>
|
|
||||||
participant "SongService\nsb-api::routes::set_song" as control <<control>>
|
|
||||||
participant "BardSong\nBARD_SONGS + active_song" as entity <<entity>>
|
|
||||||
|
|
||||||
== View ==
|
|
||||||
Player -> boundary : GET songs
|
|
||||||
boundary -> entity : available_songs (level-gated)
|
|
||||||
boundary --> Player : songs + effects + active song
|
|
||||||
|
|
||||||
== Set / Clear ==
|
|
||||||
Player -> boundary : POST song id (or empty to clear)
|
|
||||||
boundary -> control : set_song(character, song)
|
|
||||||
alt non-Bard
|
|
||||||
control --> boundary : 403
|
|
||||||
else unknown song
|
|
||||||
control --> boundary : 404
|
|
||||||
else level too low
|
|
||||||
control --> boundary : 422
|
|
||||||
else ok
|
|
||||||
control -> entity : active_song = song (or None), persist
|
|
||||||
control --> boundary : {success, message, active_song}
|
|
||||||
boundary --> Player : {success, message, active_song}
|
|
||||||
end
|
|
||||||
note over entity : active song applies in UC-08 combat (step 5)
|
|
||||||
@enduml
|
|
||||||
|
Before Width: | Height: | Size: 103 KiB |
|
|
@ -1,51 +0,0 @@
|
||||||
@startuml uc-11-study-magic
|
|
||||||
autonumber
|
|
||||||
title UC-11 Study Magic (design sequence)
|
|
||||||
actor Player
|
|
||||||
participant "MagicBoundary\n«/api/characters/{id}/spells»" as boundary <<boundary>>
|
|
||||||
participant "MagicService\nsb-api::routes::{get_spells,learn}" as control <<control>>
|
|
||||||
participant "Spell\nSpellDef + known/active/points" as entity <<entity>>
|
|
||||||
|
|
||||||
== View spellbook ==
|
|
||||||
Player -> boundary : GET spells
|
|
||||||
boundary -> control : get_spells(character)
|
|
||||||
control -> entity : caster class, spell level = (level/3)+1
|
|
||||||
control --> boundary : spells (marked known) + learn costs 2-7
|
|
||||||
boundary --> Player : spellbook + spell points
|
|
||||||
|
|
||||||
== Learn spell level ==
|
|
||||||
Player -> boundary : POST learn level (1-7)
|
|
||||||
boundary -> control : learn_spell_level(character, level)
|
|
||||||
alt non-caster
|
|
||||||
control --> boundary : 403
|
|
||||||
else level out of 1-7
|
|
||||||
control --> boundary : 400
|
|
||||||
else level above current spell level
|
|
||||||
control --> boundary : 422
|
|
||||||
else gold < learn cost
|
|
||||||
control --> boundary : 422
|
|
||||||
else no new spells at level
|
|
||||||
control --> boundary : 400
|
|
||||||
else ok
|
|
||||||
control -> entity : gold -= cost, add unknown spell ids
|
|
||||||
control -> entity : recompute + refill max spell points, persist
|
|
||||||
control --> boundary : {learned_count, spell_points, max_spell_points, gold}
|
|
||||||
boundary --> Player : {learned_count, ...}
|
|
||||||
end
|
|
||||||
|
|
||||||
== Activate / Clear active spell ==
|
|
||||||
Player -> boundary : POST spell id (or empty)
|
|
||||||
boundary -> control : activate_spell(character, spell)
|
|
||||||
alt spell not known
|
|
||||||
control --> boundary : 403
|
|
||||||
else spell unknown
|
|
||||||
control --> boundary : 404
|
|
||||||
else spell points insufficient
|
|
||||||
control --> boundary : 422
|
|
||||||
else ok
|
|
||||||
control -> entity : points -= cost, active_spell = spell, persist
|
|
||||||
control --> boundary : {active_spell, spell_points}
|
|
||||||
boundary --> Player : {active_spell, spell_points}
|
|
||||||
end
|
|
||||||
note over entity : active spell acts in UC-08 combat\n(dmg/heal per round + upkeep)
|
|
||||||
@enduml
|
|
||||||
|
Before Width: | Height: | Size: 60 KiB |
|
|
@ -1,26 +0,0 @@
|
||||||
@startuml uc-12-level-up
|
|
||||||
autonumber
|
|
||||||
title UC-12 Level Up at Review Board (design sequence)
|
|
||||||
actor Player
|
|
||||||
participant "ReviewBoundary\n«/api/characters/{id}/level-up»" as boundary <<boundary>>
|
|
||||||
participant "ReviewBoard\nsb-core::character::level_up" as control <<control>>
|
|
||||||
participant "Progression\nxp_for_level + level_up_cost" as entity <<entity>>
|
|
||||||
|
|
||||||
== Level up ==
|
|
||||||
Player -> boundary : POST level-up
|
|
||||||
boundary -> control : level_up(character)
|
|
||||||
control -> entity : xp_for_level(next) = 18*100*level^2
|
|
||||||
control -> entity : cost = 500 * next level
|
|
||||||
alt at max level 100
|
|
||||||
control --> boundary : 422 (DomainError)
|
|
||||||
else XP below threshold
|
|
||||||
control --> boundary : 422 (DomainError)
|
|
||||||
else gold < cost
|
|
||||||
control --> boundary : 422 (DomainError)
|
|
||||||
else ok
|
|
||||||
control -> entity : level += 1, gold -= cost
|
|
||||||
control -> entity : recompute + fully restore\nHP/energy/nerve/max SP, persist
|
|
||||||
control --> boundary : {success, message, character}
|
|
||||||
boundary --> Player : {success, message, character}
|
|
||||||
end
|
|
||||||
@enduml
|
|
||||||
|
|
@ -249,34 +249,3 @@ Read-only on the model: renders 14 diagrams to PNG for the markdown documents
|
||||||
image methods live on **ProjectInterface** (not Repository); `PutDiagramImageToFile(id,
|
image methods live on **ProjectInterface** (not Repository); `PutDiagramImageToFile(id,
|
||||||
path, 0)` = PNG; the diagram must be `OpenDiagram`-ed first or a blank 241×151 stub is
|
path, 0)` = PNG; the diagram must be `OpenDiagram`-ed first or a blank 241×151 stub is
|
||||||
written. Regenerate after model changes; renders reflect the manual layout.
|
written. Regenerate after model changes; renders reflect the manual layout.
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 7. Documentation restructure (2026-10-05, non-PSP effort)
|
|
||||||
|
|
||||||
The OpenUP markdown set was aligned to the blank templates (process-data repo,
|
|
||||||
`templates/openup/`) — no EA model change required: scenario content is unchanged,
|
|
||||||
reformatted only; the model's UC notes/actors already carry the brief descriptions the
|
|
||||||
template sections now expose. XMI backup added 2026-10-05 via manual EA export
|
|
||||||
(`exports/xmi-backup.xml`); the COM export path is broken in this EA 15 build
|
|
||||||
(`ExportPackageXMI` filename param declared as Object in the typelib — verified across
|
|
||||||
PowerShell/JScript/VBScript, arities 2–6; `ExportProjectXML` returns false silently).
|
|
||||||
|
|
||||||
Restructured to template form:
|
|
||||||
- `requirements/vision.md` — positioning tables, stakeholder summary, user environment,
|
|
||||||
needs-and-features table (R1/R2), other product requirements.
|
|
||||||
- `requirements/use-case-model.md` — per-UC specification sections (Brief Description,
|
|
||||||
Actor Brief Descriptions, Preconditions, Basic Flow, named Alternative/Exception
|
|
||||||
subsections with numbered steps, Post-conditions, Special Requirements). Flow step
|
|
||||||
text unchanged from version 1.0.
|
|
||||||
- `requirements/supplementary-specifications.md` — category tables with Priority and
|
|
||||||
Use-Case columns + reverse Use Case Coverage Matrix; IDs unchanged; project-specific
|
|
||||||
categories (Quality Gates, Data) kept, DOC-01 added.
|
|
||||||
- `test/quality-check-procedure.md` — migrated from Joplin (single content home);
|
|
||||||
stale open items marked resolved (WI-1/WI-2).
|
|
||||||
|
|
||||||
New design content:
|
|
||||||
- `analysis-design/sequences/uc-01..uc-12.puml` + PNG renders — design sequences per
|
|
||||||
realization (lifelines = analysis classes, messages = design elements; PlantUML per
|
|
||||||
the layout style guide). Embedded in Architecture Notebook §9.3, indexed §9.5.
|
|
||||||
EA import via PlantUML `-txmi` remains optional future work (workflow canon).
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
| # | Issue | Work Item | Iteration | PSP level | Est. N (LOC) | Act. N (LOC) | Est. time (min) | Act. time (min) | Status |
|
| # | Issue | Work Item | Iteration | PSP level | Est. N (LOC) | Act. N (LOC) | Est. time (min) | Act. time (min) | Status |
|
||||||
|---|-------|-----------|-----------|-----------|--------------|--------------|-----------------|-----------------|--------|
|
|---|-------|-----------|-----------|-----------|--------------|--------------|-----------------|-----------------|--------|
|
||||||
| 1 | skara-brae-server#1 | Injectable RNG (plan item #8) | I1 | PSP1.0 | 35 (pred. 42, PI 37–73) | **41** | 105 (PI 75–135) | **90** | **Done** — both actuals inside 70% PI (size −2.4%, time −14%) |
|
| 1 | skara-brae-server#1 | Injectable RNG (plan item #8) | I1 | PSP1.0 | 35 (pred. 42, PI 37–73) | **41** | 105 (PI 75–135) | **90** | **Done** — both actuals inside 70% PI (size −2.4%, time −14%) |
|
||||||
| 2 | skara-brae-server#2 | Architecture cleanup + OpenUP work set (plan item #7) | I1 | PSP1.0 | 660 (pred. 951, PI 607–1295) | **1833** | 620 (PI 455–785) | **201** | **Done, merged & closed 2026-10-05** — size +42% OVER UPI, time UNDER LPI (both PIs missed, opposite directions — calibration: agent-class data); 24 defects, 100% pre-compile; gates green, 71/71 tests; EA model built incl. XMI backup; EA session time deliberately unbooked |
|
| 2 | skara-brae-server#2 | Architecture cleanup + OpenUP work set (plan item #7) | I1 | PSP1.0 | 660 (pred. 951, PI 607–1295) | **1833** | 620 (PI 455–785) | **~171** | **Done** (pending human gates) — size +42% OVER UPI, time 72% UNDER LPI; 22 defects, 100% pre-compile; gates green, 71/71 tests |
|
||||||
|
|
||||||
Notes:
|
Notes:
|
||||||
- Estimates filled during PLN (PROBE); actuals during PM postmortem.
|
- Estimates filled during PLN (PROBE); actuals during PM postmortem.
|
||||||
|
|
|
||||||
|
|
@ -1,93 +1,51 @@
|
||||||
# Skara Brae — Supplementary Specifications
|
# Skara Brae — Supplementary Specifications
|
||||||
|
|
||||||
`Skara Brae` — OpenUP Requirements · version 2.0 (2026-10-05, restructured to the OpenUP
|
Version 1.0 (WI-2, 2026-10-03) · OpenUP artifact: `requirements/supplementary-specifications.md`
|
||||||
supplementary-specifications template: category tables with priority and use-case trace +
|
Non-functional requirements and constraints for the server MVP. Facts cite code where they are implemented; assumptions are marked.
|
||||||
coverage matrix; requirement IDs unchanged from version 1.0).
|
|
||||||
Non-functional requirements and constraints for the server MVP. Facts cite code where they
|
|
||||||
are implemented; assumptions are marked. Category tailoring vs stock OpenUP: this project
|
|
||||||
adds **Quality Gates** and **Data** categories (project-specific acceptance and
|
|
||||||
game-data rules); a Standards category is not applicable at R1.
|
|
||||||
|
|
||||||
# Performance / Scalability
|
## 1. Performance / Scalability
|
||||||
|
|
||||||
| **ID** | **Requirement** | **Priority** | **Use Cases** |
|
- **NFR-01 (in-memory state):** all game state (users, characters, shop stock) is held in process memory behind `tokio::sync::RwLock` (`crates/sb-api/src/routes/mod.rs:33–42`). Single-process deployment; persistence is write-through to SQLite, reads never hit the DB.
|
||||||
| --- | --- | --- | --- |
|
- **NFR-02 (lazy regeneration):** resource regeneration is computed on every character access from elapsed wall-clock time (`apply_regen`, character.rs:105–122) — no timers, no background ticks. Intervals: energy 180 s, nerve 300 s, HP 300 s (5% max HP per tick).
|
||||||
| NFR-01 | In-memory state: all game state (users, characters, shop stock) is held in process memory behind `tokio::sync::RwLock` (`crates/sb-api/src/routes/mod.rs:33–42`). Single-process deployment; persistence is write-through to SQLite, reads never hit the DB. | High | UC-01..UC-12 |
|
- **NFR-03 (client polling):** clients poll character state to observe regeneration; the assumed UI refresh cadence is ~15 s *(assumption carried from project planning; server-side behavior is poll-frequency-independent by design NFR-02)*.
|
||||||
| NFR-02 | Lazy regeneration: resource regeneration is computed on every character access from elapsed wall-clock time (`apply_regen`, character.rs:105–122) — no timers, no background ticks. Intervals: energy 180 s, nerve 300 s, HP 300 s (5% max HP per tick). | High | UC-03, UC-05, UC-08 |
|
- **NFR-04 (static catalogue):** items, enemies, zones, spells, and crit tables are compiled in via `include_str!` from `skara-brae-common` JSON and parsed once behind `LazyLock`; catalogue reads are lock-free after first access.
|
||||||
| NFR-03 | Client polling: clients poll character state to observe regeneration; the assumed UI refresh cadence is ~15 s *(assumption carried from project planning; server-side behavior is poll-frequency-independent by design NFR-02)*. | Medium | UC-03, UC-05, UC-08 |
|
|
||||||
| NFR-04 | Static catalogue: items, enemies, zones, spells, and crit tables are compiled in via `include_str!` from `skara-brae-common` JSON and parsed once behind `LazyLock`; catalogue reads are lock-free after first access. | High | UC-04 |
|
|
||||||
|
|
||||||
# Reliability / Correctness
|
## 2. Reliability / Correctness
|
||||||
|
|
||||||
| **ID** | **Requirement** | **Priority** | **Use Cases** |
|
- **NFR-05 (deterministic domain logic):** all domain randomness is injected `StdRng` (WI-1); identical seeds produce identical outcomes. Request paths construct RNG only at `request_rng()`.
|
||||||
| --- | --- | --- | --- |
|
- **NFR-06 (persistence best-effort):** persistence failures are logged (`tracing::error`) and do not fail the request; in-memory state remains authoritative for the process lifetime.
|
||||||
| NFR-05 | Deterministic domain logic: all domain randomness is injected `StdRng` (WI-1); identical seeds produce identical outcomes. Request paths construct RNG only at `request_rng()`. | High | UC-03, UC-07, UC-08 |
|
- **NFR-07 (referential data integrity):** zone encounter tables must reference existing enemy ids and loot drops must reference existing item ids; violations are detected at first use (WI-2: `DomainError::UnknownEncounterEnemy` → 500 instead of a panic).
|
||||||
| NFR-06 | Persistence best-effort: persistence failures are logged (`tracing::error`) and do not fail the request; in-memory state remains authoritative for the process lifetime. | Medium | UC-01, UC-03, UC-05..UC-12 |
|
|
||||||
| NFR-07 | Referential data integrity: zone encounter tables must reference existing enemy ids and loot drops must reference existing item ids; violations are detected at first use (WI-2: `DomainError::UnknownEncounterEnemy` → 500 instead of a panic). | High | UC-08 |
|
|
||||||
|
|
||||||
# Quality Gates (per-commit acceptance)
|
## 3. Quality Gates (per-commit acceptance)
|
||||||
|
|
||||||
| **ID** | **Requirement** | **Priority** | **Use Cases** |
|
- **NFR-08:** `cargo fmt --check` clean (fmt baseline established by WI-2).
|
||||||
| --- | --- | --- | --- |
|
- **NFR-09:** `cargo clippy --all-targets -- -D warnings` clean — zero-warning policy.
|
||||||
| NFR-08 | `cargo fmt --check` clean (fmt baseline established by WI-2). | High | all |
|
- **NFR-10:** `cargo test --workspace` fully green (45 sb-core tests at WI-2 start; suite only grows).
|
||||||
| NFR-09 | `cargo clippy --all-targets -- -D warnings` clean — zero-warning policy. | High | all |
|
- **NFR-11 (WI-2-specific):** behavior-identical refactor — JSON field names/order, HTTP status codes, game semantics, and RNG draw order unchanged.
|
||||||
| NFR-10 | `cargo test --workspace` fully green (45 sb-core tests at WI-2 start; suite only grows). | High | all |
|
- **NFR-12:** no `unwrap()`/`expect()` on request paths outside the documented keep-with-reason invariants in the design-note §6 ledger (covers sb-api, sb-core, sb-db mutex poisoning, sb-auth time/entropy invariants).
|
||||||
| NFR-11 | Behavior-identical refactor — JSON field names/order, HTTP status codes, game semantics, and RNG draw order unchanged (WI-2-specific; standing interpretation for future refactors). | High | all |
|
|
||||||
| NFR-12 | No `unwrap()`/`expect()` on request paths outside the documented keep-with-reason invariants in the design-note §6 ledger (covers sb-api, sb-core, sb-db mutex poisoning, sb-auth time/entropy invariants). | High | all |
|
|
||||||
|
|
||||||
# Data
|
## 4. Data
|
||||||
|
|
||||||
| **ID** | **Requirement** | **Priority** | **Use Cases** |
|
- **NFR-13 (shared data source):** all game content lives in the `skara-brae-common` repo as language-neutral JSON under `data/` — single source of truth consumed at build time by server (`include_str!` + serde) and client. Server must not duplicate or transform these definitions in code.
|
||||||
| --- | --- | --- | --- |
|
- **NFR-14 (persistence format):** optional SQLite via `SB_DB_PATH` (rusqlite; users, characters, shop stock with `next_character_id`). Absent the variable the server runs purely in-memory with seeded `admin`/`player` accounts.
|
||||||
| NFR-13 | Shared data source: all game content lives in the `skara-brae-common` repo as language-neutral JSON under `data/` — single source of truth consumed at build time by server (`include_str!` + serde) and client. Server must not duplicate or transform these definitions in code. | High | UC-04 |
|
- **NFR-15 (numeric headroom):** stats are `i64` (BIGINT) — “exponential growth, tiered display” is a product commitment; no narrowing conversions to smaller integers in new code.
|
||||||
| NFR-14 | Persistence format: optional SQLite via `SB_DB_PATH` (rusqlite; users, characters, shop stock with `next_character_id`). Absent the variable the server runs purely in-memory with seeded `admin`/`player` accounts. | Medium | UC-01, UC-03, UC-07 |
|
|
||||||
| NFR-15 | Numeric headroom: stats are `i64` (BIGINT) — "exponential growth, tiered display" is a product commitment; no narrowing conversions to smaller integers in new code. | High | UC-05, UC-08, UC-12 |
|
|
||||||
|
|
||||||
# Security
|
## 5. Security
|
||||||
|
|
||||||
| **ID** | **Requirement** | **Priority** | **Use Cases** |
|
- **NFR-16:** passwords hashed with argon2; verification constant-time via the crate.
|
||||||
| --- | --- | --- | --- |
|
- **NFR-17:** JWT (HS256, `jsonwebtoken`), 24 h expiry; all game routes behind auth middleware; cross-user access requires the `admin` role (403 otherwise).
|
||||||
| NFR-16 | Passwords hashed with argon2; verification constant-time via the crate. | High | UC-01, UC-02 |
|
- **NFR-18:** no secrets in code; JWT secret and admin/player seed passwords come from environment/configuration.
|
||||||
| NFR-17 | JWT (HS256, `jsonwebtoken`), 24 h expiry; all game routes behind auth middleware; cross-user access requires the `admin` role (403 otherwise). | High | UC-01..UC-12 |
|
|
||||||
| NFR-18 | No secrets in code; JWT secret and admin/player seed passwords come from environment/configuration. | High | UC-01, UC-02 |
|
|
||||||
|
|
||||||
# Interfaces
|
## 6. Constraints
|
||||||
|
|
||||||
| **ID** | **Requirement** | **Priority** | **Use Cases** |
|
- **CON-01:** Rust, edition **2024**; workspace crates `sb-api` / `sb-core` / `sb-db` / `sb-auth` / `sb-shared` + external sibling `sb-common` (absolute path dependency; submodule migration planned).
|
||||||
| --- | --- | --- | --- |
|
- **CON-02:** HTTP framework **Axum 0.8** (ws + macros features), tokio, tower stack (CORS/trace/compression-gzip).
|
||||||
| NFR-19 | REST JSON API; field names and order are a wire contract — refactors must preserve them byte-for-byte. The current API emits JSON object keys in lexicographic order (serde_json resolves without `preserve_order`; `json!` uses BTreeMap-backed maps), and the typed-response structs of WI-2 declare fields in that order to stay byte-identical. | High | UC-01..UC-12 |
|
- **CON-03:** `rand 0.9`; domain functions take `rng: &mut impl Rng`; handlers obtain RNG only from `request_rng()` (WI-1 rule).
|
||||||
| NFR-20 | Meaningful HTTP status codes: 400 malformed input, 401 auth failure, 403 foreign/non-permitted resource, 404 unknown resource, 409 name conflict, 410 shop stock exhausted, 422 game-rule violation (resources/requirements), 500 internal. | High | UC-01..UC-12 |
|
- **CON-04:** Error handling: `thiserror 2` in-domain; **no new error/framework dependencies**; one domain error enum (`sb_core::error::DomainError`) with a single central HTTP status mapping in sb-api.
|
||||||
|
- **CON-05:** Clean Architecture dependency rule: sb-core has zero knowledge of HTTP/axum/serde_json/tokio/tracing/sb-db; ports (domain traits) would live in sb-core, adapters outward.
|
||||||
|
- **CON-06:** OpenUP work products are versioned in the **skara-brae-common repo** under `docs/openup/` — one canonical project-docs home (decision reversed 2026-10-03 from the earlier skara-brae-server `docs/openup/` plan). The drafted WI-2 artifacts move there verbatim (coder, session 2); WI-1 artifacts at the old project-top folder migrate there as well. `roadmap.md` stays at the project-top folder per the earlier PM decision.
|
||||||
|
|
||||||
# Design Constraints
|
## 7. Usability / API
|
||||||
|
|
||||||
| **ID** | **Requirement** | **Priority** | **Use Cases** |
|
- **NFR-19:** REST JSON API; field names and order are a wire contract — refactors must preserve them byte-for-byte. The current API emits JSON object keys in **lexicographic order** (serde_json resolves without `preserve_order`; `json!` uses BTreeMap-backed maps), and the typed-response structs of WI-2 declare fields in that order to stay byte-identical.
|
||||||
| --- | --- | --- | --- |
|
- **NFR-20:** meaningful HTTP status codes: 400 malformed input, 401 auth failure, 403 foreign/non-permitted resource, 404 unknown resource, 409 name conflict, 410 shop stock exhausted, 422 game-rule violation (resources/requirements), 500 internal.
|
||||||
| CON-01 | Rust, edition **2024**; workspace crates `sb-api` / `sb-core` / `sb-db` / `sb-auth` / `sb-shared` + external sibling `sb-common` (absolute path dependency; submodule migration planned). | High | all |
|
|
||||||
| CON-02 | HTTP framework **Axum 0.8** (ws + macros features), tokio, tower stack (CORS/trace/compression-gzip). | High | all |
|
|
||||||
| CON-03 | `rand 0.9`; domain functions take `rng: &mut impl Rng`; handlers obtain RNG only from `request_rng()` (WI-1 rule). | High | UC-03, UC-07, UC-08 |
|
|
||||||
| CON-04 | Error handling: `thiserror 2` in-domain; **no new error/framework dependencies**; one domain error enum (`sb_core::error::DomainError`) with a single central HTTP status mapping in sb-api. | High | UC-05, UC-06, UC-08, UC-12 |
|
|
||||||
| CON-05 | Clean Architecture dependency rule: sb-core has zero knowledge of HTTP/axum/serde_json/tokio/tracing/sb-db; ports (domain traits) would live in sb-core, adapters outward. | High | all |
|
|
||||||
| CON-06 | OpenUP work products are versioned in the **skara-brae-common repo** under `docs/openup/` — one canonical project-docs home (decision reversed 2026-10-03 from the earlier skara-brae-server `docs/openup/` plan). `roadmap.md` stays at the project-top folder per the earlier PM decision. | Medium | — |
|
|
||||||
|
|
||||||
# Documentation
|
|
||||||
|
|
||||||
| **ID** | **Requirement** | **Priority** | **Use Cases** |
|
|
||||||
| --- | --- | --- | --- |
|
|
||||||
| DOC-01 | The OpenUP artifact set (Vision, Use-Case Specifications, Supplementary Specifications, Architecture Notebook, test artifacts) and the game-design canon (`docs/game/`) live in the skara-brae-common repo and are maintained there; the EA model and its exports render them. Joplin keeps project status only. | Medium | — |
|
|
||||||
|
|
||||||
# Use Case Coverage Matrix
|
|
||||||
|
|
||||||
| **ID** | **Use Case** | **Traced Requirements** |
|
|
||||||
| --- | --- | --- |
|
|
||||||
| UC-01 | Register Account | NFR-01, NFR-06, NFR-16, NFR-17, NFR-18, NFR-19, NFR-20 |
|
|
||||||
| UC-02 | Authenticate | NFR-16, NFR-17, NFR-18, NFR-19, NFR-20 |
|
|
||||||
| UC-03 | Manage Characters | NFR-01, NFR-02, NFR-03, NFR-05, NFR-06, NFR-14, NFR-17, NFR-19, NFR-20 |
|
|
||||||
| UC-04 | Browse Game Catalogue | NFR-04, NFR-13, NFR-19, NFR-20 |
|
|
||||||
| UC-05 | Train Stat | NFR-02, NFR-03, NFR-06, NFR-11, NFR-12, NFR-15, CON-04 |
|
|
||||||
| UC-06 | Manage Equipment | NFR-06, NFR-11, NFR-12, CON-04 |
|
|
||||||
| UC-07 | Trade at Shop | NFR-05, NFR-06, NFR-14, CON-03 |
|
|
||||||
| UC-08 | Run Adventure | NFR-02, NFR-03, NFR-05, NFR-07, NFR-11, NFR-15, CON-03, CON-04 |
|
|
||||||
| UC-09 | Heal at Temple | NFR-06, NFR-11, NFR-12 |
|
|
||||||
| UC-10 | Practice Bard Song | NFR-06, NFR-11, NFR-12 |
|
|
||||||
| UC-11 | Study Magic | NFR-06, NFR-11, NFR-12, NFR-15 |
|
|
||||||
| UC-12 | Level Up at Review Board | NFR-06, NFR-11, NFR-12, NFR-15, CON-04 |
|
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,23 @@
|
||||||
# Skara Brae — Use-Case Specifications
|
# Skara Brae — Use Case Model
|
||||||
|
|
||||||
`Skara Brae` — OpenUP Requirements · version 2.0 (2026-10-05, restructured to the OpenUP
|
Version 1.0 (WI-2, 2026-10-03) · OpenUP artifact: `requirements/use-case-model.md`
|
||||||
use-case-specification template; scenario content unchanged from version 1.0).
|
Scope: the **existing implemented system** (server MVP as of `wi-2-architecture-cleanup` @ 899fde8). Every flow below is derived from actual handler code (`crates/sb-api/src/routes/mod.rs`) — status codes cited are the implemented behavior and are normative.
|
||||||
Scope: the **existing implemented system** (server MVP as of `main`, formerly
|
|
||||||
`wi-2-architecture-cleanup` @ 899fde8). Every flow below is derived from actual handler
|
|
||||||
code (`crates/sb-api/src/routes/mod.rs`) — status codes cited are the implemented
|
|
||||||
behavior and are normative. The EA model (`docs/openup/model/skara-brae.eapx`) carries
|
|
||||||
the same scenarios with per-step actors; markdown and model must agree (drift rule).
|
|
||||||
|
|
||||||
# Use Case Overview
|
## Actors
|
||||||
|
|
||||||
| ID | Use Case | Actors | Includes / Extends |
|
| Actor | Description |
|
||||||
|
|---|---|
|
||||||
|
| **Player** | Authenticated user owning one or more characters (JWT role `player`). |
|
||||||
|
| **Administrator** | Player with elevated rights (`role = admin`); may view any user's and any character's resources read-only. |
|
||||||
|
| **Guest** | Unauthenticated caller; only register/login are open. |
|
||||||
|
|
||||||
|
## Use Case Overview
|
||||||
|
|
||||||
|
| ID | Use Case | Primary Actor | Includes / Extends |
|
||||||
|---|---|---|---|
|
|---|---|---|---|
|
||||||
| UC-01 | Register Account | Guest | — |
|
| UC-01 | Register Account | Guest | — |
|
||||||
| UC-02 | Authenticate | Guest | — |
|
| UC-02 | Authenticate | Guest | — |
|
||||||
| UC-03 | Manage Characters | Player, Administrator | — |
|
| UC-03 | Manage Characters | Player (Admin read) | — |
|
||||||
| UC-04 | Browse Game Catalogue | Player | — |
|
| UC-04 | Browse Game Catalogue | Player | — |
|
||||||
| UC-05 | Train Stat | Player | includes Regenerate Resources |
|
| UC-05 | Train Stat | Player | includes Regenerate Resources |
|
||||||
| UC-06 | Manage Equipment | Player | — |
|
| UC-06 | Manage Equipment | Player | — |
|
||||||
|
|
@ -27,372 +30,88 @@ the same scenarios with per-step actors; markdown and model must agree (drift ru
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
*Figure 1: Use case overview (rendered from the EA model via `scripts/openup/export-diagram-images.ps1`).*
|
*Figure 1: Use case overview (rendered from the EA model, `docs/openup/model/skara-brae.eapx`, via `scripts/openup/export-diagram-images.ps1`).*
|
||||||
|
|
||||||
Shared sub-flow **Regenerate Resources**: the system recomputes time-based regeneration
|
Shared sub-flow **Regenerate Resources**: the system recomputes time-based regeneration **at specific call sites only** — list characters, view character, run adventure, and train stat (routes/mod.rs:264–266, 331, 442, 642). Energy +1 per 180 s, nerve +1 per 300 s, HP +5% of max per 300 s (only if alive and injured), capped at maxima; `last_regen` advances to now. It is **not** applied by equip/unequip, gym view, shop, heal, songs, spells, or level-up.
|
||||||
**at specific call sites only** — list characters, view character, run adventure, and
|
|
||||||
train stat (routes/mod.rs:264–266, 331, 442, 642). Energy +1 per 180 s, nerve +1 per
|
|
||||||
300 s, HP +5% of max per 300 s (only if alive and injured), capped at maxima;
|
|
||||||
`last_regen` advances to now. It is **not** applied by equip/unequip, gym view, shop,
|
|
||||||
heal, songs, spells, or level-up.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
# UC-01 Register Account
|
## UC-01 Register Account
|
||||||
|
|
||||||
## Brief Description
|
|
||||||
|
|
||||||
Open registration: a guest submits name and password and receives a JWT with the `player`
|
|
||||||
role. No precondition.
|
|
||||||
|
|
||||||
## Actor Brief Descriptions
|
|
||||||
|
|
||||||
| **Actor** | **Type** | **Description** |
|
|
||||||
| --- | --- | --- |
|
|
||||||
| Guest | Primary | Unauthenticated caller; only register/login are open. |
|
|
||||||
|
|
||||||
## Preconditions and Context
|
|
||||||
|
|
||||||
Precondition: none.
|
|
||||||
|
|
||||||
## Basic Flow of Events
|
|
||||||
|
|
||||||
|
**Precondition:** none. **Main success scenario:**
|
||||||
1. Guest submits name (3–32 chars) and password (≥ 6 chars).
|
1. Guest submits name (3–32 chars) and password (≥ 6 chars).
|
||||||
2. System verifies the name is unused → 409 CONFLICT if taken.
|
2. System verifies the name is unused → 409 CONFLICT if taken.
|
||||||
3. System hashes the password (argon2), assigns the `player` role and the next id, persists the user.
|
3. System hashes the password (argon2), assigns the `player` role and the next id, persists the user.
|
||||||
4. System issues a JWT (HS256, `player` role) and returns `{token, user_id, name, role}`.
|
4. System issues a JWT (HS256, `player` role) and returns `{token, user_id, name, role}`.
|
||||||
|
|
||||||
## Alternative and Exception Flows
|
**Alternate flows:** name length invalid → 400; password too short → 400; name taken → 409; hashing/token failure → 500.
|
||||||
|
|
||||||
### Invalid input (Alternate)
|
## UC-02 Authenticate
|
||||||
|
|
||||||
1. System rejects a name outside 3–32 chars or a password under 6 chars with 400.
|
|
||||||
|
|
||||||
### Hashing or token failure (Exception)
|
|
||||||
|
|
||||||
1. System fails during password hashing or JWT creation → 500; no user is persisted.
|
|
||||||
|
|
||||||
## Post-conditions
|
|
||||||
|
|
||||||
- User persisted with `player` role; JWT issued and returned.
|
|
||||||
|
|
||||||
## Special Requirements
|
|
||||||
|
|
||||||
- Passwords hashed with argon2, verification constant-time (NFR-16).
|
|
||||||
- JWT HS256, 24 h expiry (NFR-17); no secrets in code (NFR-18).
|
|
||||||
|
|
||||||
# UC-02 Authenticate
|
|
||||||
|
|
||||||
## Brief Description
|
|
||||||
|
|
||||||
Login with name and password; issues a JWT carrying the user's real role.
|
|
||||||
|
|
||||||
## Actor Brief Descriptions
|
|
||||||
|
|
||||||
| **Actor** | **Type** | **Description** |
|
|
||||||
| --- | --- | --- |
|
|
||||||
| Guest | Primary | Unauthenticated caller; only register/login are open. |
|
|
||||||
|
|
||||||
## Preconditions and Context
|
|
||||||
|
|
||||||
Precondition: none.
|
|
||||||
|
|
||||||
## Basic Flow of Events
|
|
||||||
|
|
||||||
|
**Main success scenario:**
|
||||||
1. Guest submits name and password.
|
1. Guest submits name and password.
|
||||||
2. System finds the user (401 if unknown) and verifies the password hash (401 on mismatch).
|
2. System finds the user (401 if unknown) and verifies the password hash (401 on mismatch).
|
||||||
3. System issues a JWT carrying the user's real role (`admin`/`player`) and returns `{token, user_id, name, role}`.
|
3. System issues a JWT carrying the user's real role (`admin`/`player`) and returns `{token, user_id, name, role}`.
|
||||||
|
|
||||||
## Alternative and Exception Flows
|
**Alternate flows:** unknown name or wrong password → 401 UNAUTHORIZED; token creation failure → 500.
|
||||||
|
|
||||||
### Credentials rejected (Alternate)
|
## UC-03 Manage Characters
|
||||||
|
|
||||||
1. Unknown name or wrong password → 401 UNAUTHORIZED.
|
**Main success scenario (create):**
|
||||||
|
1. Player submits character name, race, class for their user id (Admin may act for any user).
|
||||||
### Token creation failure (Exception)
|
|
||||||
|
|
||||||
1. JWT creation fails → 500.
|
|
||||||
|
|
||||||
## Post-conditions
|
|
||||||
|
|
||||||
- JWT issued with the user's real role; no persistent state change.
|
|
||||||
|
|
||||||
## Special Requirements
|
|
||||||
|
|
||||||
- The middleware guards all UC-03…12 routes with this token (NFR-17).
|
|
||||||
|
|
||||||
# UC-03 Manage Characters
|
|
||||||
|
|
||||||
## Brief Description
|
|
||||||
|
|
||||||
Create, list and view characters. Admin may act for any user (read-only view).
|
|
||||||
|
|
||||||
## Actor Brief Descriptions
|
|
||||||
|
|
||||||
| **Actor** | **Type** | **Description** |
|
|
||||||
| --- | --- | --- |
|
|
||||||
| Player | Primary | Authenticated user owning one or more characters (JWT role `player`). |
|
|
||||||
| Administrator | Supporting | Player with elevated rights (`role = admin`); may view any user's and any character's resources read-only. |
|
|
||||||
|
|
||||||
## Preconditions and Context
|
|
||||||
|
|
||||||
Precondition (create): target user exists. Admin may act for any user.
|
|
||||||
|
|
||||||
## Basic Flow of Events (create)
|
|
||||||
|
|
||||||
1. Player submits character name, race, class for their user id.
|
|
||||||
2. System validates the target user exists (404) and the trimmed name is 1–32 chars (400).
|
2. System validates the target user exists (404) and the trimmed name is 1–32 chars (400).
|
||||||
3. 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.
|
3. 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.
|
||||||
4. System assigns the next character id, stores and persists the character; returns it fully.
|
4. System assigns the next character id, stores and persists the character; returns it fully.
|
||||||
|
|
||||||
## Alternative and Exception Flows
|
**Scenario (list/view):** Player lists their characters (Admin: any user's); the system applies Regenerate Resources to each returned character and returns them. Viewing one character applies regen then returns it.
|
||||||
|
|
||||||
### List / view (Alternate)
|
**Alternate flows:** foreign user/character without admin role → 403 FORBIDDEN; user/character not found → 404; invalid name → 400.
|
||||||
|
|
||||||
1. Player lists their characters (Admin: any user's); the system applies Regenerate Resources to each returned character and returns them.
|
## UC-04 Browse Game Catalogue
|
||||||
2. Player views one character; the system applies regen then returns it.
|
|
||||||
|
|
||||||
### Access denied (Alternate)
|
|
||||||
|
|
||||||
1. Foreign user/character without admin role → 403 FORBIDDEN.
|
|
||||||
|
|
||||||
### Not found (Alternate)
|
|
||||||
|
|
||||||
1. User or character not found → 404.
|
|
||||||
|
|
||||||
### Invalid name (Alternate)
|
|
||||||
|
|
||||||
1. Trimmed name outside 1–32 chars → 400.
|
|
||||||
|
|
||||||
## Post-conditions
|
|
||||||
|
|
||||||
- (create) Character persisted with rolled stats, class resources and starting gold.
|
|
||||||
- (view/list) Regeneration applied to returned characters.
|
|
||||||
|
|
||||||
## Special Requirements
|
|
||||||
|
|
||||||
- Stat rolls use the injected rng — deterministic under seed (NFR-05, WI-1).
|
|
||||||
|
|
||||||
# UC-04 Browse Game Catalogue
|
|
||||||
|
|
||||||
## Brief Description
|
|
||||||
|
|
||||||
Races, classes, items (type/quality/slot filters), enemies, adventure zones from static
|
|
||||||
game data.
|
|
||||||
|
|
||||||
## Actor Brief Descriptions
|
|
||||||
|
|
||||||
| **Actor** | **Type** | **Description** |
|
|
||||||
| --- | --- | --- |
|
|
||||||
| Player | Primary | Authenticated user owning one or more characters (JWT role `player`). |
|
|
||||||
|
|
||||||
## Preconditions and Context
|
|
||||||
|
|
||||||
Precondition: authenticated.
|
|
||||||
|
|
||||||
## Basic Flow of Events
|
|
||||||
|
|
||||||
|
**Main success scenario:**
|
||||||
1. Player requests the catalogue: races, classes, items (optional type/quality/slot filters), enemies, or adventure zones.
|
1. Player requests the catalogue: races, classes, items (optional type/quality/slot filters), enemies, or adventure zones.
|
||||||
2. System returns static game data loaded from `skara-brae-common` JSON (class info is enriched with `is_caster`).
|
2. System returns static game data loaded from `skara-brae-common` JSON (class info is enriched with `is_caster`).
|
||||||
|
|
||||||
## Alternative and Exception Flows
|
**Alternate flows:** single item by unknown id → 404; filters may return an empty list (not an error).
|
||||||
|
|
||||||
### Unknown item (Alternate)
|
## UC-05 Train Stat
|
||||||
|
|
||||||
1. Single item by unknown id → 404.
|
|
||||||
|
|
||||||
### Empty filter result (Alternate)
|
|
||||||
|
|
||||||
1. Filters may return an empty list (not an error).
|
|
||||||
|
|
||||||
## Post-conditions
|
|
||||||
|
|
||||||
- None (read-only).
|
|
||||||
|
|
||||||
## Special Requirements
|
|
||||||
|
|
||||||
- Catalogue is compiled-in and parsed once behind `LazyLock`; lock-free reads (NFR-04).
|
|
||||||
- Content source is `skara-brae-common` JSON, never duplicated in code (NFR-13).
|
|
||||||
|
|
||||||
# UC-05 Train Stat
|
|
||||||
|
|
||||||
## Brief Description
|
|
||||||
|
|
||||||
Train a stat at a training ground; costs 1 energy + gold. Includes Regenerate Resources.
|
|
||||||
|
|
||||||
## Actor Brief Descriptions
|
|
||||||
|
|
||||||
| **Actor** | **Type** | **Description** |
|
|
||||||
| --- | --- | --- |
|
|
||||||
| Player | Primary | Authenticated user owning one or more characters (JWT role `player`). |
|
|
||||||
|
|
||||||
## Preconditions and Context
|
|
||||||
|
|
||||||
Precondition: character exists and caller may act on it.
|
|
||||||
|
|
||||||
## Basic Flow of Events
|
|
||||||
|
|
||||||
|
**Precondition:** character exists and caller may act on it. **Main success scenario:**
|
||||||
1. Player selects a training ground (strength / dexterity / constitution / intelligence / luck) and submits the stat name.
|
1. Player selects a training ground (strength / dexterity / constitution / intelligence / luck) and submits the stat name.
|
||||||
2. System applies Regenerate Resources.
|
2. System applies Regenerate Resources.
|
||||||
3. System checks energy ≥ 1 and gold ≥ training cost (cost grows ~1.3× per 10 stat points).
|
3. System checks energy ≥ 1 and gold ≥ training cost (cost grows ~1.3× per 10 stat points).
|
||||||
4. System deducts 1 energy and the gold cost, increments the stat; constitution training recomputes max HP (current HP clamped).
|
4. System deducts 1 energy and the gold cost, increments the stat; constitution training recomputes max HP (current HP clamped).
|
||||||
5. System persists and returns `{success, message, character}`.
|
5. System persists and returns `{success, message, character}`.
|
||||||
|
|
||||||
## Alternative and Exception Flows
|
**Alternate flows:** foreign character → 403; character not found → 404; not enough energy → 422; not enough gold → 422; unknown stat name → 400.
|
||||||
|
|
||||||
### Foreign character (Alternate)
|
## UC-06 Manage Equipment
|
||||||
|
|
||||||
1. Character owned by another user without admin role → 403.
|
|
||||||
|
|
||||||
### Not found (Alternate)
|
|
||||||
|
|
||||||
1. Character not found → 404.
|
|
||||||
|
|
||||||
### Not enough energy (Alternate)
|
|
||||||
|
|
||||||
1. Energy < 1 → 422.
|
|
||||||
|
|
||||||
### Not enough gold (Alternate)
|
|
||||||
|
|
||||||
1. Gold below training cost → 422.
|
|
||||||
|
|
||||||
### Unknown stat (Alternate)
|
|
||||||
|
|
||||||
1. Unknown stat name → 400.
|
|
||||||
|
|
||||||
## Post-conditions
|
|
||||||
|
|
||||||
- Stat incremented; energy −1 and gold −cost deducted; max HP recomputed on constitution training; character persisted.
|
|
||||||
|
|
||||||
## Special Requirements
|
|
||||||
|
|
||||||
- Rule failures flow through `DomainError` → central status mapping (CON-04).
|
|
||||||
|
|
||||||
# UC-06 Manage Equipment
|
|
||||||
|
|
||||||
## Brief Description
|
|
||||||
|
|
||||||
Equip from inventory / unequip back to inventory.
|
|
||||||
|
|
||||||
## Actor Brief Descriptions
|
|
||||||
|
|
||||||
| **Actor** | **Type** | **Description** |
|
|
||||||
| --- | --- | --- |
|
|
||||||
| Player | Primary | Authenticated user owning one or more characters (JWT role `player`). |
|
|
||||||
|
|
||||||
## Preconditions and Context
|
|
||||||
|
|
||||||
Precondition: character exists and caller may act on it.
|
|
||||||
|
|
||||||
## Basic Flow of Events (equip)
|
|
||||||
|
|
||||||
|
**Main success scenario (equip):**
|
||||||
1. Player submits an item id from their inventory.
|
1. Player submits an item id from their inventory.
|
||||||
2. System moves the item from inventory to its slot; a previously equipped item in that slot returns to inventory.
|
2. System moves the item from inventory to its slot; a previously equipped item in that slot returns to inventory.
|
||||||
3. System persists and returns the updated character.
|
3. System persists and returns the updated character.
|
||||||
|
|
||||||
## Alternative and Exception Flows
|
**Scenario (unequip):** Player submits a slot name; the system moves the equipped item back to inventory.
|
||||||
|
|
||||||
### Unequip (Alternate)
|
**Alternate flows:** foreign character → 403; character/item not found → 404; item not in inventory → 400; nothing equipped in slot → 400.
|
||||||
|
|
||||||
1. Player submits a slot name; the system moves the equipped item back to inventory.
|
## UC-07 Trade at Shop
|
||||||
|
|
||||||
### Foreign character (Alternate)
|
|
||||||
|
|
||||||
1. Foreign character without admin role → 403.
|
|
||||||
|
|
||||||
### Not found (Alternate)
|
|
||||||
|
|
||||||
1. Character or item not found → 404.
|
|
||||||
|
|
||||||
### Item not in inventory (Alternate)
|
|
||||||
|
|
||||||
1. Equip target not in inventory → 400.
|
|
||||||
|
|
||||||
### Empty slot (Alternate)
|
|
||||||
|
|
||||||
1. Unequip on a slot with nothing equipped → 400.
|
|
||||||
|
|
||||||
## Post-conditions
|
|
||||||
|
|
||||||
- Item moved between inventory and equipment slot; character persisted.
|
|
||||||
|
|
||||||
## Special Requirements
|
|
||||||
|
|
||||||
- Rule failures flow through `DomainError` → central status mapping (CON-04).
|
|
||||||
|
|
||||||
# UC-07 Trade at Shop
|
|
||||||
|
|
||||||
## Brief Description
|
|
||||||
|
|
||||||
Buy from (always-stocked + rotating) shop stock or sell inventory items.
|
|
||||||
|
|
||||||
## Actor Brief Descriptions
|
|
||||||
|
|
||||||
| **Actor** | **Type** | **Description** |
|
|
||||||
| --- | --- | --- |
|
|
||||||
| Player | Primary | Authenticated user owning one or more characters (JWT role `player`). |
|
|
||||||
|
|
||||||
## Preconditions and Context
|
|
||||||
|
|
||||||
Precondition: character exists and caller may act on it.
|
|
||||||
|
|
||||||
## Basic Flow of Events (buy)
|
|
||||||
|
|
||||||
|
**Main success scenario (buy):**
|
||||||
1. Player views the shop: always-stocked items plus rotating stock (with quantities) alongside their inventory.
|
1. Player views the shop: always-stocked items plus rotating stock (with quantities) alongside their inventory.
|
||||||
2. Player submits `buy` + item id.
|
2. Player submits `buy` + item id.
|
||||||
3. System checks gold ≥ price (422), and for non-always-in-stock items decrements the limited stock (410 GONE if 0).
|
3. System checks gold ≥ price (422), and for non-always-in-stock items decrements the limited stock (410 GONE if 0).
|
||||||
4. System deducts gold, adds the item to inventory, persists character and stock; returns `{success, message, gold}`.
|
4. System deducts gold, adds the item to inventory, persists character and stock; returns `{success, message, gold}`.
|
||||||
|
|
||||||
## Alternative and Exception Flows
|
**Scenario (sell):** Player submits `sell` + item id; system removes the first matching inventory item, pays half the item value, increments shop stock for non-permanent items.
|
||||||
|
|
||||||
### Sell (Alternate)
|
**Alternate flows:** unknown action or item not owned (sell) → 400; item not found → 404; insufficient gold → 422; stock exhausted → 410.
|
||||||
|
|
||||||
1. Player submits `sell` + item id; system removes the first matching inventory item, pays half the item value, increments shop stock for non-permanent items.
|
## UC-08 Run Adventure
|
||||||
|
|
||||||
### Bad request (Alternate)
|
|
||||||
|
|
||||||
1. Unknown action, or sell of an item not owned → 400.
|
|
||||||
|
|
||||||
### Not found (Alternate)
|
|
||||||
|
|
||||||
1. Item not found → 404.
|
|
||||||
|
|
||||||
### Insufficient gold (Alternate)
|
|
||||||
|
|
||||||
1. Gold below price → 422.
|
|
||||||
|
|
||||||
### Stock exhausted (Alternate)
|
|
||||||
|
|
||||||
1. Limited stock at 0 → 410.
|
|
||||||
|
|
||||||
## Post-conditions
|
|
||||||
|
|
||||||
- Buy: gold deducted, item in inventory, stock decremented; Sell: item removed, half value paid, stock incremented; persisted.
|
|
||||||
|
|
||||||
## Special Requirements
|
|
||||||
|
|
||||||
- Shop business logic is handler-side recorded debt (Architecture Notebook D1, Q3).
|
|
||||||
|
|
||||||
# UC-08 Run Adventure
|
|
||||||
|
|
||||||
## Brief Description
|
|
||||||
|
|
||||||
Zone adventure with weighted enemy pick and turn-based combat. Includes Regenerate
|
|
||||||
Resources, Resolve Combat. Exception: encounter references an unknown enemy → 500 (post
|
|
||||||
WI-2; previously a panic). WI-2 design driver (`sb_core::adventure` extraction).
|
|
||||||
|
|
||||||
## Actor Brief Descriptions
|
|
||||||
|
|
||||||
| **Actor** | **Type** | **Description** |
|
|
||||||
| --- | --- | --- |
|
|
||||||
| Player | Primary | Authenticated user owning one or more characters (JWT role `player`). |
|
|
||||||
|
|
||||||
## Preconditions and Context
|
|
||||||
|
|
||||||
Precondition: character exists and caller may act on it.
|
|
||||||
|
|
||||||
## Basic Flow of Events
|
|
||||||
|
|
||||||
|
**Precondition:** character exists and caller may act on it. **Main success scenario:**
|
||||||
1. Player requests an adventure for a zone (default `skara_brae_streets`).
|
1. Player requests an adventure for a zone (default `skara_brae_streets`).
|
||||||
2. System validates the zone (404) and applies Regenerate Resources.
|
2. System validates the zone (404) and applies Regenerate Resources.
|
||||||
3. System refuses incapacitated characters (HP ≤ 0 → 400) and characters with nerve below the zone cost (422); otherwise deducts the nerve cost.
|
3. System refuses incapacitated characters (HP ≤ 0 → 400) and characters with nerve below the zone cost (422); otherwise deducts the nerve cost.
|
||||||
|
|
@ -403,232 +122,53 @@ Precondition: character exists and caller may act on it.
|
||||||
8. Spell-point upkeep is charged whenever a spell was active, win or lose.
|
8. Spell-point upkeep is charged whenever a spell was active, win or lose.
|
||||||
9. System persists the character and returns `{zone, enemy, combat_log, loot}` (loot = item display names).
|
9. System persists the character and returns `{zone, enemy, combat_log, loot}` (loot = item display names).
|
||||||
|
|
||||||
## Alternative and Exception Flows
|
**Alternate flows:** foreign character → 403; character/zone not found → 404; incapacitated → 400; insufficient nerve → 422. **Exception:** encounter references an unknown enemy (data error) → 500 (post WI-2; previously a panic).
|
||||||
|
|
||||||
### Foreign character (Alternate)
|
## UC-09 Heal at Temple
|
||||||
|
|
||||||
1. Foreign character without admin role → 403.
|
|
||||||
|
|
||||||
### Not found (Alternate)
|
|
||||||
|
|
||||||
1. Character or zone not found → 404.
|
|
||||||
|
|
||||||
### Incapacitated (Alternate)
|
|
||||||
|
|
||||||
1. HP ≤ 0 → 400.
|
|
||||||
|
|
||||||
### Insufficient nerve (Alternate)
|
|
||||||
|
|
||||||
1. Nerve below zone cost → 422.
|
|
||||||
|
|
||||||
### Unknown encounter enemy (Exception)
|
|
||||||
|
|
||||||
1. Encounter references an enemy id missing from the catalogue (data error) → 500 (post WI-2; previously a panic).
|
|
||||||
|
|
||||||
## Post-conditions
|
|
||||||
|
|
||||||
- Victory: rewards granted, loot added, HP set to last defender HP; defeat: HP 0, no rewards; spell upkeep charged if a spell was active; character persisted.
|
|
||||||
|
|
||||||
## Special Requirements
|
|
||||||
|
|
||||||
- Enemy draw and combat rolls use the injected rng (NFR-05, CON-03).
|
|
||||||
- Referential integrity violations surface as `DomainError::UnknownEncounterEnemy` → 500 (NFR-07).
|
|
||||||
- Crit damage caps by level gap; open-ended d100 (combat canon, `docs/game/`).
|
|
||||||
|
|
||||||
# UC-09 Heal at Temple
|
|
||||||
|
|
||||||
## Brief Description
|
|
||||||
|
|
||||||
Full or partial healing, cost = amount healed, minimum 1 gold.
|
|
||||||
|
|
||||||
## Actor Brief Descriptions
|
|
||||||
|
|
||||||
| **Actor** | **Type** | **Description** |
|
|
||||||
| --- | --- | --- |
|
|
||||||
| Player | Primary | Authenticated user owning one or more characters (JWT role `player`). |
|
|
||||||
|
|
||||||
## Preconditions and Context
|
|
||||||
|
|
||||||
Precondition: character exists, is injured, and caller may act on it.
|
|
||||||
|
|
||||||
## Basic Flow of Events
|
|
||||||
|
|
||||||
|
**Main success scenario:**
|
||||||
1. Player requests healing, optionally `partial`.
|
1. Player requests healing, optionally `partial`.
|
||||||
2. System computes missing HP; full heals all, partial heals half (rounded up); cost = amount healed, minimum 1 gold.
|
2. System computes missing HP; full heals all, partial heals half (rounded up); cost = amount healed, minimum 1 gold.
|
||||||
3. System checks gold (422), deducts it, restores HP, persists; returns `{hp, max_hp, gold, healed: true}`.
|
3. System checks gold (422), deducts it, restores HP, persists; returns `{hp, max_hp, gold, healed: true}`.
|
||||||
|
|
||||||
## Alternative and Exception Flows
|
**Alternate flows:** foreign character → 403; not found → 404; already at full HP → 400; insufficient gold → 422.
|
||||||
|
|
||||||
### Foreign character (Alternate)
|
## UC-10 Practice Bard Song
|
||||||
|
|
||||||
1. Foreign character without admin role → 403.
|
|
||||||
|
|
||||||
### Not found (Alternate)
|
|
||||||
|
|
||||||
1. Character not found → 404.
|
|
||||||
|
|
||||||
### Already at full HP (Alternate)
|
|
||||||
|
|
||||||
1. No missing HP → 400.
|
|
||||||
|
|
||||||
### Insufficient gold (Alternate)
|
|
||||||
|
|
||||||
1. Gold below heal cost → 422.
|
|
||||||
|
|
||||||
## Post-conditions
|
|
||||||
|
|
||||||
- HP restored, gold deducted, character persisted.
|
|
||||||
|
|
||||||
## Special Requirements
|
|
||||||
|
|
||||||
- Healing logic is handler-side recorded debt (Architecture Notebook D1, Q3).
|
|
||||||
|
|
||||||
# UC-10 Practice Bard Song
|
|
||||||
|
|
||||||
## Brief Description
|
|
||||||
|
|
||||||
Set or clear the active bard song (Bard only, level-gated).
|
|
||||||
|
|
||||||
## Actor Brief Descriptions
|
|
||||||
|
|
||||||
| **Actor** | **Type** | **Description** |
|
|
||||||
| --- | --- | --- |
|
|
||||||
| Player | Primary | Authenticated user owning one or more characters (JWT role `player`). |
|
|
||||||
|
|
||||||
## Preconditions and Context
|
|
||||||
|
|
||||||
Precondition: character class is Bard.
|
|
||||||
|
|
||||||
## Basic Flow of Events
|
|
||||||
|
|
||||||
|
**Precondition:** character class is Bard. **Main success scenario:**
|
||||||
1. Player views available songs (level-gated, with combat effect descriptions) and the active song.
|
1. Player views available songs (level-gated, with combat effect descriptions) and the active song.
|
||||||
2. Player submits a song id; system validates level requirement (422) and sets it active; returns `{success, message, active_song}`.
|
2. Player submits a song id; system validates level requirement (422) and sets it active; returns `{success, message, active_song}`.
|
||||||
|
|
||||||
## Alternative and Exception Flows
|
**Scenario (clear):** submitting no song id clears the active song. **Alternate flows:** non-Bard → 403; unknown song → 404; level too low → 422; foreign character → 403; not found → 404.
|
||||||
|
|
||||||
### Clear (Alternate)
|
## UC-11 Study Magic
|
||||||
|
|
||||||
1. Submitting no song id clears the active song.
|
**Precondition:** character belongs to a caster class (Mage→magician, Wizard, Conjurer, Sorcerer). Spell level = (character level / 3) + 1 — **uncapped by code** (level 100 → spell level 34); learn *requests* are validated to 1–7, and the practical ceiling is emergent from the data (spells are defined only through level 7, so higher computed levels surface no new spells).
|
||||||
|
|
||||||
### Non-Bard (Alternate)
|
|
||||||
|
|
||||||
1. Character class is not Bard → 403.
|
|
||||||
|
|
||||||
### Unknown song (Alternate)
|
|
||||||
|
|
||||||
1. Unknown song id → 404.
|
|
||||||
|
|
||||||
### Level too low (Alternate)
|
|
||||||
|
|
||||||
1. Character level below the song requirement → 422.
|
|
||||||
|
|
||||||
### Foreign character / not found (Alternate)
|
|
||||||
|
|
||||||
1. Foreign character → 403; character not found → 404.
|
|
||||||
|
|
||||||
## Post-conditions
|
|
||||||
|
|
||||||
- Active song set or cleared; character persisted.
|
|
||||||
|
|
||||||
## Special Requirements
|
|
||||||
|
|
||||||
- Song effects apply in UC-08 combat (step 5).
|
|
||||||
|
|
||||||
# UC-11 Study Magic
|
|
||||||
|
|
||||||
## Brief Description
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
## Actor Brief Descriptions
|
|
||||||
|
|
||||||
| **Actor** | **Type** | **Description** |
|
|
||||||
| --- | --- | --- |
|
|
||||||
| Player | Primary | Authenticated user owning one or more characters (JWT role `player`). |
|
|
||||||
|
|
||||||
## Preconditions and Context
|
|
||||||
|
|
||||||
Precondition: character belongs to a caster class (Mage→magician, Wizard, Conjurer,
|
|
||||||
Sorcerer). Spell level = (character level / 3) + 1 — uncapped by code (level 100 → spell
|
|
||||||
level 34); learn requests are validated to 1–7.
|
|
||||||
|
|
||||||
## Basic Flow of Events (view spellbook)
|
|
||||||
|
|
||||||
|
**Scenario (view spellbook):**
|
||||||
1. 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.
|
1. 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.
|
||||||
|
|
||||||
## Alternative and Exception Flows
|
**Scenario (learn spell level):**
|
||||||
|
|
||||||
### Learn spell level (Alternate)
|
|
||||||
|
|
||||||
1. Player submits a spell level (1–7).
|
1. Player submits a spell level (1–7).
|
||||||
2. System validates caster class (403), level range (400), level not above the character's current spell level (422), gold ≥ learn cost (422), and that new spells exist (400).
|
2. System validates caster class (403), level range (400), level not above the character's current spell level (422), gold ≥ learn cost (422), and that new spells exist (400).
|
||||||
3. 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}`.
|
3. 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}`.
|
||||||
|
|
||||||
### Activate / clear active spell (Alternate)
|
**Scenario (activate/clear active spell):**
|
||||||
|
|
||||||
1. Player submits a spell id (or empty to clear).
|
1. Player submits a spell id (or empty to clear).
|
||||||
2. System validates the spell is known (403), exists (404), and spell points suffice (422); deducts the spell's points and sets it active; returns `{active_spell, spell_points}`.
|
2. System validates the spell is known (403), exists (404), and spell points suffice (422); deducts the spell's points and sets it active; returns `{active_spell, spell_points}`.
|
||||||
|
|
||||||
## Post-conditions
|
## UC-12 Level Up at Review Board
|
||||||
|
|
||||||
- (learn) spells of the level known, gold deducted, max spell points recomputed and refilled; (activate) active spell set, spell points deducted; persisted.
|
|
||||||
|
|
||||||
## Special Requirements
|
|
||||||
|
|
||||||
- Active spell deals damage/heals per round and charges upkeep in UC-08 combat (steps 5, 8).
|
|
||||||
- Parts of spell logic are handler-side recorded debt (Architecture Notebook D1, Q3).
|
|
||||||
|
|
||||||
# UC-12 Level Up at Review Board
|
|
||||||
|
|
||||||
## Brief Description
|
|
||||||
|
|
||||||
Manual level-up: XP threshold + gold cost (500 per next level), full resource restore on
|
|
||||||
level-up.
|
|
||||||
|
|
||||||
## Actor Brief Descriptions
|
|
||||||
|
|
||||||
| **Actor** | **Type** | **Description** |
|
|
||||||
| --- | --- | --- |
|
|
||||||
| Player | Primary | Authenticated user owning one or more characters (JWT role `player`). |
|
|
||||||
|
|
||||||
## Preconditions and Context
|
|
||||||
|
|
||||||
Precondition: character exists and caller may act on it.
|
|
||||||
|
|
||||||
## Basic Flow of Events
|
|
||||||
|
|
||||||
|
**Main success scenario:**
|
||||||
1. Player requests a level-up.
|
1. Player requests a level-up.
|
||||||
2. System validates: below max level 100, XP ≥ 18·100·(level)² for the next level (i.e. `xp_for_level(next)`), gold ≥ 500·next level.
|
2. System validates: below max level 100, XP ≥ 18·100·(level)² for the next level (i.e. `xp_for_level(next)`), gold ≥ 500·next level.
|
||||||
3. System deducts the gold cost, increments the level, recomputes and fully restores HP/energy/nerve and max spell points; persists; returns `{success, message, character}`.
|
3. System deducts the gold cost, increments the level, recomputes and fully restores HP/energy/nerve and max spell points; persists; returns `{success, message, character}`.
|
||||||
|
|
||||||
## Alternative and Exception Flows
|
**Alternate flows (all 422):** already at max level; not enough XP; not enough gold. Foreign character → 403; not found → 404.
|
||||||
|
|
||||||
### Level-up rejected (Alternate)
|
|
||||||
|
|
||||||
1. Already at max level, not enough XP, or not enough gold → 422.
|
|
||||||
|
|
||||||
### Foreign character (Alternate)
|
|
||||||
|
|
||||||
1. Foreign character without admin role → 403.
|
|
||||||
|
|
||||||
### Not found (Alternate)
|
|
||||||
|
|
||||||
1. Character not found → 404.
|
|
||||||
|
|
||||||
## Post-conditions
|
|
||||||
|
|
||||||
- Level +1, gold deducted, all resources fully restored and maxima recomputed; character persisted.
|
|
||||||
|
|
||||||
## Special Requirements
|
|
||||||
|
|
||||||
- Level-up rule failures flow through `DomainError` → central status mapping (CON-04).
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
# Traceability Notes
|
## Traceability Notes
|
||||||
|
|
||||||
- UC-08 is the design driver for WI-2's service extraction (`sb_core::adventure`); its status mapping feeds `DomainError` (see `analysis-design/design-wi-2-architecture-cleanup.md` §4.1–4.2).
|
- UC-08 is the design driver for WI-2's service extraction (`sb_core::adventure`); its status mapping feeds `DomainError` (see `analysis-design/design-wi-2-architecture-cleanup.md` §4.1–4.2).
|
||||||
- Catalogue data backing UC-04 lives in `skara-brae-common/data/` (items, enemies, zones, spells, crit tables).
|
- Catalogue data backing UC-04 lives in `skara-brae-common/data/` (items, enemies, zones, spells, crit tables).
|
||||||
- Analysis realizations for all twelve use cases: `analysis-design/uc-realization-mapping.md` §2 + EA model; design sequences: `analysis-design/sequences/`.
|
|
||||||
- Requirement traceability: `supplementary-specifications.md` coverage matrix.
|
|
||||||
|
|
|
||||||
|
|
@ -1,84 +1,41 @@
|
||||||
# Skara Brae — Vision
|
# Skara Brae — Vision
|
||||||
|
|
||||||
`Skara Brae` — OpenUP Requirements · Vision · version 2.0 (2026-10-05, restructured to the
|
Version 1.0 (WI-2, 2026-10-03) · OpenUP artifact: `requirements/vision.md` · Canonical home: **skara-brae-common repo**, `docs/openup/` (decision reversed 2026-10-03; drafts move verbatim from skara-brae-server/docs/)
|
||||||
OpenUP vision template; content unchanged in substance from version 1.0, WI-2).
|
|
||||||
Canonical home: **skara-brae-common repo**, `docs/openup/` (decision 2026-10-03).
|
|
||||||
|
|
||||||
## 1. Introduction
|
## Problem / Opportunity
|
||||||
|
|
||||||
This Vision describes Skara Brae, a text-based browser MMORPG built as a modern
|
Text-based browser MMORPGs have proven retention and monetization for two decades (Torn City, since 2004), but incumbents carry 2000s-era engines. There is room for a modern, API-first, type-safe implementation of the formula: deep numeric progression, player-driven economy, idle-friendly pacing, real-time feedback.
|
||||||
re-implementation of a proven formula. The document is maintained alongside an
|
|
||||||
implemented, growing system: the server MVP (accounts, characters, training, adventures,
|
|
||||||
economy, magic, progression) is live at `main` with the OpenUP artifact set generated from
|
|
||||||
it; later-phase features are committed in intent but not built.
|
|
||||||
|
|
||||||
The product comprises three repositories: `skara-brae-server` (Rust/Axum backend),
|
## Product Vision
|
||||||
`skara-brae-client` (Vue 3 SPA) and `skara-brae-common` (bilingual game-data package and
|
|
||||||
OpenUP artifact home). In the tables below, R1 denotes the delivered server MVP and R2 the
|
|
||||||
later-phase features (not yet committed to dates).
|
|
||||||
|
|
||||||
References: game design canon in `docs/game/`, OpenUP artifact set in `docs/openup/`,
|
**Skara Brae** is a fantasy text-based/idle MMORPG set in an ancient, labyrinthine city of stone and sorcery (The Bard's Tale I inspiration, dark-fantasy tone). It transplants **Torn City's proven loop** — energy-gated activities, training, economy, social systems — into that setting, adds **idle-RPG elements** (offline progression, hireable workers, pets; Idle Fantasy inspiration), and grounds combat in a **RoleMaster-inspired critical-hit system** (open-ended d100, crit tables with bleed/stun effects, level-gap damage caps).
|
||||||
EA model in `docs/openup/model/skara-brae.eapx`.
|
|
||||||
|
|
||||||
## 2. Positioning
|
**Tagline:** *Set your hero to work. Close the app. Come back to loot.*
|
||||||
|
|
||||||
### 2.1 Problem Statement
|
## Stakeholders
|
||||||
|
|
||||||
| | |
|
- **Owner/developer (solo)** — builds and operates the game on self-hosted infrastructure (Forgejo/Jenkins pipeline).
|
||||||
| --- | --- |
|
- **Players** — web/PWA users; the API-first contract also serves future community tools.
|
||||||
| The problem of | 2000s-era engines under proven text-based browser MMORPGs |
|
|
||||||
| affects | players of the genre (retention-heavy games with dated UX and closed stacks) and a solo developer wanting a type-safe, API-first base for community tooling |
|
|
||||||
| the impact of which is | incumbents carry legacy engines; no modern reference implementation exists for the formula with real-time feedback, idle-friendly pacing and an open API |
|
|
||||||
| a successful solution would be | a 2026-era, type-safe full-stack implementation: instant feedback, mobile-first PWA, API-first design, offline-friendly idle progression, self-hostable by one operator |
|
|
||||||
|
|
||||||
### 2.2 Product Position Statement
|
## Key Features (committed MVP scope, Phase 1)
|
||||||
|
|
||||||
| For | players of deep, numeric-progression browser games and the solo operator building for them |
|
1. Accounts (register/login, JWT) and character creation (5 races, 10 classes).
|
||||||
| --- | --- |
|
2. Stat training with escalating gold costs; energy/nerve/HP resources with lazy timed regeneration.
|
||||||
| Who | need a modern, maintainable instance of the proven Torn-style loop |
|
3. Adventures (energy/nerve-gated zone runs) with turn-based combat, crit tables, XP/gold/loot.
|
||||||
| Skara Brae | is a fantasy text-based/idle MMORPG set in an ancient city of stone and sorcery (The Bard's Tale I inspiration, dark-fantasy tone) |
|
4. Economy: shop (buy/sell, stock), equipment slots, inventory.
|
||||||
| That | transplants the proven loop — energy-gated activities, training, economy — into that setting, adds idle-RPG elements (offline progression, hireable workers, pets) and grounds combat in a RoleMaster-inspired crit system |
|
5. Magic (class-gated spell levels, spell points) and bard songs (combat buffs).
|
||||||
| Unlike | incumbent PHP-era engines with closed APIs |
|
6. Level-up review board; temple healing.
|
||||||
| Our product | ships a Rust/Axum REST API, a Vue 3 PWA client, language-neutral game data, and a self-hosted Forgejo/Jenkins pipeline — with the tagline: *Set your hero to work. Close the app. Come back to loot.* |
|
7. REST API (Rust/Axum) + Vue 3 client; WebSocket notifications.
|
||||||
|
|
||||||
## 3. Stakeholder Descriptions
|
Later phases (not committed): PvP, guilds, properties, crafting, pets, blessings, offline workers, tower endgame.
|
||||||
|
|
||||||
### 3.1 Stakeholder Summary
|
## Constraints & Quality Bars
|
||||||
|
|
||||||
| **Name** | **Description** | **Responsibilities** |
|
- Behavior continuity: refactors must be wire-format and game-semantics identical (WI-2 governs).
|
||||||
| --- | --- | --- |
|
- Quality gates: `cargo fmt --check`, `cargo clippy --all-targets -- -D warnings`, full test suite — zero-warning policy.
|
||||||
| Owner/developer (solo) | Builds and operates the game on self-hosted infrastructure | Scope, releases, quality gate, external hosting (Forgejo/Jenkins pipeline) |
|
- Game data lives in the shared `skara-brae-common` repo as language-neutral JSON (single source of truth for server, client, and a future generated wiki).
|
||||||
| Players | Web/PWA users; the API-first contract also serves future community tools | Play; consume the public API within its contract |
|
- BIGINT (`i64`) stat growth; stats only ever go up.
|
||||||
|
|
||||||
### 3.2 User Environment
|
## Success Criteria (current iteration)
|
||||||
|
|
||||||
Players use a browser or installed PWA against the hosted Vue 3 SPA; the client polls the
|
WI-1 delivered injectable RNG (deterministic domain tests). This iteration (WI-2) delivers an architecture cleanup that makes the codebase safe to grow on: typed responses, domain-extracted adventure service, named game-balance constants, one domain error taxonomy, fmt baseline — with all 45 existing tests green and zero behavior change. Longer term: a playable MVP per the feature list above.
|
||||||
REST API (assumed refresh cadence ~15 s; server behavior is poll-frequency-independent by
|
|
||||||
design). The operator runs a single Rust process per deployment (systemd), with optional
|
|
||||||
write-through SQLite persistence, behind Caddy TLS; game state otherwise lives in memory.
|
|
||||||
All game content ships compiled-in from `skara-brae-common` JSON — no external data
|
|
||||||
services for R1.
|
|
||||||
|
|
||||||
## 4. Product Overview
|
|
||||||
|
|
||||||
### 4.1 Needs and Features
|
|
||||||
|
|
||||||
| **Need** | **Priority** | **Features** | **Planned Release** |
|
|
||||||
| --- | --- | --- | --- |
|
|
||||||
| Progress a character | High | Accounts (register/login, JWT), character creation (5 races, 10 classes), stat training with escalating gold costs, level-up review board | R1 |
|
|
||||||
| Adventure and fight | High | Energy/nerve-gated zone adventures, turn-based combat with open-ended d100 rolls and RoleMaster crit tables, XP/gold/loot | R1 |
|
|
||||||
| Run an economy | High | Shop (buy/sell, rotating stock), equipment slots, inventory | R1 |
|
|
||||||
| Wield magic and song | High | Class-gated spell levels with spell points, bard songs with combat effects | R1 |
|
|
||||||
| Regenerate over time | High | Energy/nerve/HP resources with lazy timed regeneration; temple healing | R1 |
|
|
||||||
| Consume the game programmatically | High | REST JSON API (Rust/Axum), Vue 3 client; WebSocket notifications | R1 (WS: later R1+) |
|
|
||||||
| Play idly | Medium | Offline progression, hireable workers, pets; further endgame (tower, guilds, properties, crafting, blessings, PvP) | R2 |
|
|
||||||
|
|
||||||
## 5. Other Product Requirements
|
|
||||||
|
|
||||||
| **Requirement** | **Priority** | **Planned Release** |
|
|
||||||
| --- | --- | --- |
|
|
||||||
| Behavior continuity: refactors must be wire-format and game-semantics identical | High | R1 (standing) |
|
|
||||||
| Quality gates: `cargo fmt --check`, `cargo clippy --all-targets -- -D warnings`, full test suite — zero-warning policy | High | R1 (standing) |
|
|
||||||
| Game data lives in the shared `skara-brae-common` repo as language-neutral JSON (single source of truth for server, client and future generated wiki) | High | R1 |
|
|
||||||
| BIGINT (`i64`) stat growth; stats only ever go up | High | R1 |
|
|
||||||
| Self-hosted pipeline: Forgejo (git), Jenkins CI, systemd + Caddy deployment | Medium | R1 |
|
|
||||||
|
|
|
||||||
|
|
@ -1,107 +0,0 @@
|
||||||
# Quality Check Procedure
|
|
||||||
|
|
||||||
`Skara Brae` — OpenUP Test · migrated 2026-10-05 from the Joplin note of the same name
|
|
||||||
(markdown is the single content home; Joplin keeps status only). Post-migration update:
|
|
||||||
the three unchecked items below were resolved — `rand::rng()` direct use by WI-1
|
|
||||||
(single construction point `request_rng()`), handler-side business logic by WI-2
|
|
||||||
(`run_adventure` extraction) and constants by WI-2 (`sb-core::constants`).
|
|
||||||
|
|
||||||
## Purpose
|
|
||||||
|
|
||||||
Systematic verification that the implementation matches design notes, passes all code
|
|
||||||
checks, and follows Clean Code / Clean Architecture principles.
|
|
||||||
|
|
||||||
## Procedure
|
|
||||||
|
|
||||||
### Step 1: Code Checks
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Rust build + clippy
|
|
||||||
cd ~/Development/skara-brae/skara-brae-server && cargo clippy -- -W clippy::all 2>&1
|
|
||||||
|
|
||||||
# Rust tests
|
|
||||||
cd ~/Development/skara-brae/skara-brae-server && cargo test 2>&1
|
|
||||||
|
|
||||||
# Vue typecheck
|
|
||||||
cd ~/Development/skara-brae/skara-brae-client && npx vue-tsc --noEmit 2>&1
|
|
||||||
```
|
|
||||||
|
|
||||||
### Step 2: Implementation vs Design Notes
|
|
||||||
|
|
||||||
For each design note, verify the implementation matches:
|
|
||||||
|
|
||||||
| Note (docs/) | What to Check |
|
|
||||||
|---|---|
|
|
||||||
| `docs/game/game-concept-overview.md` | Character system (races, classes, stats), economy model, adventure structure |
|
|
||||||
| `docs/game/combat-system-stat-scaling-design.md` | BIGINT stats, open-ended d100, crit tables, crit caps by level diff |
|
|
||||||
| `docs/game/mechanics-source-mapping.md` | BT1/RM/IF/Torn mapping consistency |
|
|
||||||
| `docs/game/tech-stack-architecture.md` | Crate structure, dependency direction, deployment |
|
|
||||||
| `docs/game/skill-magic-system.md` | Spell system design vs implementation |
|
|
||||||
| `docs/game/medals-honours-system.md` | Medal system (not yet implemented) |
|
|
||||||
| `docs/game/idle-fantasy-inspirations.md` | Features adopted from IF |
|
|
||||||
| `docs/openup/analysis-design/architecture-notebook.md` | Layers, dependency rule, key abstractions |
|
|
||||||
|
|
||||||
Check items:
|
|
||||||
- [x] Stats are i64 (BIGINT) — not i32
|
|
||||||
- [x] 5 races match design (Human, Elf, Dwarf, Hobbit, HalfElf)
|
|
||||||
- [x] 10 classes match design (Warrior through Sorcerer, no Cleric)
|
|
||||||
- [x] Crit damage cap by level difference implemented
|
|
||||||
- [x] Open-ended d100 combat rolls
|
|
||||||
- [x] BT1 items (127), enemies (125), spells (79), songs (6) all present
|
|
||||||
- [x] Zones match BT1 dungeon structure (8 zones)
|
|
||||||
- [x] Shop economy uses BT1 gold values
|
|
||||||
- [x] Bard songs with combat integration
|
|
||||||
- [x] Spell system with SP costs, learning, combat casting
|
|
||||||
- [x] Training costs gold (not just energy)
|
|
||||||
- [x] Review Board level-up: XP threshold polynomial (18×100×(level-1)²), gold cost, max level 100
|
|
||||||
|
|
||||||
### Step 3: Clean Architecture Audit
|
|
||||||
|
|
||||||
Check dependency direction:
|
|
||||||
- [x] `sb-shared` → no dependencies on other game crates (domain types only)
|
|
||||||
- [x] `sb-core` → depends only on `sb-shared` + `sb-common` (domain services, no HTTP)
|
|
||||||
- [x] `sb-api` → depends on `sb-core`, `sb-shared`, `sb-auth`, `sb-db` (HTTP adapters)
|
|
||||||
|
|
||||||
Check layer violations:
|
|
||||||
- [x] No `serde_json` in domain logic (only in LazyLock data loaders)
|
|
||||||
- [x] No `include_str!` called during business logic (only module-level const)
|
|
||||||
- [x] No `rand::rng()` in domain functions — resolved by WI-1: single construction point
|
|
||||||
`request_rng()`, domain takes injected rng
|
|
||||||
- [x] Route handlers delegate to domain services — resolved by WI-2 for adventure;
|
|
||||||
remaining handler-side logic (shop, heal, parts of spells) is recorded debt
|
|
||||||
(Architecture Notebook D1, follow-up question Q3)
|
|
||||||
|
|
||||||
Check code quality:
|
|
||||||
- [x] No magic numbers — resolved by WI-2: `sb-core::constants` is the audit home
|
|
||||||
- [x] No abbreviations in variable names
|
|
||||||
- [x] Functions do one thing, are short
|
|
||||||
- [x] No duplicated logic across modules
|
|
||||||
- [x] No comments that restate code
|
|
||||||
- [x] Fail fast, return early — happy path flat
|
|
||||||
- [x] No mixed concerns (HTTP + business logic in same function)
|
|
||||||
|
|
||||||
### Step 4: Bug Scan
|
|
||||||
|
|
||||||
- [x] All gold/energy/nerve/SP costs are both displayed AND enforced
|
|
||||||
- [x] All state mutations happen inside write locks
|
|
||||||
- [x] No unwrap() on fallible operations in request paths — WI-2 §6 ledger classifies
|
|
||||||
the remaining ones as documented keep-with-reason invariants
|
|
||||||
- [x] All enum match arms exhaustive
|
|
||||||
- [x] No integer overflow paths (xp_for_level uses saturating arithmetic)
|
|
||||||
|
|
||||||
## Audit History
|
|
||||||
|
|
||||||
| Date | Clippy | Tests | vue-tsc | Criticals Found | Criticals Fixed |
|
|
||||||
|---|---|---|---|---|---|
|
|
||||||
| 2026-08-03 #1 | 18 warnings | 0 tests | clean | 3 | 3 |
|
|
||||||
| 2026-08-03 #2 | 0 | 42 pass | clean | 4 | 4 |
|
|
||||||
| 2026-08-03 #3 | 0 | 44 pass | clean | 1 | 1 |
|
|
||||||
|
|
||||||
## Quality Gate
|
|
||||||
|
|
||||||
A check passes when:
|
|
||||||
- Zero clippy warnings (excluding allowed lints)
|
|
||||||
- Zero typecheck errors
|
|
||||||
- All tests pass
|
|
||||||
- Zero critical architecture violations
|
|
||||||
- All tracked inconsistencies have a ticket or accepted rationale
|
|
||||||