Files
initiative/specs/029-on-demand-bestiary/quickstart.md

77 lines
3.2 KiB
Markdown

# Quickstart: On-Demand Bestiary with Pre-Indexed Search
**Feature**: 029-on-demand-bestiary
**Date**: 2026-03-10
## What This Feature Does
Replaces the bundled full bestiary file (one source, ~1.3 MB of copyrighted content) with:
1. A pre-shipped lightweight index (102 sources, 3,312 creatures, ~52 KB gzipped) for instant search and combatant creation
2. On-demand fetching of full stat block data per source, cached in IndexedDB
## Key Changes
### Removed
- `data/bestiary/xmm.json` — no longer shipped with the app
### New Files
- `apps/web/src/adapters/bestiary-index-adapter.ts` — loads and parses the shipped index, converts compact format to domain types
- `apps/web/src/adapters/bestiary-cache.ts` — IndexedDB cache adapter for fetched source data
- `apps/web/src/components/source-fetch-prompt.tsx` — dialog prompting user to fetch/upload source data
- `apps/web/src/components/source-manager.tsx` — UI for viewing and clearing cached sources
### Modified Files
- `apps/web/src/hooks/use-bestiary.ts` — rewritten to search from index and look up creatures from cache
- `apps/web/src/hooks/use-encounter.ts``addFromBestiary` accepts index entries (no fetch needed to add)
- `apps/web/src/components/bestiary-search.tsx` — shows source display name in results
- `apps/web/src/components/stat-block-panel.tsx` — triggers source fetch prompt when creature not cached
- `packages/domain/src/creature-types.ts` — new `BestiaryIndexEntry` and `BestiaryIndex` types
### Unchanged
- `apps/web/src/adapters/bestiary-adapter.ts` — normalization pipeline processes fetched data exactly as before
- `apps/web/src/adapters/strip-tags.ts` — tag stripping unchanged
- `apps/web/src/components/stat-block.tsx` — stat block rendering unchanged
- `apps/web/src/persistence/encounter-storage.ts` — encounter persistence unchanged
## Architecture Overview
```
index.json (shipped, static)
↓ Vite JSON import
bestiary-index-adapter.ts
↓ BestiaryIndexEntry[]
use-bestiary.ts (search, add)
bestiary-search.tsx → use-encounter.ts (addFromBestiary)
stat-block-panel.tsx
↓ creatureId → source not cached?
source-fetch-prompt.tsx
↓ fetch URL or upload file
bestiary-adapter.ts (normalizeBestiary — unchanged)
↓ Creature[]
bestiary-cache.ts (IndexedDB)
stat-block.tsx (renders full stat block)
```
## Development Commands
```bash
pnpm check # Must pass before every commit
pnpm test # Run all tests
pnpm typecheck # TypeScript type checking
pnpm --filter web dev # Dev server at localhost:5173
```
## Testing Strategy
- **Domain tests**: Pure function tests for new `BestiaryIndexEntry` type and any utility functions
- **Adapter tests**: Test index parsing (compact → readable format), test IndexedDB cache operations (mock IndexedDB via fake-indexeddb)
- **Component tests**: Not in scope (existing pattern — components tested via manual verification)
- **Integration**: Verify search returns multi-source results, verify add-from-index flow, verify fetch→cache→display flow
## New Dependency
- `idb` — Promise-based IndexedDB wrapper (~1.5 KB gzipped). Used only in `bestiary-cache.ts`.