openup: architecture notebook + EA diagram renders
All checks were successful
build / build-test (push) Successful in 44s
All checks were successful
build / build-test (push) Successful in 44s
- analysis-design/architecture-notebook.md: Architecture Notebook work product in the keyfob docx template structure (10 sections), grounded in mapping / design note / supplementary specs; embeds the component model and all 12 realization figures - scripts/openup/export-diagram-images.ps1: read-only EA COM renderer (EA-15 findings: image API on ProjectInterface, OpenDiagram before export or blank stub, type 0 = PNG); renders reflect manual layouts - renders: requirements/use-case-overview.png, analysis-design/ uc-01..12-realization.png + component-architecture.png; embedded as figures in use-case-model.md and uc-realization-mapping.md - BUILD-CHECKLIST 6.4 documents the exporter
This commit is contained in:
parent
c0226df62d
commit
6e5d3fb45a
19 changed files with 351 additions and 0 deletions
244
docs/openup/analysis-design/architecture-notebook.md
Normal file
244
docs/openup/analysis-design/architecture-notebook.md
Normal file
|
|
@ -0,0 +1,244 @@
|
||||||
|
# Skara Brae — Architecture Notebook
|
||||||
|
|
||||||
|
Version 1.0 (2026-10-05) · OpenUP Analysis & Design artifact: `analysis-design/architecture-notebook.md`
|
||||||
|
Summary work product in the keyfob-station template structure. Sources (all in-repo, normative):
|
||||||
|
`analysis-design/uc-realization-mapping.md` (§1–§3), `analysis-design/design-wi-2-architecture-cleanup.md`
|
||||||
|
(§2–§4, §11), `requirements/supplementary-specifications.md`, `requirements/vision.md`, and the EA model
|
||||||
|
`docs/openup/model/skara-brae.eapx` (exports under `docs/openup/model/exports/`). Detailed per-WI design
|
||||||
|
remains in the WI design notes; this notebook is the cross-WI architecture view. Drift rule applies:
|
||||||
|
a mismatch between this notebook and its sources is a defect fixed in the same cycle.
|
||||||
|
|
||||||
|
## 1. Purpose
|
||||||
|
|
||||||
|
This notebook describes the goals, decisions, constraints and significant elements that shape the design of
|
||||||
|
Skara Brae across work items. The analysis and design models live in the EA model (Requirements / Use Case
|
||||||
|
Model, Analysis-Design realizations and Design component model); this notebook summarizes them for review
|
||||||
|
and onboarding. One model covers the whole product — server, client and common — because the use cases are
|
||||||
|
player-facing and Requirement→realization traceability spans tiers (joint-model decision, 2026-10-03).
|
||||||
|
|
||||||
|
## 2. Architectural Goals and Philosophy
|
||||||
|
|
||||||
|
- **Dependency rule inward** (Clean Architecture): domain in `sb-core`/`sb-shared` with zero HTTP/framework
|
||||||
|
knowledge; adapters (`sb-api`, `sb-db`, `sb-auth`) and the client at the edge (D1, CON-05).
|
||||||
|
- **Behavior continuity**: refactors are wire-format and game-semantics identical (NFR-11, NFR-19).
|
||||||
|
- **Determinism by construction**: domain randomness is injected (WI-1); identical seeds produce identical
|
||||||
|
outcomes (NFR-05, D5).
|
||||||
|
- **One taxonomy of failure**: a single domain error enum with one central HTTP status mapping (D2).
|
||||||
|
- **Data as source of truth**: game content is language-neutral JSON in `skara-brae-common`, compiled into
|
||||||
|
both consumers (NFR-13, D6).
|
||||||
|
- **Zero-warning quality gate**: fmt + clippy + full test suite on every commit (NFR-08..NFR-10).
|
||||||
|
- **Docs are architecture**: OpenUP markdown is the content source; the EA model renders it; drift is a
|
||||||
|
defect (D7).
|
||||||
|
|
||||||
|
## 3. Assumptions and Dependencies
|
||||||
|
|
||||||
|
- Single-process Rust server (Axum 0.8, edition 2024); all game state in memory behind `tokio::sync::RwLock`,
|
||||||
|
optional write-through persistence to SQLite via `SB_DB_PATH` (NFR-01, NFR-14).
|
||||||
|
- Static game data ships with the binary via `include_str!` from `skara-brae-common` (NFR-04, NFR-13).
|
||||||
|
- Clients are web/PWA (Vue 3 SPA) polling the REST API; server behavior is poll-frequency-independent
|
||||||
|
(NFR-02, NFR-03).
|
||||||
|
- `sb-common` is consumed as a sibling absolute-path dependency locally; git-submodule migration planned
|
||||||
|
(CON-01).
|
||||||
|
- Self-hosted pipeline: Forgejo (git), Jenkins CI, systemd deployment (vision.md; topology canon in Joplin
|
||||||
|
"Tech Stack & Architecture" note).
|
||||||
|
|
||||||
|
## 4. Architecturally Significant Requirements
|
||||||
|
|
||||||
|
The full set is `requirements/supplementary-specifications.md`; the categories that shape the architecture:
|
||||||
|
|
||||||
|
| Category | IDs | Architectural consequence |
|
||||||
|
|---|---|---|
|
||||||
|
| Performance / Scalability | NFR-01..NFR-04 | in-memory state, lazy regen (no timers), lock-free catalogue reads |
|
||||||
|
| Reliability / Correctness | NFR-05..NFR-07 | injected RNG, best-effort persistence, referential data integrity → `DomainError` |
|
||||||
|
| Quality Gates | NFR-08..NFR-12 | fmt/clippy/test gates; unwrap ledger; behavior-identical refactors |
|
||||||
|
| Data | NFR-13..NFR-15 | bilingual common package, SQLite format, i64 stat growth |
|
||||||
|
| Security | NFR-16..NFR-18 | argon2, JWT HS256 + auth middleware, role model (player/admin) |
|
||||||
|
| Constraints | CON-01..CON-06 | crate layout, Axum 0.8, rand 0.9 rule, one error enum, dependency rule, docs home |
|
||||||
|
| Usability / API | NFR-19..NFR-20 | wire-format freeze (lexicographic key order), status-code contract |
|
||||||
|
|
||||||
|
## 5. Decisions, Constraints, and Justifications
|
||||||
|
|
||||||
|
Full records in the WI design notes; the architecture-level decisions:
|
||||||
|
|
||||||
|
- **D1 — Layered crate architecture with inward dependencies.** `sb-api` (boundary/adapter) may import
|
||||||
|
`sb-core`, `sb-shared`, `sb-common`, `sb-db`, `sb-auth`; `sb-core` must not reference axum/http/
|
||||||
|
serde_json-json!/tokio/sb-db/sb-api (design note §3). Known debt: ShopService, HealingService, parts of
|
||||||
|
MagicService remain handler-side in sb-api — recorded, follow-up WI question Q3; the model must not paper
|
||||||
|
over them.
|
||||||
|
- **D2 — One domain error taxonomy.** `sb_core::error::DomainError` (thiserror 2) + single status mapping
|
||||||
|
`sb-api::routes::domain_status` realize the error paths of UC-05/06/08/12 (design note §4.1).
|
||||||
|
- **D3 — Constants centralized.** `sb_core::constants` is the single audit home for game-balance scalars
|
||||||
|
(NFR "no magic numbers"); static data tables stay in their modules (design note §2).
|
||||||
|
- **D4 — Response DTOs in sb-api, not sb-shared.** HTTP wire types never leak into the domain crate;
|
||||||
|
`AdventureOutcome` derives nothing (design note §2 placement decisions).
|
||||||
|
- **D5 — Injectable RNG with a single construction point.** `request_rng()` (`StdRng::from_os_rng`, WI-1);
|
||||||
|
domain functions take `rng: &mut impl Rng` (CON-03, NFR-05).
|
||||||
|
- **D6 — Bilingual shared data package.** `skara-brae-common`: `data/` JSON single source, `rust/` + `ts/`
|
||||||
|
thin consumers, `codegen/` planned (NFR-13; tech-stack canon).
|
||||||
|
- **D7 — Joint EA model, markdown source of truth, surgical builders.** Model changes after the manual
|
||||||
|
layout session go through surgical scripts only; `build-model.ps1` rebuilds and is forbidden on the laid-
|
||||||
|
out model (mapping §1, BUILD-CHECKLIST §6).
|
||||||
|
|
||||||
|
## 6. Architectural Mechanisms
|
||||||
|
|
||||||
|
- **Lazy resource regeneration** — resources recompute from elapsed wall-clock time at specific call sites;
|
||||||
|
no timers or background ticks (NFR-02; UC-05/UC-08 "Regenerate Resources" sub-flow).
|
||||||
|
- **Static catalogue via LazyLock** — game data parsed once at first access; lock-free reads (NFR-04, UC-04).
|
||||||
|
- **DomainError → status mapping** — domain rule failures flow through one enum to one mapping; handlers own
|
||||||
|
store misses/authz (D2, NFR-20).
|
||||||
|
- **Wire-format freeze** — JSON keys serialize in lexicographic order; typed responses declare fields in that
|
||||||
|
order (NFR-19).
|
||||||
|
- **Injectable RNG determinism** — seeded domain tests, single entropy entry point (D5, NFR-05).
|
||||||
|
- **Best-effort write-through persistence** — SQLite behind an in-memory-authoritative process (NFR-06,
|
||||||
|
NFR-14).
|
||||||
|
|
||||||
|
## 7. Key Abstractions
|
||||||
|
|
||||||
|
The analysis vocabulary (boundary/controller/entity) of the use-case realizations — full mapping incl.
|
||||||
|
design elements in `uc-realization-mapping.md` §2; classes, stereotypes and interactions per UC in the EA
|
||||||
|
model (§2a lists the 24 associations + 4 «uses» dependencies).
|
||||||
|
|
||||||
|
| Class | Stereotype | Responsibility (design element) |
|
||||||
|
|---|---|---|
|
||||||
|
| AuthBoundary | «boundary» | `POST /api/auth/register`, `AuthResponse` (UC-01) |
|
||||||
|
| TokenService | «boundary» | `POST /api/auth/login`, `AuthResponse`, auth middleware (UC-02, guards UC-03…12) |
|
||||||
|
| CharacterCatalog | «boundary» | character routes (UC-03) |
|
||||||
|
| CatalogueBrowser | «boundary» | catalogue routes + `sb-shared::responses` (UC-04) |
|
||||||
|
| GymBoundary | «boundary» | gym routes + responses (UC-05) |
|
||||||
|
| EquipmentBoundary | «boundary» | equip/unequip routes (UC-06) |
|
||||||
|
| ShopBoundary | «boundary» | shop routes + responses (UC-07) |
|
||||||
|
| AdventureBoundary | «boundary» | adventure route + `AdventureRunResponse` (UC-08) |
|
||||||
|
| TempleBoundary | «boundary» | heal route + `HealResponse` (UC-09) |
|
||||||
|
| SongBoundary | «boundary» | song routes + responses (UC-10) |
|
||||||
|
| MagicBoundary | «boundary» | spell routes + responses (UC-11) |
|
||||||
|
| ReviewBoundary | «boundary» | level-up route + response (UC-12) |
|
||||||
|
| AccountRegistry | «controller» | `sb-api::routes::{register, seed_users}` (UC-01) |
|
||||||
|
| Authenticator | «controller» | `sb-api::routes::login` + sb-auth verify/create (UC-02) |
|
||||||
|
| CharacterFactory | «controller» | `sb-core::character::create_character` (UC-03) |
|
||||||
|
| TrainingService | «controller» | `sb-core::services::train_stat` (UC-05) |
|
||||||
|
| EquipmentService | «controller» | `sb-core::services::{equip_item, unequip_item}` (UC-06) |
|
||||||
|
| ShopService | «controller» | `sb-api::routes::{shop_action, buy_item, sell_item}` (UC-07; **debt**: handler-side, extraction candidate Q3) |
|
||||||
|
| AdventureService | «controller» | `sb-core::adventure::run_adventure` (UC-08; WI-2 extraction) |
|
||||||
|
| HealingService | «controller» | `sb-api::routes::heal_character` (UC-09; **debt**: handler-side, extraction candidate Q3) |
|
||||||
|
| SongService | «controller» | `sb-api::routes::set_song` + `available_songs` (UC-10) |
|
||||||
|
| MagicService | «controller» | spell routes + `sb-core::spells` helpers (UC-11; **debt**: parts handler-side) |
|
||||||
|
| ReviewBoard | «controller» | `sb-core::character::level_up` (UC-12) |
|
||||||
|
| UserAccount | «entity» | `sb-shared::user::{User, Role}` (UC-01/02) |
|
||||||
|
| Character | «entity» | `sb-shared::character::Character` + Race/Class/Stats (UC-03) |
|
||||||
|
| ResourceRegenerator | «entity» | `sb-core::character::apply_regen` + regen constants (UC-03/05/08 sub-flow) |
|
||||||
|
| GameData | «entity» | `sb-core::data::{EnemyDef, ZoneDef, EncounterEntry, LootDrop}` (UC-04) |
|
||||||
|
| TrainingGrounds | «entity» | `TRAINING_GROUNDS`, `training_cost` (UC-05) |
|
||||||
|
| Equipment/Inventory | «entity» | `Character.equipment/.inventory`, `sb-shared::item::Item` (UC-06) |
|
||||||
|
| ShopStock | «entity» | `AppState.shop_stock` (UC-07) |
|
||||||
|
| CombatEngine | «entity» | `sb-core::combat::{resolve_combat_full, resolve_attack, crit tables, open_ended_roll}` (UC-08) |
|
||||||
|
| Combatant | «entity» | `sb-core::combat::CombatStats` (UC-08) |
|
||||||
|
| SpellEffect / BardSong | «entity» | `SpellEffect`, `sb-core::spells`, `sb-core::songs` (UC-08/10/11) |
|
||||||
|
| BardSong | «entity» | `BARD_SONGS`, `Character.active_song` (UC-10) |
|
||||||
|
| Spell | «entity» | `SpellDef`, `Character.{known_spells, active_spell, spell_points}` (UC-11) |
|
||||||
|
| Progression | «entity» | `xp_for_level`, `level_up_cost`, `MAX_LEVEL` (UC-12) |
|
||||||
|
|
||||||
|
Cross-cutting: `DomainError` (error paths UC-05/06/08/12), `Constants` (no-magic-numbers NFR), `Responses`
|
||||||
|
(wire-format freeze NFR-19) — carried in the model's Architecture Overview package.
|
||||||
|
|
||||||
|
## 8. Layers
|
||||||
|
|
||||||
|
The joint component model (mapping §3); dependencies point inward only.
|
||||||
|
|
||||||
|
| Tier | Component | Role |
|
||||||
|
|---|---|---|
|
||||||
|
| Presentation | skara-brae-client | Vue 3.5 SPA (Pinia, Vite), JWT bearer, REST via proxy; player-facing boundary of UC-01…12 |
|
||||||
|
| Boundary / adapter | sb-api | Axum routes/handlers, `domain_status`, `responses`; boundaries of all UCs |
|
||||||
|
| Adapter | sb-auth | argon2 + JWT (UC-01/02; middleware guards UC-03…12) |
|
||||||
|
| Adapter | sb-db | persistence via `sb-db::Database` |
|
||||||
|
| Domain | sb-core | controllers/entities: adventure, services, character, combat, spells, songs, data/items |
|
||||||
|
| Domain types | sb-shared | `User`, `Character`, `Item`, response types; zero HTTP imports |
|
||||||
|
| Data | sb-common | bilingual data package (`data/` JSON, `rust/`, `ts/`, `codegen/`); UC-04 data source |
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
*Figure 1: Joint component architecture — server crates, client, common (EA model render).*
|
||||||
|
|
||||||
|
## 9. Architectural Views
|
||||||
|
|
||||||
|
### 9.1 Use Case View
|
||||||
|
|
||||||
|
Architecturally significant use cases: UC-08 (Run Adventure — WI-2 design driver, combat + data integrity),
|
||||||
|
UC-03/UC-12 (character lifecycle), UC-04 (shared-data consumption), UC-05/06/07 (rule-driven economy
|
||||||
|
actions with the DomainError error paths), UC-01/02 (auth, middleware guard). Full model:
|
||||||
|
`requirements/use-case-model.md` + overview figure there.
|
||||||
|
|
||||||
|
| Realization | Use Case | Analysis classes |
|
||||||
|
|---|---|---|
|
||||||
|
| UC-01 Realization | Register Account | AuthBoundary, AccountRegistry, UserAccount |
|
||||||
|
| UC-02 Realization | Authenticate | TokenService, Authenticator |
|
||||||
|
| UC-03 Realization | Manage Characters | CharacterCatalog, CharacterFactory, Character, ResourceRegenerator |
|
||||||
|
| UC-04 Realization | Browse Game Catalogue | CatalogueBrowser, GameData |
|
||||||
|
| UC-05 Realization | Train Stat | GymBoundary, TrainingService, TrainingGrounds |
|
||||||
|
| UC-06 Realization | Manage Equipment | EquipmentBoundary, EquipmentService, Equipment/Inventory |
|
||||||
|
| UC-07 Realization | Trade at Shop | ShopBoundary, ShopService, ShopStock |
|
||||||
|
| UC-08 Realization | Run Adventure | AdventureBoundary, AdventureService, CombatEngine, Combatant, SpellEffect / BardSong |
|
||||||
|
| UC-09 Realization | Heal at Temple | TempleBoundary, HealingService |
|
||||||
|
| UC-10 Realization | Practice Bard Song | SongBoundary, SongService, BardSong |
|
||||||
|
| UC-11 Realization | Study Magic | MagicBoundary, MagicService, Spell |
|
||||||
|
| UC-12 Realization | Level Up at Review Board | ReviewBoundary, ReviewBoard, Progression |
|
||||||
|
|
||||||
|
### 9.2 Analysis View (Use-Case Realizations)
|
||||||
|
|
||||||
|
Each realization package in the EA model carries a class diagram (boundary/controller/entity with §2a
|
||||||
|
associations); renders in this folder, generated by `scripts/openup/export-diagram-images.ps1`:
|
||||||
|
|
||||||
|

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

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

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

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

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

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

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

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

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

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

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

