Behind the Build · QuestKeeper
How QuestKeeper keeps a DM's secrets secret
The short version (no code needed)
QuestKeeper moves three kinds of information, and each one travels differently:
- Rules and spells are public, so they come through my own server from a public source.
- Characters are saved to your account. Joining a table also lets that table's DM read your character sheet.
- Enemy stats are hidden even from the players at the table. So the rules that need them run in the database, and players get back only the result.
Showing: 1 · Reference data
Public rules travel through my backend
Path 1 · public reference
- Your browserasks for "Fireball"
- Express APIQuestKeeper's backend
- D&D 5e SRD APIpublic rules data
- Consistent wrapper{ data: … } for every category
Keeping the outside API behind my own server gives me one place to add validation, caching and source information later.
Your browser asks QuestKeeper's backend. The backend asks the public D&D 5e SRD API, then returns it. The backend returns each category in a consistent response wrapper. Keeping the outside API behind my own server gives me one place to add validation, caching and source information later, without touching the frontend.
GET /api/spells/fireball → { data: … }
Why hiding it on screen wasn't enough
Anything a browser receives can be read in its developer tools. A "DM only" label on the screen wouldn't stop a curious player from opening the network tab. The fix had to change what gets sent, not just what gets shown.
Try it
Roll to attack
A goblin boss with a hidden armor class. Roll, and see what your browser actually gets back.
Goblin Boss · Bloodied · AC: hidden
Your attack bonus: +5
How it's been checked
The project README records local checks of the database functions using DM, player and outsider identities. Those checks are not currently included as automated tests in the repository.
What players see instead
The DM sees the numbers. Players see a name, a status and the damage dealt.
