openup: EA model preparation (COD) - checklist, scripts, realizations intermediate
Per design-wi-2-architecture-cleanup.md §11.b/c: keyfob-station pipeline studied (add-wi19-uc11.ps1, export-model-json.ps1). Platform gap: EA COM pipeline is Windows-only; this session ran on Linux (no EABase.eapx found, no pwsh) - .eapx skeleton NOT committed, documented in model/README.md with the two path options. Landed: - docs/openup/model/BUILD-CHECKLIST.md: full EA-session checklist (packages, 3 actors, 12 UCs with scenarios, 13 associations, 12 realization packages / 36 elements) derived from use-case-model.md + uc-realization-mapping.md - docs/openup/model/README.md: platform note, status, drift rule - docs/openup/model/exports/uc-realizations.json: generated from mapping §2 via scripts/openup/markdown-to-json.py (tested locally) - scripts/openup/build-model.ps1, export-model.ps1: adapted from keyfob patterns, Windows-gated (human gate per design §11.d) - scripts/openup/markdown-to-json.py: local markdown -> JSON transform
This commit is contained in:
parent
7a9a5a3e7b
commit
41f1ec2887
6 changed files with 1311 additions and 0 deletions
295
docs/openup/model/exports/uc-realizations.json
Normal file
295
docs/openup/model/exports/uc-realizations.json
Normal file
|
|
@ -0,0 +1,295 @@
|
|||
{
|
||||
"exportedFrom": "docs/openup/analysis-design/uc-realization-mapping.md §2, generated by scripts/openup/markdown-to-json.py — generated file, never hand-edit",
|
||||
"realizations": [
|
||||
{
|
||||
"id": "UC-01 Realization",
|
||||
"elements": [
|
||||
{
|
||||
"name": "AccountRegistry",
|
||||
"stereotype": "controller",
|
||||
"designElement": "`sb-api::routes::{register, seed_users}`",
|
||||
"notes": "argon2 hash via `sb-auth::hash`; JWT via `sb-auth::jwt`"
|
||||
},
|
||||
{
|
||||
"name": "UserAccount",
|
||||
"stereotype": "entity",
|
||||
"designElement": "`sb-shared::user::User`, `Role`",
|
||||
"notes": "persisted via `sb-db::Database`"
|
||||
},
|
||||
{
|
||||
"name": "AuthBoundary",
|
||||
"stereotype": "boundary",
|
||||
"designElement": "`POST /api/auth/register`, `AuthResponse`",
|
||||
"notes": ""
|
||||
}
|
||||
],
|
||||
"useCase": "Register Account"
|
||||
},
|
||||
{
|
||||
"id": "UC-02 Realization",
|
||||
"elements": [
|
||||
{
|
||||
"name": "Authenticator",
|
||||
"stereotype": "controller",
|
||||
"designElement": "`sb-api::routes::login`, `sb-auth::{hash::verify_password, jwt::create_token}`",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "TokenService",
|
||||
"stereotype": "boundary",
|
||||
"designElement": "`POST /api/auth/login`, `AuthResponse`, `middleware::auth::auth_middleware`",
|
||||
"notes": "middleware guards all UC-03…12"
|
||||
}
|
||||
],
|
||||
"useCase": "Authenticate"
|
||||
},
|
||||
{
|
||||
"id": "UC-03 Realization",
|
||||
"elements": [
|
||||
{
|
||||
"name": "CharacterFactory",
|
||||
"stereotype": "controller",
|
||||
"designElement": "`sb-core::character::create_character`",
|
||||
"notes": "takes injected rng (WI-1)"
|
||||
},
|
||||
{
|
||||
"name": "Character",
|
||||
"stereotype": "entity",
|
||||
"designElement": "`sb-shared::character::Character` (+ `Race`, `Class`, `CharacterStats`)",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "CharacterCatalog",
|
||||
"stereotype": "boundary",
|
||||
"designElement": "`GET/POST /api/users/{id}/characters`, `GET /api/characters/{id}`",
|
||||
"notes": "store: `AppState.characters`"
|
||||
},
|
||||
{
|
||||
"name": "ResourceRegenerator",
|
||||
"stereotype": "entity",
|
||||
"designElement": "`sb-core::character::apply_regen` (+ regen constants — WI-2 names them)",
|
||||
"notes": "included sub-flow"
|
||||
}
|
||||
],
|
||||
"useCase": "Manage Characters"
|
||||
},
|
||||
{
|
||||
"id": "UC-04 Realization",
|
||||
"elements": [
|
||||
{
|
||||
"name": "CatalogueBrowser",
|
||||
"stereotype": "boundary",
|
||||
"designElement": "`GET /api/{races,classes,items,enemies,adventures}`; response types `sb-shared::responses`",
|
||||
"notes": "data from `sb-common` JSON via `sb-core::{character::RACES/CLASSES, data, items}`"
|
||||
},
|
||||
{
|
||||
"name": "GameData",
|
||||
"stereotype": "entity",
|
||||
"designElement": "`sb-core::data::{EnemyDef, ZoneDef, EncounterEntry, LootDrop}`, `items::load_all_items`",
|
||||
"notes": ""
|
||||
}
|
||||
],
|
||||
"useCase": "Browse Game Catalogue"
|
||||
},
|
||||
{
|
||||
"id": "UC-05 Realization",
|
||||
"elements": [
|
||||
{
|
||||
"name": "TrainingService",
|
||||
"stereotype": "controller",
|
||||
"designElement": "`sb-core::services::train_stat`",
|
||||
"notes": "error type `DomainError` (WI-2)"
|
||||
},
|
||||
{
|
||||
"name": "TrainingGrounds",
|
||||
"stereotype": "entity",
|
||||
"designElement": "`sb-core::character::TRAINING_GROUNDS`, `training_cost` (+ cost constants WI-2)",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "GymBoundary",
|
||||
"stereotype": "boundary",
|
||||
"designElement": "`GET/POST /api/characters/{id}/gym`, `GymResponse`, `TrainStatResponse`",
|
||||
"notes": ""
|
||||
}
|
||||
],
|
||||
"useCase": "Train Stat"
|
||||
},
|
||||
{
|
||||
"id": "UC-06 Realization",
|
||||
"elements": [
|
||||
{
|
||||
"name": "EquipmentService",
|
||||
"stereotype": "controller",
|
||||
"designElement": "`sb-core::services::{equip_item, unequip_item}`",
|
||||
"notes": "`DomainError` (WI-2)"
|
||||
},
|
||||
{
|
||||
"name": "Equipment/Inventory",
|
||||
"stereotype": "entity",
|
||||
"designElement": "`Character.equipment` / `.inventory`, `sb-shared::item::Item`",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "EquipmentBoundary",
|
||||
"stereotype": "boundary",
|
||||
"designElement": "`POST /api/characters/{id}/{equip,unequip}`",
|
||||
"notes": ""
|
||||
}
|
||||
],
|
||||
"useCase": "Manage Equipment"
|
||||
},
|
||||
{
|
||||
"id": "UC-07 Realization",
|
||||
"elements": [
|
||||
{
|
||||
"name": "ShopService",
|
||||
"stereotype": "controller",
|
||||
"designElement": "`sb-api::routes::{shop_action, buy_item, sell_item}` (handler-side; extraction candidate, design note Q3)",
|
||||
"notes": "prices: `sb-core::items::{item_price, item_sell_price}`"
|
||||
},
|
||||
{
|
||||
"name": "ShopStock",
|
||||
"stereotype": "entity",
|
||||
"designElement": "`AppState.shop_stock`",
|
||||
"notes": "persisted via `sb-db`"
|
||||
},
|
||||
{
|
||||
"name": "ShopBoundary",
|
||||
"stereotype": "boundary",
|
||||
"designElement": "`GET/POST /api/characters/{id}/shop`, `ShopResponse`, `ShopActionResponse`",
|
||||
"notes": ""
|
||||
}
|
||||
],
|
||||
"useCase": "Trade at Shop"
|
||||
},
|
||||
{
|
||||
"id": "UC-08 Realization",
|
||||
"elements": [
|
||||
{
|
||||
"name": "AdventureService",
|
||||
"stereotype": "controller",
|
||||
"designElement": "`sb-core::adventure::run_adventure` (**new, WI-2**) + `services::pick_enemy` → `Result` (WI-2)",
|
||||
"notes": "takes injected rng; `DomainError` (WI-2)"
|
||||
},
|
||||
{
|
||||
"name": "CombatEngine",
|
||||
"stereotype": "entity",
|
||||
"designElement": "`sb-core::combat::{resolve_combat_full, resolve_attack, crit tables, open_ended_roll}` + combat constants (WI-2)",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "Combatant",
|
||||
"stereotype": "entity",
|
||||
"designElement": "`sb-core::combat::CombatStats`",
|
||||
"notes": "built from Character/EnemyDef"
|
||||
},
|
||||
{
|
||||
"name": "SpellEffect / BardSong",
|
||||
"stereotype": "entity",
|
||||
"designElement": "`sb-core::combat::SpellEffect`, `sb-core::spells`, `sb-core::songs`",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "AdventureBoundary",
|
||||
"stereotype": "boundary",
|
||||
"designElement": "`GET /api/characters/{id}/adventure`; `AdventureRunResponse` (**new, WI-2**), `sb-shared::responses::CombatLog`",
|
||||
"notes": ""
|
||||
}
|
||||
],
|
||||
"useCase": "Run Adventure"
|
||||
},
|
||||
{
|
||||
"id": "UC-09 Realization",
|
||||
"elements": [
|
||||
{
|
||||
"name": "HealingService",
|
||||
"stereotype": "controller",
|
||||
"designElement": "`sb-api::routes::heal_character` (handler-side; extraction candidate, Q3)",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "TempleBoundary",
|
||||
"stereotype": "boundary",
|
||||
"designElement": "`POST /api/characters/{id}/heal`; `HealResponse` (**new, WI-2**)",
|
||||
"notes": ""
|
||||
}
|
||||
],
|
||||
"useCase": "Heal at Temple"
|
||||
},
|
||||
{
|
||||
"id": "UC-10 Realization",
|
||||
"elements": [
|
||||
{
|
||||
"name": "SongService",
|
||||
"stereotype": "controller",
|
||||
"designElement": "`sb-api::routes::set_song`; `sb-core::songs::available_songs`",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "BardSong",
|
||||
"stereotype": "entity",
|
||||
"designElement": "`sb-core::songs::BARD_SONGS`, `Character.active_song`",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "SongBoundary",
|
||||
"stereotype": "boundary",
|
||||
"designElement": "`GET/POST /api/characters/{id}/songs`, `SongsResponse`, `SetSongResponse`",
|
||||
"notes": ""
|
||||
}
|
||||
],
|
||||
"useCase": "Practice Bard Song"
|
||||
},
|
||||
{
|
||||
"id": "UC-11 Realization",
|
||||
"elements": [
|
||||
{
|
||||
"name": "MagicService",
|
||||
"stereotype": "controller",
|
||||
"designElement": "`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)}`",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "Spell",
|
||||
"stereotype": "entity",
|
||||
"designElement": "`sb-core::spells::SpellDef`, `Character.{known_spells, active_spell, spell_points}`",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "MagicBoundary",
|
||||
"stereotype": "boundary",
|
||||
"designElement": "`GET/POST /api/characters/{id}/spells`; `SpellbookResponse`, `LearnSpellResponse` (**new, WI-2**)",
|
||||
"notes": ""
|
||||
}
|
||||
],
|
||||
"useCase": "Study Magic"
|
||||
},
|
||||
{
|
||||
"id": "UC-12 Realization",
|
||||
"elements": [
|
||||
{
|
||||
"name": "ReviewBoard",
|
||||
"stereotype": "controller",
|
||||
"designElement": "`sb-core::character::level_up`",
|
||||
"notes": "`DomainError` (WI-2)"
|
||||
},
|
||||
{
|
||||
"name": "Progression",
|
||||
"stereotype": "entity",
|
||||
"designElement": "`sb-core::character::{xp_for_level, level_up_cost, MAX_LEVEL}` (+ curve constants WI-2)",
|
||||
"notes": ""
|
||||
},
|
||||
{
|
||||
"name": "ReviewBoundary",
|
||||
"stereotype": "boundary",
|
||||
"designElement": "`POST /api/characters/{id}/level-up`, `LevelUpResponse`",
|
||||
"notes": ""
|
||||
}
|
||||
],
|
||||
"useCase": "Level Up at Review Board"
|
||||
}
|
||||
],
|
||||
"crossCutting": "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).",
|
||||
"dependencyRule": "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)."
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue