Files
Emberfall/docs/DECISIONS.md
T
2026-10-23 06:16:38 +11:00

63 lines
3.9 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.
# 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-022: Material sell prices use item-level formula
- Context: BALANCE.md says materials sell at `common 2×level, uncommon 4×level, rare 8×level` — but "level" was ambiguous (hero level vs item level). The code used `defaultRate * heroLevel / itemMinLevel`, making high-level heroes overpay and low-level heroes underpay for high-level materials.
- Decision: Use `materialSellPrice(rarity, itemMinLevel)` from `src/game/rewards.js` — price depends on the ITEM's level, not the hero's. BALANCE.md table corrected to match the formula (e.g., Drake Scale: 90g → 112g).
- Consequences: Existing shop tests that asserted hero-level prices updated; material sell prices are now consistent regardless of hero level.
## 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.
## D-023: Shared grantItem for inventory item granting
- Date: 2026-10-23
- Context: `huntService` and `shopService` both need to grant items to inventory. `huntService` had a local `grantItem` that correctly creates one row per unit for non-stackable items, but `shopService` duplicated the logic incorrectly (inserted full quantity for non-stackables).
- Decision: Extract `grantItem(s, characterId, item, quantity, now)` to `src/game/inventory.js`. Both services import it. The service's stmtCache must include `stackRow`, `addToStack`, `insertInv` with the exact same SQL used by huntService.
- Consequences: Single source of truth for item-granting logic. Any future service that grants items (expeditions, quests, etc.) can reuse it.
<!-- Add D-008 onward below -->