Build MVP: campaigns, characters, combat, dice, compendium
- Rules abstraction (5e + pf2e) behind one interface, fully tested - Pure combat engine: turn-order safe across add/remove/reorder/init-change - Dexie storage with real cascade deletes + Zod validation on write - Seedable dice engine with notation parser - Lazy SRD compendium (code-split), bestiary -> combat - Strict TS, 54 unit tests, Playwright e2e smoke (all green) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,32 @@
|
||||
import Dexie, { type EntityTable } from 'dexie';
|
||||
import type { Campaign } from '@/lib/schemas/campaign';
|
||||
import type { Character } from '@/lib/schemas/character';
|
||||
import type { Encounter } from '@/lib/schemas/encounter';
|
||||
import type { DiceRoll } from '@/lib/schemas/dice';
|
||||
|
||||
/**
|
||||
* Single Dexie instance for the whole app. Dexie wraps IndexedDB transactions
|
||||
* correctly (commits before resolving), which removes the silent-data-loss
|
||||
* class of bugs the old hand-rolled adapter shipped with.
|
||||
*
|
||||
* Schema versions are additive: bump `version(n)` and add a `.upgrade()` when
|
||||
* the shape changes — never edit a past version in place.
|
||||
*/
|
||||
export class TtrpgDatabase extends Dexie {
|
||||
campaigns!: EntityTable<Campaign, 'id'>;
|
||||
characters!: EntityTable<Character, 'id'>;
|
||||
encounters!: EntityTable<Encounter, 'id'>;
|
||||
diceRolls!: EntityTable<DiceRoll, 'id'>;
|
||||
|
||||
constructor() {
|
||||
super('ttrpg-manager');
|
||||
this.version(1).stores({
|
||||
campaigns: 'id, updatedAt',
|
||||
characters: 'id, campaignId, kind',
|
||||
encounters: 'id, campaignId, status',
|
||||
diceRolls: 'id, campaignId, createdAt',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export const db = new TtrpgDatabase();
|
||||
Reference in New Issue
Block a user