All OpenUP artifacts are versioned in skara-brae-common under docs/openup/ per the 2026-10-03 decision reversal in design-wi-2-architecture-cleanup.md (supersedes the earlier in-server-docs decision). Verbatim move, no content changes: analysis-design/, requirements/, test/ (6 files).
80 lines
9.1 KiB
Markdown
80 lines
9.1 KiB
Markdown
# Skara Brae — Analysis & Design Model (text form)
|
||
|
||
Version 1.0 (WI-2, 2026-10-03) · OpenUP artifact: `analysis-design/uc-realization-mapping.md`
|
||
This is the **content the EA model will carry** once the modeling pipeline exists. The EA repository itself (`.eapx`, keyfob-station style) is planned for a later work item — EA is a human-gated interactive tool; this document is the authoritative source any future EA builder script generates from.
|
||
|
||
## 1. Model structure (planned EA packages)
|
||
|
||
```
|
||
Model: Skara Brae
|
||
├── Requirements
|
||
│ ├── Vision (from requirements/vision.md)
|
||
│ ├── Use Case Model
|
||
│ │ ├── Actors: Player, Administrator, Guest
|
||
│ │ └── Use Cases UC-01 … UC-12 (from requirements/use-case-model.md;
|
||
│ │ scenarios as Basic Path / Alternate / Exception with per-step Actor)
|
||
│ └── Supplementary Specifications (from requirements/supplementary-specifications.md)
|
||
└── Analysis-Design
|
||
├── Architecture Overview (crate/layer diagram, dependency rule)
|
||
└── UC-01 Realization … UC-12 Realization (one package per UC: analysis classes,
|
||
design elements, realization table below)
|
||
```
|
||
|
||
## 2. UC realization mapping (analysis classes → design elements)
|
||
|
||
Legend — **Analysis class** (OpenUP stereotype): `«controller»`, `«entity»`, `«boundary»`. **Design element**: crate::module::item (Rust). "WI-2" marks elements introduced or re-homed by this work item; everything else exists at 899fde8.
|
||
|
||
| UC | Analysis class | Stereotype | Design element | Notes |
|
||
|---|---|---|---|---|
|
||
| UC-01 Register | AccountRegistry | controller | `sb-api::routes::{register, seed_users}` | argon2 hash via `sb-auth::hash`; JWT via `sb-auth::jwt` |
|
||
| | UserAccount | entity | `sb-shared::user::User`, `Role` | persisted via `sb-db::Database` |
|
||
| | AuthBoundary | boundary | `POST /api/auth/register`, `AuthResponse` | |
|
||
| UC-02 Authenticate | Authenticator | controller | `sb-api::routes::login`, `sb-auth::{hash::verify_password, jwt::create_token}` | |
|
||
| | TokenService | boundary | `POST /api/auth/login`, `AuthResponse`, `middleware::auth::auth_middleware` | middleware guards all UC-03…12 |
|
||
| UC-03 Manage Characters | CharacterFactory | controller | `sb-core::character::create_character` | takes injected rng (WI-1) |
|
||
| | Character | entity | `sb-shared::character::Character` (+ `Race`, `Class`, `CharacterStats`) | |
|
||
| | CharacterCatalog | boundary | `GET/POST /api/users/{id}/characters`, `GET /api/characters/{id}` | store: `AppState.characters` |
|
||
| | ResourceRegenerator | entity | `sb-core::character::apply_regen` (+ regen constants — WI-2 names them) | included sub-flow |
|
||
| UC-04 Browse Catalogue | CatalogueBrowser | boundary | `GET /api/{races,classes,items,enemies,adventures}`; response types `sb-shared::responses` | data from `sb-common` JSON via `sb-core::{character::RACES/CLASSES, data, items}` |
|
||
| | GameData | entity | `sb-core::data::{EnemyDef, ZoneDef, EncounterEntry, LootDrop}`, `items::load_all_items` | |
|
||
| UC-05 Train Stat | TrainingService | controller | `sb-core::services::train_stat` | error type `DomainError` (WI-2) |
|
||
| | TrainingGrounds | entity | `sb-core::character::TRAINING_GROUNDS`, `training_cost` (+ cost constants WI-2) | |
|
||
| | GymBoundary | boundary | `GET/POST /api/characters/{id}/gym`, `GymResponse`, `TrainStatResponse` | |
|
||
| UC-06 Manage Equipment | EquipmentService | controller | `sb-core::services::{equip_item, unequip_item}` | `DomainError` (WI-2) |
|
||
| | Equipment/Inventory | entity | `Character.equipment` / `.inventory`, `sb-shared::item::Item` | |
|
||
| | EquipmentBoundary | boundary | `POST /api/characters/{id}/{equip,unequip}` | |
|
||
| UC-07 Trade at Shop | ShopService | controller | `sb-api::routes::{shop_action, buy_item, sell_item}` (handler-side; extraction candidate, design note Q3) | prices: `sb-core::items::{item_price, item_sell_price}` |
|
||
| | ShopStock | entity | `AppState.shop_stock` | persisted via `sb-db` |
|
||
| | ShopBoundary | boundary | `GET/POST /api/characters/{id}/shop`, `ShopResponse`, `ShopActionResponse` | |
|
||
| UC-08 Run Adventure | **AdventureService** | controller | `sb-core::adventure::run_adventure` (**new, WI-2**) + `services::pick_enemy` → `Result` (WI-2) | takes injected rng; `DomainError` (WI-2) |
|
||
| | CombatEngine | entity | `sb-core::combat::{resolve_combat_full, resolve_attack, crit tables, open_ended_roll}` + combat constants (WI-2) | |
|
||
| | Combatant | entity | `sb-core::combat::CombatStats` | built from Character/EnemyDef |
|
||
| | SpellEffect / BardSong | entity | `sb-core::combat::SpellEffect`, `sb-core::spells`, `sb-core::songs` | |
|
||
| | AdventureBoundary | boundary | `GET /api/characters/{id}/adventure`; `AdventureRunResponse` (**new, WI-2**), `sb-shared::responses::CombatLog` | |
|
||
| UC-09 Heal at Temple | HealingService | controller | `sb-api::routes::heal_character` (handler-side; extraction candidate, Q3) | |
|
||
| | TempleBoundary | boundary | `POST /api/characters/{id}/heal`; `HealResponse` (**new, WI-2**) | |
|
||
| UC-10 Practice Bard Song | SongService | controller | `sb-api::routes::set_song`; `sb-core::songs::available_songs` | |
|
||
| | BardSong | entity | `sb-core::songs::BARD_SONGS`, `Character.active_song` | |
|
||
| | SongBoundary | boundary | `GET/POST /api/characters/{id}/songs`, `SongsResponse`, `SetSongResponse` | |
|
||
| UC-11 Study Magic | MagicService | controller | `sb-api::routes::{get_spells, learn_spell_level}`; `sb-core::spells::{spells_for_class, spell_learn_cost, max_spell_points, caster_spell_level (WI-2)}` | |
|
||
| | Spell | entity | `sb-core::spells::SpellDef`, `Character.{known_spells, active_spell, spell_points}` | |
|
||
| | MagicBoundary | boundary | `GET/POST /api/characters/{id}/spells`; `SpellbookResponse`, `LearnSpellResponse` (**new, WI-2**) | |
|
||
| UC-12 Level Up | ReviewBoard | controller | `sb-core::character::level_up` | `DomainError` (WI-2) |
|
||
| | Progression | entity | `sb-core::character::{xp_for_level, level_up_cost, MAX_LEVEL}` (+ curve constants WI-2) | |
|
||
| | ReviewBoundary | boundary | `POST /api/characters/{id}/level-up`, `LevelUpResponse` | |
|
||
|
||
Cross-cutting design elements (WI-2): `sb-core::error::DomainError` + `sb-api::routes::domain_status` (status mapping table, design note §4.1) realize the error paths of UC-05/06/08/12; `sb-core::constants` realizes NFR "no magic numbers"; `sb-api::routes::responses` realizes NFR-19 (wire-format freeze).
|
||
|
||
Dependency rule check (Clean Architecture): all controllers/entities above live in `sb-core`/`sb-shared` (domain side, no HTTP imports); all boundaries live in `sb-api`; the single current violations (ShopService, HealingService, parts of MagicService in sb-api) are recorded as debt with a follow-up question — the model must not paper over them (stale docs are defects).
|
||
|
||
## 3. Research summary — keyfob-station EA pipeline (reference)
|
||
|
||
Source: read-only clone `http://192.168.1.10:3000/jan/keyfob-station.git` (inspected 2026-10-03; no modifications).
|
||
|
||
- **Model file:** `docs/openup/model/keyfob-station.eapx` (MS Access database — the EA native format; EABase-derived). Never hand-edited.
|
||
- **Structure:** Model → `Requirements` package → `Use Case Model` package containing `Actor` and `UseCase` elements; scenario lists are stored on each use case as named scenarios of type **Basic Path / Alternate / Exception**, each with ordered steps carrying a per-step **Actor** tag and notes. An `Analysis-Design` package holds **one `UC-N Realization` package per use case** (realization diagrams + design elements).
|
||
- **Builders are surgical scripts:** `scripts/add-*.ps1` (PowerShell driving the EA COM object `New-Object -ComObject EA.App`, `$repo.OpenFile($modelPath)`). Each script opens the model, adds/rebuilds exactly one package's contents, and closes it — because EA repository IDs and package rebuilds clobber manual edits, hand edits do not survive; all content lives in the scripts (scenario text is embedded as PowerShell arrays of `Name/Type/Notes/Steps`). This matches our standards note: *model additions are surgical; builders rebuild whole packages*.
|
||
- **Exports:** `scripts/export-model-json.ps1` walks the Use Case Model package and emits `exports/use-case-model.json` + `supplementary-requirements.json`; realization diagrams are exported to PDF/PNG into `docs/openup/analysis-design/`. The JSON export is the doc-machine readable form of the same content.
|
||
- **Windows-only:** the pipeline runs on Windows (EA is a Win32 app; scripts use `.ps1` + COM). For Skara Brae, the same pattern applies when the modeling WI lands: keep `docs/openup/*.md` (this file set) as the source the builder scripts embed, never the reverse.
|
||
|
||
Adoption decision for Skara Brae (updated at 1B rework): the EA model + generator pipeline is **in WI-2 scope**. This document (§1–2) plus `requirements/use-case-model.md` are the content source; the model-home recommendation, agent preparation steps, generator scripts (`scripts/openup/build-model.ps1`, `export-model.ps1`), and the human-gate checklist are specified in `design-wi-2-architecture-cleanup.md` §11. The `.eapx` interactive editing session remains human-gated; everything around it is COD-phase agent work.
|