Files
the-sunken-reach/README.md
T
joshuaandClaude Opus 5.5 9c97d61ce5 V1.12.0: worlds from a code, shops and cash in the seeds, up-to-date packages
- A DM can start a campaign from a ready-made world by typing its
  six-character code: "+ New Campaign" on the Campaigns page, then "Or
  start from a ready-made world". The whole world is built in one go
  with them as its DM: locations, weapons, items, spells, monsters,
  NPCs, encounters and notes. ALDENF is Aldenfell, HOLLOW is Hollowcrown.
- A world is one file in /backend/seeds. Drop another in and its code
  works straight away, with no restart. "npm run seeds:check" lists
  every world, or what is wrong with one: a misspelt field, a name used
  twice, an encounter pointing at something the file does not have. A
  file with a mistake in it is never offered. docs/SEEDS.md has the
  format.
- A seed can now hold everything a campaign can: gear effects, an NPC's
  wares and exchange rate, things for sale at an encounter, and rewards
  in silver, copper and cash.
- The database seed creates the admin account and nothing else. The
  Aldenfell and Hollowcrown seed commands are gone: worlds come from
  codes.
- Hollowcrown follows the V3 book: 4 starting items and 3 things
  equipped, the book's effects on every weapon and item, armor as items
  (library, modern and magic), worn gear at the book's levels, damage
  types on monsters, ten shop scenes with prices and stock, five money
  changers, Meridian loot as cash and mixed hoards as gold, silver and
  copper.
- Aldenfell: the Shield and Leather Armor change AC, Mireille and the
  Founding Fair stalls sell things, and the book's missing scenes are in
  (E5, E7, E15, E16, E18, E23-24, E26, the Drowned Shrine, Sevrisk's
  Hollow, a wyvern pass). The locket is found with Investigation, as the
  book has it.
- Packages are up to date: Prisma 7 (with the pg driver adapter and a
  prisma.config.js that holds the database URL), Express 5, zod 4,
  dotenv 18, jest 30, bcrypt 6 and TypeScript 7. "npm audit" finds
  nothing. Install scripts are approved for Prisma and bcrypt. On a
  server: "npm install", then "npm run deploy".
- The frontend's five lint warnings are fixed; useAuth and usePagination
  have files of their own.
- All packages at version 1.12.0.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 16:03:16 +02:00

154 lines
6.8 KiB
Markdown

