skara-brae-common/docs/openup/analysis-design/architecture-notebook.md
Jan-Peter von Hunnius 6e5d3fb45a
All checks were successful
build / build-test (push) Successful in 44s
openup: architecture notebook + EA diagram renders
- 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
2026-10-05 10:00:45 +02:00

15 KiB
Raw Blame History

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

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-02 Realization

UC-03 Realization

UC-04 Realization

UC-05 Realization

UC-06 Realization

UC-07 Realization

UC-08 Realization

UC-09 Realization

UC-10 Realization

UC-11 Realization

UC-12 Realization

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)