# Skara Brae — Supplementary Specifications `Skara Brae` — OpenUP Requirements · version 2.0 (2026-10-05, restructured to the OpenUP supplementary-specifications template: category tables with priority and use-case trace + coverage matrix; requirement IDs unchanged from version 1.0). Non-functional requirements and constraints for the server MVP. Facts cite code where they are implemented; assumptions are marked. Category tailoring vs stock OpenUP: this project adds **Quality Gates** and **Data** categories (project-specific acceptance and game-data rules); a Standards category is not applicable at R1. # Performance / Scalability | **ID** | **Requirement** | **Priority** | **Use Cases** | | --- | --- | --- | --- | | NFR-01 | In-memory state: all game state (users, characters, shop stock) is held in process memory behind `tokio::sync::RwLock` (`crates/sb-api/src/routes/mod.rs:33–42`). Single-process deployment; persistence is write-through to SQLite, reads never hit the DB. | High | UC-01..UC-12 | | NFR-02 | Lazy regeneration: resource regeneration is computed on every character access from elapsed wall-clock time (`apply_regen`, character.rs:105–122) — no timers, no background ticks. Intervals: energy 180 s, nerve 300 s, HP 300 s (5% max HP per tick). | High | UC-03, UC-05, UC-08 | | NFR-03 | Client polling: clients poll character state to observe regeneration; the assumed UI refresh cadence is ~15 s *(assumption carried from project planning; server-side behavior is poll-frequency-independent by design NFR-02)*. | Medium | UC-03, UC-05, UC-08 | | NFR-04 | Static catalogue: items, enemies, zones, spells, and crit tables are compiled in via `include_str!` from `skara-brae-common` JSON and parsed once behind `LazyLock`; catalogue reads are lock-free after first access. | High | UC-04 | # Reliability / Correctness | **ID** | **Requirement** | **Priority** | **Use Cases** | | --- | --- | --- | --- | | NFR-05 | Deterministic domain logic: all domain randomness is injected `StdRng` (WI-1); identical seeds produce identical outcomes. Request paths construct RNG only at `request_rng()`. | High | UC-03, UC-07, UC-08 | | NFR-06 | Persistence best-effort: persistence failures are logged (`tracing::error`) and do not fail the request; in-memory state remains authoritative for the process lifetime. | Medium | UC-01, UC-03, UC-05..UC-12 | | NFR-07 | Referential data integrity: zone encounter tables must reference existing enemy ids and loot drops must reference existing item ids; violations are detected at first use (WI-2: `DomainError::UnknownEncounterEnemy` → 500 instead of a panic). | High | UC-08 | # Quality Gates (per-commit acceptance) | **ID** | **Requirement** | **Priority** | **Use Cases** | | --- | --- | --- | --- | | NFR-08 | `cargo fmt --check` clean (fmt baseline established by WI-2). | High | all | | NFR-09 | `cargo clippy --all-targets -- -D warnings` clean — zero-warning policy. | High | all | | NFR-10 | `cargo test --workspace` fully green (45 sb-core tests at WI-2 start; suite only grows). | High | all | | NFR-11 | Behavior-identical refactor — JSON field names/order, HTTP status codes, game semantics, and RNG draw order unchanged (WI-2-specific; standing interpretation for future refactors). | High | all | | NFR-12 | No `unwrap()`/`expect()` on request paths outside the documented keep-with-reason invariants in the design-note §6 ledger (covers sb-api, sb-core, sb-db mutex poisoning, sb-auth time/entropy invariants). | High | all | # Data | **ID** | **Requirement** | **Priority** | **Use Cases** | | --- | --- | --- | --- | | NFR-13 | Shared data source: all game content lives in the `skara-brae-common` repo as language-neutral JSON under `data/` — single source of truth consumed at build time by server (`include_str!` + serde) and client. Server must not duplicate or transform these definitions in code. | High | UC-04 | | NFR-14 | Persistence format: optional SQLite via `SB_DB_PATH` (rusqlite; users, characters, shop stock with `next_character_id`). Absent the variable the server runs purely in-memory with seeded `admin`/`player` accounts. | Medium | UC-01, UC-03, UC-07 | | NFR-15 | Numeric headroom: stats are `i64` (BIGINT) — "exponential growth, tiered display" is a product commitment; no narrowing conversions to smaller integers in new code. | High | UC-05, UC-08, UC-12 | # Security | **ID** | **Requirement** | **Priority** | **Use Cases** | | --- | --- | --- | --- | | NFR-16 | Passwords hashed with argon2; verification constant-time via the crate. | High | UC-01, UC-02 | | NFR-17 | JWT (HS256, `jsonwebtoken`), 24 h expiry; all game routes behind auth middleware; cross-user access requires the `admin` role (403 otherwise). | High | UC-01..UC-12 | | NFR-18 | No secrets in code; JWT secret and admin/player seed passwords come from environment/configuration. | High | UC-01, UC-02 | # Interfaces | **ID** | **Requirement** | **Priority** | **Use Cases** | | --- | --- | --- | --- | | NFR-19 | REST JSON API; field names and order are a wire contract — refactors must preserve them byte-for-byte. The current API emits JSON object keys in lexicographic order (serde_json resolves without `preserve_order`; `json!` uses BTreeMap-backed maps), and the typed-response structs of WI-2 declare fields in that order to stay byte-identical. | High | UC-01..UC-12 | | NFR-20 | Meaningful HTTP status codes: 400 malformed input, 401 auth failure, 403 foreign/non-permitted resource, 404 unknown resource, 409 name conflict, 410 shop stock exhausted, 422 game-rule violation (resources/requirements), 500 internal. | High | UC-01..UC-12 | # Design Constraints | **ID** | **Requirement** | **Priority** | **Use Cases** | | --- | --- | --- | --- | | CON-01 | Rust, edition **2024**; workspace crates `sb-api` / `sb-core` / `sb-db` / `sb-auth` / `sb-shared` + external sibling `sb-common` (absolute path dependency; submodule migration planned). | High | all | | CON-02 | HTTP framework **Axum 0.8** (ws + macros features), tokio, tower stack (CORS/trace/compression-gzip). | High | all | | CON-03 | `rand 0.9`; domain functions take `rng: &mut impl Rng`; handlers obtain RNG only from `request_rng()` (WI-1 rule). | High | UC-03, UC-07, UC-08 | | CON-04 | Error handling: `thiserror 2` in-domain; **no new error/framework dependencies**; one domain error enum (`sb_core::error::DomainError`) with a single central HTTP status mapping in sb-api. | High | UC-05, UC-06, UC-08, UC-12 | | CON-05 | Clean Architecture dependency rule: sb-core has zero knowledge of HTTP/axum/serde_json/tokio/tracing/sb-db; ports (domain traits) would live in sb-core, adapters outward. | High | all | | CON-06 | OpenUP work products are versioned in the **skara-brae-common repo** under `docs/openup/` — one canonical project-docs home (decision reversed 2026-10-03 from the earlier skara-brae-server `docs/openup/` plan). `roadmap.md` stays at the project-top folder per the earlier PM decision. | Medium | — | # Documentation | **ID** | **Requirement** | **Priority** | **Use Cases** | | --- | --- | --- | --- | | DOC-01 | The OpenUP artifact set (Vision, Use-Case Specifications, Supplementary Specifications, Architecture Notebook, test artifacts) and the game-design canon (`docs/game/`) live in the skara-brae-common repo and are maintained there; the EA model and its exports render them. Joplin keeps project status only. | Medium | — | # Use Case Coverage Matrix | **ID** | **Use Case** | **Traced Requirements** | | --- | --- | --- | | UC-01 | Register Account | NFR-01, NFR-06, NFR-16, NFR-17, NFR-18, NFR-19, NFR-20 | | UC-02 | Authenticate | NFR-16, NFR-17, NFR-18, NFR-19, NFR-20 | | UC-03 | Manage Characters | NFR-01, NFR-02, NFR-03, NFR-05, NFR-06, NFR-14, NFR-17, NFR-19, NFR-20 | | UC-04 | Browse Game Catalogue | NFR-04, NFR-13, NFR-19, NFR-20 | | UC-05 | Train Stat | NFR-02, NFR-03, NFR-06, NFR-11, NFR-12, NFR-15, CON-04 | | UC-06 | Manage Equipment | NFR-06, NFR-11, NFR-12, CON-04 | | UC-07 | Trade at Shop | NFR-05, NFR-06, NFR-14, CON-03 | | UC-08 | Run Adventure | NFR-02, NFR-03, NFR-05, NFR-07, NFR-11, NFR-15, CON-03, CON-04 | | UC-09 | Heal at Temple | NFR-06, NFR-11, NFR-12 | | UC-10 | Practice Bard Song | NFR-06, NFR-11, NFR-12 | | UC-11 | Study Magic | NFR-06, NFR-11, NFR-12, NFR-15 | | UC-12 | Level Up at Review Board | NFR-06, NFR-11, NFR-12, NFR-15, CON-04 |