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:

  1. Rules and spells are public, so they come through my own server from a public source.
  2. Characters are saved to your account. Joining a table also lets that table's DM read your character sheet.
  3. 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

  1. Your browserasks for "Fireball"
  2. Express APIQuestKeeper's backend
  3. D&D 5e SRD APIpublic rules data
  4. 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.

QuestKeeper's DM view of a table's initiative order, using test data. Each enemy and ally shows its public status, such as Down, Bloodied or Healthy, with a DM-only line of hit points and armor class underneath.
The DM's table view, shown with test data.
Read the QuestKeeper case study →Source on GitHub