|
||||||
|
|
||||||
|
### 9.3 Interaction View
|
||||||
|
|
||||||
|
Not yet modeled: no sequence diagrams exist for the Skara Brae MVP (the EA model carries scenarios with
|
||||||
|
per-step actors, not interactions). Candidate first sequences: UC-08 adventure request→combat→loot, and
|
||||||
|
UC-01/02 auth flows. Adding them is a future work item (PlantUML prototype → EA per the workflow canon).
|
||||||
|
|
||||||
|
### 9.4 Operational View
|
||||||
|
|
||||||
|
Single Rust process per deployment (systemd unit on the self-hosted boxes; Forgejo + Jenkins pipeline per
|
||||||
|
vision.md). All state in memory, optional write-through SQLite (NFR-01/06/14); no Redis for MVP. The Vue SPA
|
||||||
|
is served statically and talks to the API over HTTPS (Caddy, tech-stack canon). Clients poll; no push
|
||||||
|
channel in the MVP (WebSocket notifications are a later-phase feature, vision.md).
|
||||||
|
|
||||||
|
### 9.5 Design Diagram Index
|
||||||
|
|
||||||
|
| Diagram | File | Documents |
|
||||||
|
|---|---|---|
|
||||||
|
| 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 |
|
||||||
|
| Component Architecture | `component-architecture.png` | joint component model, dependency rule |
|
||||||
|
|
||||||
|
All three sets are renders of the EA model (`docs/openup/model/skara-brae.eapx`) produced by
|
||||||
|
`scripts/openup/export-diagram-images.ps1`; regenerate after model changes (read-only, layout-preserving).
|
||||||
|
|
||||||
|
## 10. References
|
||||||
|
|
||||||
|
- `requirements/vision.md`, `requirements/use-case-model.md`, `requirements/supplementary-specifications.md`
|
||||||
|
- `analysis-design/uc-realization-mapping.md` (§1 structure, §2 mapping, §2a interactions, §3 component model)
|
||||||
|
- `analysis-design/design-wi-1-injectable-rng.md`, `design-wi-2-architecture-cleanup.md` (detailed WI designs)
|
||||||
|
- EA model: `docs/openup/model/skara-brae.eapx` (+ `exports/` JSON, `BUILD-CHECKLIST.md`)
|
||||||
|
- Client-side UC realizations: future work item (joint-model decision, mapping §1)
|
||||||
BIN
docs/openup/analysis-design/component-architecture.png
Normal file
BIN
docs/openup/analysis-design/component-architecture.png
Normal file
Binary file not shown.
BIN
docs/openup/analysis-design/uc-01-realization.png
Normal file
BIN
docs/openup/analysis-design/uc-01-realization.png
Normal file
Binary file not shown.
BIN
docs/openup/analysis-design/uc-02-realization.png
Normal file
BIN
docs/openup/analysis-design/uc-02-realization.png
Normal file
Binary file not shown.
BIN
docs/openup/analysis-design/uc-03-realization.png
Normal file
BIN
docs/openup/analysis-design/uc-03-realization.png
Normal file
Binary file not shown.
BIN
docs/openup/analysis-design/uc-04-realization.png
Normal file
BIN
docs/openup/analysis-design/uc-04-realization.png
Normal file
Binary file not shown.
BIN
docs/openup/analysis-design/uc-05-realization.png
Normal file
BIN
docs/openup/analysis-design/uc-05-realization.png
Normal file
Binary file not shown.
BIN
docs/openup/analysis-design/uc-06-realization.png
Normal file
BIN
docs/openup/analysis-design/uc-06-realization.png
Normal file
Binary file not shown.
BIN
docs/openup/analysis-design/uc-07-realization.png
Normal file
BIN
docs/openup/analysis-design/uc-07-realization.png
Normal file
Binary file not shown.
BIN
docs/openup/analysis-design/uc-08-realization.png
Normal file
BIN
docs/openup/analysis-design/uc-08-realization.png
Normal file
Binary file not shown.
BIN
docs/openup/analysis-design/uc-09-realization.png
Normal file
BIN
docs/openup/analysis-design/uc-09-realization.png
Normal file
Binary file not shown.
BIN
docs/openup/analysis-design/uc-10-realization.png
Normal file
BIN
docs/openup/analysis-design/uc-10-realization.png
Normal file
Binary file not shown.
BIN
docs/openup/analysis-design/uc-11-realization.png
Normal file
BIN
docs/openup/analysis-design/uc-11-realization.png
Normal file
Binary file not shown.
BIN
docs/openup/analysis-design/uc-12-realization.png
Normal file
BIN
docs/openup/analysis-design/uc-12-realization.png
Normal file
Binary file not shown.
|
|
@ -144,6 +144,10 @@ sb-api → {sb-core, sb-shared, sb-db, sb-auth, sb-common}; sb-core → {sb-shar
|
||||||
sb-db → sb-shared; sb-auth → sb-shared. The dependency rule: inward toward
|
sb-db → sb-shared; sb-auth → sb-shared. The dependency rule: inward toward
|
||||||
sb-core/sb-shared (domain); adapters (sb-api/sb-db/sb-auth) and the client at the edge.
|
sb-core/sb-shared (domain); adapters (sb-api/sb-db/sb-auth) and the client at the edge.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
*Figure: joint component architecture (rendered from the EA model via `scripts/openup/export-diagram-images.ps1`). Per-UC realization figures: `uc-01-realization.png` … `uc-12-realization.png` in this folder; they are embedded in the Architecture Notebook (§9.2).*
|
||||||
|
|
||||||
## 4. Research summary — keyfob-station EA pipeline (reference)
|
## 4. 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).
|
Source: read-only clone `http://192.168.1.10:3000/jan/keyfob-station.git` (inspected 2026-10-03; no modifications).
|
||||||
|
|
|
||||||
|
|
@ -240,3 +240,12 @@ would destroy manual layout). Sources: `uc-realization-mapping.md` §2a (interac
|
||||||
associations; Requirements tree untouched.
|
associations; Requirements tree untouched.
|
||||||
4. Manual layout preserved: the scripts add no/modify no DiagramObjects in existing
|
4. Manual layout preserved: the scripts add no/modify no DiagramObjects in existing
|
||||||
diagrams (only the new `Design` diagram carries its own object layout).
|
diagrams (only the new `Design` diagram carries its own object layout).
|
||||||
|
|
||||||
|
### 6.4 Diagram image export — `scripts/openup/export-diagram-images.ps1`
|
||||||
|
|
||||||
|
Read-only on the model: renders 14 diagrams to PNG for the markdown documents
|
||||||
|
(`requirements/use-case-overview.png`, `analysis-design/uc-01..uc-12-realization.png`,
|
||||||
|
`analysis-design/component-architecture.png`). EA-15 findings baked into the script:
|
||||||
|
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
|
||||||
|
written. Regenerate after model changes; renders reflect the manual layout.
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,10 @@ Scope: the **existing implemented system** (server MVP as of `wi-2-architecture-
|
||||||
| UC-11 | Study Magic | Player | — |
|
| UC-11 | Study Magic | Player | — |
|
||||||
| UC-12 | Level Up at Review Board | Player | — |
|
| UC-12 | Level Up at Review Board | Player | — |
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
*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 **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.
|
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.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
|
||||||
BIN
docs/openup/requirements/use-case-overview.png
Normal file
BIN
docs/openup/requirements/use-case-overview.png
Normal file
Binary file not shown.
90
scripts/openup/export-diagram-images.ps1
Normal file
90
scripts/openup/export-diagram-images.ps1
Normal file
|
|
@ -0,0 +1,90 @@
|
||||||
|
# Skara Brae — EA diagram image exporter.
|
||||||
|
# Renders the model's diagrams to PNG for embedding in the OpenUP markdown documents.
|
||||||
|
# READ-ONLY on the model (opens diagrams, renders, closes; no model mutation).
|
||||||
|
#
|
||||||
|
# EA-15 findings baked in (probe session 2026-10-05):
|
||||||
|
# - the image methods live on ProjectInterface, NOT on Repository
|
||||||
|
# (Repository.SaveImageToPath exists but always returns False);
|
||||||
|
# - PutDiagramImageToFile(id, path, type) with type 0 = PNG;
|
||||||
|
# - the diagram must be OPEN (repo.OpenDiagram) before export, else a blank
|
||||||
|
# 241x151 stub is written;
|
||||||
|
# - works with EA hidden (app.Visible = $false).
|
||||||
|
#
|
||||||
|
# Output (keyfob-station convention: requirements overview next to the UC docs,
|
||||||
|
# realization + design figures in analysis-design/):
|
||||||
|
# docs/openup/requirements/use-case-overview.png
|
||||||
|
# docs/openup/analysis-design/uc-01-realization.png .. uc-12-realization.png
|
||||||
|
# docs/openup/analysis-design/component-architecture.png
|
||||||
|
|
||||||
|
$ErrorActionPreference = 'Stop'
|
||||||
|
|
||||||
|
$repoRoot = (Resolve-Path (Join-Path $PSScriptRoot '..\..')).Path
|
||||||
|
$modelPath = Join-Path $repoRoot 'docs\openup\model\skara-brae.eapx'
|
||||||
|
if (-not (Test-Path $modelPath)) {
|
||||||
|
Write-Output "MISSING $modelPath"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
$reqDir = Join-Path $repoRoot 'docs\openup\requirements'
|
||||||
|
$adDir = Join-Path $repoRoot 'docs\openup\analysis-design'
|
||||||
|
$null = New-Item -ItemType Directory -Force -Path $reqDir, $adDir
|
||||||
|
|
||||||
|
$step = 'start'
|
||||||
|
$app = $null
|
||||||
|
$eaBefore = @(Get-Process -Name EA -ErrorAction SilentlyContinue | Select-Object -ExpandProperty Id)
|
||||||
|
|
||||||
|
function Export-Diagram([object]$project, [object]$repo, [int]$diagramId, [string]$outPath) {
|
||||||
|
if (Test-Path $outPath) { Remove-Item $outPath -Force }
|
||||||
|
$null = $repo.OpenDiagram($diagramId)
|
||||||
|
Start-Sleep -Seconds 2
|
||||||
|
$null = $project.PutDiagramImageToFile($diagramId, $outPath, 0)
|
||||||
|
try { $null = $repo.CloseDiagram($diagramId) } catch { }
|
||||||
|
if (-not (Test-Path $outPath)) { throw "no image written: $outPath" }
|
||||||
|
$bytes = (Get-Item $outPath).Length
|
||||||
|
if ($bytes -lt 5000) { throw "suspiciously small render ($bytes bytes): $outPath" }
|
||||||
|
Write-Output "exported: $outPath ($bytes bytes)"
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$app = New-Object -ComObject EA.App
|
||||||
|
$app.Visible = $false
|
||||||
|
$repo = $app.Repository
|
||||||
|
$null = $repo.OpenFile($modelPath)
|
||||||
|
$root = $repo.Models.GetAt([int]0)
|
||||||
|
$project = $repo.GetProjectInterface()
|
||||||
|
|
||||||
|
$step = 'use case overview'
|
||||||
|
$ucModel = $root.Packages.GetByName('Requirements').Packages.GetByName('Use Case Model')
|
||||||
|
$ucModel.Diagrams.Refresh()
|
||||||
|
$overview = $ucModel.Diagrams.GetByName('Skara Brae Use Case Overview')
|
||||||
|
Export-Diagram $project $repo $overview.DiagramID (Join-Path $reqDir 'use-case-overview.png')
|
||||||
|
|
||||||
|
$step = 'realization diagrams'
|
||||||
|
$analysisDesign = $root.Packages.GetByName('Analysis-Design')
|
||||||
|
$analysisDesign.Packages.Refresh()
|
||||||
|
for ($p = 0; $p -lt $analysisDesign.Packages.Count; $p++) {
|
||||||
|
$pkg = $analysisDesign.Packages.GetAt([int]$p)
|
||||||
|
if ($pkg.Name -notlike 'UC-?? Realization') { continue }
|
||||||
|
$pkg.Diagrams.Refresh()
|
||||||
|
if ($pkg.Diagrams.Count -lt 1) { throw "no diagram in $($pkg.Name)" }
|
||||||
|
$number = $pkg.Name.Substring(3, 2)
|
||||||
|
Export-Diagram $project $repo $pkg.Diagrams.GetAt([int]0).DiagramID (Join-Path $adDir ("uc-{0}-realization.png" -f $number.ToLower()))
|
||||||
|
}
|
||||||
|
|
||||||
|
$step = 'component architecture'
|
||||||
|
$design = $analysisDesign.Packages.GetByName('Design')
|
||||||
|
$design.Diagrams.Refresh()
|
||||||
|
$componentDiagram = $design.Diagrams.GetByName('Component Architecture')
|
||||||
|
Export-Diagram $project $repo $componentDiagram.DiagramID (Join-Path $adDir 'component-architecture.png')
|
||||||
|
|
||||||
|
$null = $repo.CloseFile()
|
||||||
|
Write-Output 'EXPORT OK - 14 diagrams rendered'
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
Write-Output "FAILED at [$step]: $($_.Exception.Message)"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
Get-Process -Name EA -ErrorAction SilentlyContinue |
|
||||||
|
Where-Object { $eaBefore -notcontains $_.Id } |
|
||||||
|
ForEach-Object { Stop-Process -Id $_.Id -Force }
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue