skara-brae-common/docs/openup/analysis-design/architecture-notebook.md
Jan-Peter von Hunnius 193562cbc4 openup: doc restructure - template alignment + design sequences (non-PSP)
Align the OpenUP markdown set to the blank templates (process-data repo,
templates/openup/) per BUILD-CHECKLIST 7. Scenario step text unchanged;
the EA model needs no change (brief descriptions already live in the
model's UC/actor notes).

- vision.md: positioning tables, stakeholder summary, user environment,
  needs-and-features table (R1/R2), other product requirements
- use-case-model.md: per-UC specification sections (brief description,
  actor descriptions, named alternative/exception subsections with
  numbered steps, post-conditions, special requirements)
- supplementary-specifications.md: category tables with priority and
  use-case columns + reverse coverage matrix; IDs unchanged
- test/quality-check-procedure.md: migrated from Joplin (single content
  home); stale open items marked resolved (WI-1/WI-2)
- analysis-design/sequences/: 12 PlantUML design sequences (lifelines =
  analysis classes, messages = design elements; per the PlantUML layout
  style guide) + PNG renders; embedded in Architecture Notebook 9.3
- Joplin consolidated: project content notes deleted (all live in
  docs/game + docs/openup); Joplin keeps the status note only
2026-10-05 11:22:38 +02:00

271 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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 |
![Component Architecture](component-architecture.png)
*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`:
![UC-01 Realization](uc-01-realization.png)
![UC-02 Realization](uc-02-realization.png)
![UC-03 Realization](uc-03-realization.png)
![UC-04 Realization](uc-04-realization.png)
![UC-05 Realization](uc-05-realization.png)
![UC-06 Realization](uc-06-realization.png)
![UC-07 Realization](uc-07-realization.png)
![UC-08 Realization](uc-08-realization.png)
![UC-09 Realization](uc-09-realization.png)
![UC-10 Realization](uc-10-realization.png)
![UC-11 Realization](uc-11-realization.png)
![UC-12 Realization](uc-12-realization.png)
### 9.3 Interaction View
Design sequences for all twelve use-case realizations. Sources are the version-controlled
PlantUML files under `sequences/` (working copy per the PlantUML→EA workflow canon; the EA
model carries scenarios with per-step actors). Render: `java -jar plantuml.jar -tpng
-charset UTF-8 sequences/*.puml`; lifelines = the realization's analysis classes
(mapping §2), messages = the actual design elements (routes and domain functions).
![UC-01 Register](sequences/uc-01-register.png)
![UC-02 Authenticate](sequences/uc-02-authenticate.png)
![UC-03 Manage Characters](sequences/uc-03-manage-characters.png)
![UC-04 Browse Catalogue](sequences/uc-04-browse-catalogue.png)
![UC-05 Train Stat](sequences/uc-05-train-stat.png)
![UC-06 Manage Equipment](sequences/uc-06-manage-equipment.png)
![UC-07 Trade at Shop](sequences/uc-07-trade-at-shop.png)
![UC-08 Run Adventure](sequences/uc-08-run-adventure.png)
![UC-09 Heal at Temple](sequences/uc-09-heal-at-temple.png)
![UC-10 Practice Bard Song](sequences/uc-10-practice-bard-song.png)
![UC-11 Study Magic](sequences/uc-11-study-magic.png)
![UC-12 Level Up](sequences/uc-12-level-up.png)
### 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 |
| 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 |
EA model renders are produced by `scripts/openup/export-diagram-images.ps1`; sequence
renders by PlantUML from the committed sources. Regenerate after changes (drift rule).
## 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)