52 lines
2.5 KiB
Markdown
52 lines
2.5 KiB
Markdown
# DECISIONS.md — Architecture Decision Log
|
|
|
|
Record any choice that deviates from or fills a gap in the docs. Newest at the bottom.
|
|
|
|
Format:
|
|
```
|
|
## D-NNN: Title
|
|
- Date:
|
|
- Context: (what problem / ambiguity)
|
|
- Decision: (what you chose)
|
|
- Alternatives considered:
|
|
- Consequences:
|
|
```
|
|
|
|
## D-001: SQLite + better-sqlite3 as the datastore
|
|
- Date: (project start)
|
|
- Context: Needs persistent accounts and game state with zero setup for a local build.
|
|
- Decision: SQLite file in `data/`, synchronous driver, WAL mode.
|
|
- Alternatives considered: Postgres (heavier setup), JSON files (no integrity/transactions).
|
|
- Consequences: Single-process deployment; synchronous transactions give simple double-spend protection. Migrate to Postgres only if scaling beyond one server.
|
|
|
|
## D-002: Lazy time evaluation instead of tick loops
|
|
- Date: (project start)
|
|
- Context: Game must progress while players are offline.
|
|
- Decision: Store timestamps; compute energy/timers on demand.
|
|
- Consequences: No background workers, trivially testable with injected clocks.
|
|
|
|
## D-003: Vanilla frontend, no build step
|
|
- Date: (project start)
|
|
- Context: Reduce tooling surface area for a local-model build.
|
|
- Decision: Static HTML/CSS/JS served by Express.
|
|
- Consequences: Slightly more DOM boilerplate; far fewer moving parts.
|
|
|
|
## D-004: Both combatants attack every round
|
|
- Date: 2026-10-20 (review)
|
|
- Context: Combat treated "higher speed acts first" as "only the faster side acts", so the slower side never attacked.
|
|
- Decision: Each round, both attack; faster first; hero wins speed ties; a kill ends the round.
|
|
- Consequences: Round log has up to 2 entries per round (max 40). Win rates need re-tuning (see STATUS issue 1).
|
|
|
|
## D-005: Equipment stats are counted once in derived stats
|
|
- Context: maxHp added equipment VIT twice (once in totalVit, once as a separate term).
|
|
- Decision: `calcDerived` in `src/game/stats.js` is the ONLY derived-stat formula; combat and services call it.
|
|
|
|
## D-006: Real SQLite session store everywhere; unref its cleanup timer
|
|
- Context: better-sqlite3-session-store ignores `expired.clear:false` (`clear || true`), so its setInterval kept tests alive; the project had used a memory store in tests, so the real store was never exercised.
|
|
- Decision: Wrap store creation so its interval is unref'd. Tests now use the real store.
|
|
|
|
## D-007: `src/utils/time.js` is the only clock
|
|
- Decision: Services call `time.now()`; tests use `time.setNow()`. Game functions take `nowMs`/`rng` as parameters.
|
|
|
|
<!-- Add D-008 onward below -->
|