# The Sunken Reach — D&D 5e Campaign Manager
A web app for a D&D 5e Dungeon Master and their players to run a campaign
together: campaign management, a guided dice-roll character builder, live
character sheets, a character panel on every page, weapons/inventory/spells,
monsters, and a real-time encounter/combat tracker.
## How it works
`/docs` describes the app as it currently behaves, one subject per file:
| Document | Covers |
|---|---|
| `docs/CHARACTERS.md` | Building a character, every number on the sheet, levels, money, permissions |
| `docs/WEAPONS.md` | The weapon pool and library, equipping, weapon levels and how damage grows |
| `docs/SPELLS.md` | The spell list, who can use which spells, the spell library |
| `docs/ITEMS.md` | The item pool and library, armor and other gear effects, what can be equipped, items for sale |
| `docs/ENCOUNTERS.md` | Battles and NPC quests, turns, rewards, trade, what players see |
| `docs/MONSTERS.md` | The monster list and built-in bestiary |
| `docs/NPCS.md` | Non-player characters, what they sell and the rates they change money at |
| `docs/SEEDS.md` | World seeds: ready-made campaigns a DM starts from a code, and how to add one |
`CLAUDE_BUILD_PROMPT.md`, `docs/GAME_RULES_REFERENCE.md` and
`docs/ROLL_YOUR_CHARACTER.md` are the original specifications the first
version was built from. The app has since moved on in places (gear levels,
the builder's story steps, picking a motivation); the documents above are the
current behaviour.
## Getting around
The same four destinations are always on screen: **Campaigns** (the list),
**Campaign** and **Party** (for the campaign you were last in, from any page,
including a character sheet or an encounter) and **Account**.
- On a wide screen they are links along the top bar, and the dice roller
floats at the bottom left.
- On a phone or small tablet (900px wide or less) they are a bar along the
bottom of the screen, with the **dice roller** as its last button. Nothing
floats over the page: the 🧙 character button sits in the top bar.
- The **🧙 character button** is on every page (floating at the bottom right
on a wide screen). It opens a panel with your character's numbers and
everything they hold; the DM can open it for any character.
- The campaign page and the character sheet are long, so each starts with a
row of **section links** (Characters, Encounters, NPCs, Monsters...) that
jump straight to that part of the page.
- On a small screen every table (weapons, items, spells, monsters, the party
overview) is shown as a stack of cards, one per row, with each figure
labelled, and rows of controls wrap rather than run off the side.
## Stack
- **Backend:** Node.js + Express, JavaScript, Prisma ORM (with the `pg` driver adapter), PostgreSQL, Socket.io, JWT auth (bcrypt + jsonwebtoken), zod validation.
- **Frontend:** React + Vite + TypeScript, React Router, TanStack Query, socket.io-client.
## Prerequisites
- Node.js 20.19+ (tested on Node 24)
- A running PostgreSQL instance (local install, Docker, or a hosted service like Neon/Supabase)
## First-time setup
```bash
npm install # installs both workspaces (backend + frontend)
# Backend: point at your Postgres instance and run migrations
cd backend
cp .env.example .env # edit DATABASE_URL and JWT_SECRET
npx prisma migrate dev --name init
npx prisma generate # migrate no longer does this itself
npx prisma db seed # adds the admin account if it is missing (see output for the login and the world codes)
# Frontend
cd ../frontend
cp .env.example .env # defaults to http://localhost:4000, adjust if needed
```
## Running in dev
In two terminals, from the repo root:
```bash
npm run dev:backend # Express + Socket.io on http://localhost:4000
npm run dev:frontend # Vite dev server, prints its own port (5173 by default)
```
Open the frontend URL, register an account (or log in with the seeded admin
account — see the seed script's console output for the credentials), and
start playing.
The database seed creates the admin account and nothing else. It only adds: an
existing account, and its password, is left alone, so it is safe to run on a
server with real data. `SEED_ADMIN_EMAIL`, `SEED_ADMIN_PASSWORD` and
`SEED_ADMIN_NAME` set the account it creates. `npx prisma db seed -- --reset`
wipes every user and campaign first.
## Worlds
Campaigns are created in the app: blank, or from a **world seed** by its
code. On the Campaigns page click "+ New Campaign" and enter a code under "Or
start from a ready-made world"; the whole world is built for you as its DM.
| Code | World |
|---|---|
| `ALDENF` | Aldenfell |
| `HOLLOW` | Hollowcrown: The Rift Between Worlds |
Each world is one file in `/backend/seeds`. Drop another file in and its code
works straight away, with no restart; `npm run seeds:check` (from the repo
root or `backend`) checks every file and says what is wrong with one.
`docs/SEEDS.md` has the format.
On a server, after pulling a new version, run `npm install` in the repo root
(when dependencies changed) and then `npm run deploy` in `backend`
and then restart the backend. It applies new migrations **and** regenerates
the Prisma client; without the second half the server keeps running with the
old data model and pages that use anything new fail to load (for example
"Could not load this encounter"). Change your password from the account page
("Account" in the navigation).
## Tests
```bash
cd backend
npm test
```
The calculation engine (`src/game/calculations.js`) and the world seeds
(`src/seeds`, which also checks every file in `/backend/seeds`) are unit
tested and run with no external dependencies. The route-level integration tests in
`src/routes/api.integration.test.js` need a real, migrated database reachable
via `DATABASE_URL` — they skip themselves gracefully (with a console warning)
if the DB isn't reachable, so `npm test` still passes in an environment with
no database configured.
## Project layout
```
/backend — Express + Prisma API, Socket.io server
prisma.config.js — where the Prisma CLI finds the schema, the database and the seed
/prisma — schema.prisma, migrations, seed.js (the admin account only)
/seeds — world seeds: one file per ready-made campaign, created by code
/seed-data — reference JSON (species/classes/skills/weapons, ported into
src/game/data/*.js and used directly by the calculation engine,
not stored as DB rows)
/src
/game — calculations.js (the ONLY place D&D formulas live) + buildFlow.js
/middleware — auth + campaign/character authorization
/routes — auth, campaigns, characters, encounters, notes
/seeds — finds, checks and creates campaigns from the world seeds
/sockets — Socket.io room wiring
/frontend — React + Vite + TypeScript app
/docs — game rules & character-builder specs (reference material)
```