30 KiB
AGENTS.md - Codex Guide for Deathwatch Roller
This file gives Codex repo-specific context for working on Deathwatch Roller.
Prefer the live code and package.json over older docs when they disagree.
Project Snapshot
Deathwatch Roller is a Create React App + Express application for running Deathwatch tabletop RPG sessions. It includes player login and character data, dice rolling, missions, simulations, a requisition shop, bestiary, rules search, weapon references, GM tools, and user-submitted error reports.
The repository is currently a single-root JavaScript app:
- Frontend: React 18 JSX under
src/ - Backend: Express server under
database/ - Database: MariaDB via
mysql2/promise, with some legacy SQLite artifacts - Static data: JSON and generated assets under
public/,data/,database/, anddatabase/rules/ - Tests: Jest + React Testing Library for frontend unit tests; separate integration config for root-level integration tests
High-Value Paths
src/App.js- main React app, login/session state, tab wiringsrc/components/- feature UI componentssrc/components/DeathwatchRoller.jsx- combat dice roller, weapon mapping, attack rolls, damage, hit locations, history, presets, and tracker statesrc/components/SkillRoller.jsx- sheet-driven skill checks, manual d100 entry, target overrides, and fate-point roll modificationsrc/components/rollHelpers.js- shared frontend d100, degrees of success/failure, ids, and fate application helpers used by roller componentssrc/utils/diceRoller.js- mission-safe dice helpers andMISSION_ROLL_CONTEXT_KEYsrc/components/MissionTab.jsx- active mission play surface, scene reveal state, check rolling, combat state, initiative, mission roll feed, and GM progress controlssrc/components/SimulationTab.jsx- simulation report UI, run controls, difficulty/profile selection, roll feed display, and saved reportssrc/components/MissionSimTab.jsx- older/generated mission simulator UI; check current routing before extending itsrc/utils/- shared frontend utilities such as dice and XP logicsrc/tests/- Jest unit tests run by the default test configdatabase/server.js- Express backend entrypoint and route mountingdatabase/routes/- API routes for players, sessions, shop, rules, bestiary, weapons, missions, simulations, staging, and error reportsdatabase/routes/missionRoutes.js- mission CRUD, active mission selection, player-safe scene projection, active-scene patching, and shared roll feed APIsdatabase/routes/simulationRoutes.js- backend simulation engine and simulation CRUD/report APIsdatabase/mariadb.js- MariaDB pool, schema creation, schema patchingdatabase/sessionModel.js- session storage helpersdatabase/shop-helpers.js- requisition/shop business logicscripts/- import, cleanup, validation, generation, and local CI helpersdocs/- user/developer docs; some structure docs are stale and still refer to non-existentbackend/andfrontend/directories
Commands
Run commands from the repository root unless noted.
npm install
npm start
npm run server:notest
npm run test:unit
npm test
npm run build
Useful variants:
npm run server # runs tests first, then database/server.js
npm run test:integration
npm run build:fast # skips tests, then reloads PM2
./scripts/local-ci.sh
Local ports:
- Frontend dev server:
http://localhost:3000 - Backend API:
http://localhost:5000 - CRA proxy points frontend API requests at
http://localhost:5000
Environment And Runtime Notes
- Backend loads environment variables with
dotenvfrom the backend process working directory.npm run server:notestruns fromdatabase/, sodatabase/.envis relevant. - MariaDB connection defaults are hard-coded in
database/mariadb.js: host192.168.1.113, userdeathwatch, databasedeathwatch, port3307, password fromDB_PASSWORDordefaultpassword. - GM upload auth checks
GM_SECRETand falls back todefaultsecret. /api/narratecalls Ollama usingOLLAMA_BASEandNARRATOR_MODEL.- The backend can serve
build/statically when a production build exists.
Testing Guidance
-
Use
npm run test:unitfor normal frontend changes. -
Use targeted Jest commands when iterating, for example:
npm test -- src/tests/login.test.js -
Use
npm run test:integrationonly when backend/API behavior is touched and PM2/MariaDB are available. -
npm run buildruns unit tests beforereact-scripts build. -
If tests fail because MariaDB, PM2, Ollama, or local services are unavailable, report that explicitly rather than masking the failure.
Implementation Conventions
- The codebase is plain JavaScript/JSX, not TypeScript. Match the surrounding style unless a broader migration is explicitly requested.
- Prefer existing React hooks/component patterns in
src/components/. - Keep state persistence keys stable; the app uses
localStoragekeys such asdw:shop:authedPlayer,dw:shop:sessionId, anddw:shop:playerData. - API calls from the frontend generally use relative
/api/...URLs through the CRA proxy. - Preserve backend response shapes used by existing components and tests.
- Keep database writes parameterized through
mysql2APIs. - Avoid broad refactors in data import scripts unless the task is specifically about those scripts.
Dice Roller, Mission, And Simulation Notes
Dice Roller
- The main dice roller lives in
src/components/DeathwatchRoller.jsx. - Shared roller primitives live in two places:
src/components/rollHelpers.jsfor UI roller and skill roller behavior.src/utils/diceRoller.jsfor mission-safe helpers and the mission roll context storage key.
- Core roll semantics:
d100()returns 1-100.degrees(target, roll)treatsroll <= targetas success and reports Degree of Success or Degree of Failure in 10-point bands.- Skill and combat roll targets should stay clamped to sensible d100 bounds.
- Combat helpers in
DeathwatchRoller.jsxcover dice expressions, weapon normalization, RoF modes, hit counts from DoS, hit location from reversed d100, tearing/proven damage dice, and damage mitigation. - Skill rolling is delegated to
SkillRoller.jsx, which reads the logged-in player's sheet skills/characteristics, applies training modifiers, supports a manual d100 roll, and can override the target number. - Fate handling is shared by
FateControls.jsx,useFate.js, andapplyFateToTest()inrollHelpers.js. Spending fate persists throughPOST /api/players/:name/spend-fate. - Persistent browser state keys used by the roller include:
dw:presets:v3dw:history:v2dw:weapons:v3dw:tracker:v1dw:mission:rollContext
Mission Play
MissionTab.jsxis the current mission play implementation used fromApp.js.- GM users are identified in the UI with
authedPlayer === 'gm'. - GM flow:
- Load all missions with
GET /api/missions. - Load the current active mission with
GET /api/missions/active/current. - Create/update/delete missions through
POST/PUT/DELETE /api/missions. - Set the active mission with
POST /api/missions/:id/active. - Save progress and scene edits with
PUT /api/missions/:id/progress.
- Load all missions with
- Player flow:
- Load only the player-safe active scene with
GET /api/missions/active/player. - Hidden scene fields are stripped in
playerScene()indatabase/routes/missionRoutes.js. - Player mini rollers patch only the active scene through
PUT /api/missions/active/sceneso they do not overwrite the full mission.
- Load only the player-safe active scene with
- The shared mission roll feed is backed by the
mission_rollstable:- Read with
GET /api/missions/active/rolls/feed?limit=50. - Create with
POST /api/missions/rolls. - Delete with
DELETE /api/missions/rolls/:id.
- Read with
- Mission scenes may contain checks, objectives, complications, extra
challenges, combat state, reveal state, play prompts, enemies, rewards,
storyHook,secret, GM notes, and ending text. Preserve unknown scene fields when patching scenes. - Generated missions should give every scene a GM-only
storyHookthat acts as a thread toward the mission's main story. Skill check rewards are the visible triggers that reveal the hook; failures should use fail-forward consequences instead of blocking the clue. - Combat state is scene-local and includes round, initiatives, conditions, and
fear rating. Initiative rolls use
1d10 + Ag bonus; fear/check rolls use the same d100 degree helpers as the roller. - When changing mission roll behavior, verify both GM and player perspectives: the GM sees the full mission, while players only receive the active safe scene.
Simulation
SimulationTab.jsxis the current simulation report and control UI.database/routes/simulationRoutes.jscontains the backend simulation engine. It loads mission/player data, builds temporary player combat state fromtabInfo, runs scenes, and saves reports throughsimulationHelpers.- Simulation endpoints:
POST /api/simulationsruns and saves a new simulation.GET /api/simulations?limit=50lists saved simulation summaries.GET /api/simulations/:idreturns a full saved report.DELETE /api/simulations/:idremoves a saved report.
- Simulation request inputs include
mission_id,player_names,difficulty, per-playercombat_profiles, andenemy_profile. - Difficulty levels are 1-5 and affect wounds, enemy BS, check modifiers, fear, extra enemies, recovery, and max combat rounds.
- Combat profiles include
auto,balanced,ranged, andmelee; they affect weapon choice, grenade use, and enemy attack style. - The simulation engine normalizes weapons from player
tabInfo.weapons, infers ammo/clip defaults for common Deathwatch weapons, tracks ammo spend, resolves single/semi/full-auto hit counts, rolls initiative each combat round, applies conditions, performs fear tests, spends fate once when useful, and builds roll feeds/player report cards. - Saved simulation reports include result, earned XP, total rounds, total rolls,
overall success rate, combat success rate, puzzle/check success rate, scene
results, player cards, roll feed, story hooks, findings,
difficulty_level, andenemy_profile. - Because simulations use
Math.random()directly and are not seeded, tests and docs should avoid assuming deterministic exact roll output.
App Tabs
Tabs are selected in src/App.js with the tab state. Login/session state is
owned by App.js and passed to tabs as authedPlayer and sessionId where
needed. Navigation actions are logged with logUserAction().
Mission
- Component:
src/components/MissionTab.jsx - Default tab:
mission - Availability: all logged-in states, but GM and player views differ.
- Backend:
/api/missions,/api/missions/active/current,/api/missions/active/player,/api/missions/active/scene, and mission roll feed endpoints. - Notes: GM sees full mission state; players receive only the active safe scene. Preserve unknown scene fields and avoid replacing the full scene array from player-facing actions.
Dice Roller
- Component:
src/components/DeathwatchRoller.jsx - Tab key:
roller - Availability: visible to all users.
- Backend: player sheet/fate endpoints, bestiary enemy data where loaded, and mission roll context when launched from mission play.
- Notes: Depends on
SkillRoller.jsx,FateControls.jsx,useFate.js,rollHelpers.js, andsrc/utils/diceRoller.js. Keep d100/DoS behavior aligned across mission, skill, and combat rolls.
Requisition Shop
- Component:
src/components/RequisitionShop.jsx - Tab key:
shop - Availability: visible to all users; GM controls appear for
authedPlayer === 'gm'. - Backend:
GET /api/shop,POST /api/shop/purchase,GET /api/players/:name,GET /api/players,POST /api/players/gm/set-rp, andPOST /api/players/gm/set-renown. - Data source:
public/deathwatch-armoury.jsonthroughshopRoutes.js. - Notes: Purchases deduct
tabInfo.rpand append/updatetabInfo.gear. Renown gating uses the local rank order in the component.
Character Sheet
- Component:
src/components/PlayerTab.jsx - Tab key: fallback branch when no other tab matches; nav label is
Character Sheet. - Availability: visible to all users; GM edit tools are enabled only when the
logged-in user is
gm. - Backend:
GET /api/players,GET /api/players/:name,PUT /api/players/:name, avatar upload underPOST /api/players/:name/avatarif present, and GM player endpoints. - Local state: caches player data under
dw:shop:players:v1and also consumesdw:shop:playerDataas a fallback. - Notes: Character data is stored primarily in
tabInfoand includes characteristics, skills, weapons, armour, gear, wounds, fate, XP, XP spent, renown, movement, insanity, corruption, notes, and avatar/picture data. PreservetabInfoshape because the roller and simulator read it directly.
Rules
- Component:
src/components/RulesTab.jsx - Tab key:
rules - Availability: visible to all users.
- Backend:
GET /api/rules/categories,GET /api/rules/search,GET /api/rules/rule/:id, andGET /api/rules/random. - Local state: recent searches are stored as
dw:rules:recent. - Notes: Results include structured fields such as summary, examples, category, source, page, aliases, tags, and midgame priority. Keep highlighting and compact/full rendering behavior when changing rule result shapes.
Weapons
- Component:
src/components/WeaponsTab.jsx - Tab key:
weapons - Availability: visible to all users.
- Backend:
GET /api/weapons. - Data source: MariaDB weapons when available, with fallback to
public/deathwatch-armoury.json. - Notes: The tab normalizes displayed categories into ranged, melee, grenade,
armour, and other. Ranged stat strings may be parsed from semicolon-separated
fields in
stats.damage.
Error Reports
- Component:
src/components/ErrorReports.jsx - Tab key:
errors - Availability: visible to all logged-in users; GM sees all reports and can resolve/delete.
- Backend:
GET /api/errors,POST /api/errors,PUT /api/errors/:id/resolve,PUT /api/errors/:id/status, andDELETE /api/errors/:id. - Auth: requires
x-session-id; backend usesrequireSession. - Notes: Non-GM users should only see their own reports. Form submissions
default
pageUrlto the current browser path when not provided.
Bestiary
- Component:
src/components/BestiaryTab.jsx - Tab key:
bestiary - Availability: GM-only in
App.js; non-GM users see an access denied panel. - Backend:
GET /api/bestiary/full,POST /api/bestiary/reload, andGET /api/bestiary/enemiesfor dice roller enemy format. - Local state: caches entries under
dw:enemies:v1; DB-down warning dismissal usesdw:warning-dismiss-until:v1. - Data source: MariaDB bestiary rows with fallback to
public/deathwatch-bestiary-extracted.json. - Notes:
normalizeEntry()handles multiple imported statblock shapes. Keep fallback/cache behavior intact so the tab remains useful when the DB is down.
Player Management
- Component:
src/components/PlayerManagement.jsx - Tab key:
players - Availability: GM-only nav item. The component also expects GM context.
- Backend:
GET /api/players,POST /api/players/gm/add-or-update,POST /api/players/gm/set-xp,POST /api/players/gm/set-xp-spent,POST /api/players/gm/set-rp,POST /api/players/gm/set-renown,POST /api/players/gm/reset-password, andDELETE /api/players/gm/delete/:name. - Auth: sends
x-session-idandx-gm-secretwhere available; backend GM secret defaults are defined inplayerRoutes.js. - Notes: Bulk XP/RP operations update each player in sequence. The component
expects player economic and progression values in
tabInfo.
GM Kit
- Component:
src/components/GMKit.jsx - Tab key:
gmkit - Availability: GM-only nav item and component-level access check.
- Backend: none for the current table UI;
App.jsseparately usesGET /api/gmkit/listto choose the players-tab background. - Notes: Current GM Kit is static reference tables inside the component:
difficulty modifiers, hit locations, combat actions, weapons, armour,
critical hits, weapon qualities, cover, renown, and related GM references.
There are older
GMKit_old.jsxandGMKit_new.jsxfiles; check routing before editing them.
Simulation Lab
- Component:
src/components/SimulationTab.jsx - Tab key:
simulation - Availability: GM-only nav item in
App.js. - Backend:
/api/simulationsendpoints and mission/player data loaded by the backend simulation route. - Notes: Reports include roll feeds, scene logs, player report cards, story hooks, findings, difficulty, and enemy profile. Simulation output is non-deterministic.
External Utility Pages
public/cards.htmlis linked from nav asKortand opens in a new tab. It is a printable card-sheet view and fetches app/static data directly from the served public site.public/print.htmlis linked from nav asPrintand opens in a new tab. It is a printable quick-reference sheet.- These are not React tabs. They are static public pages served by CRA/dev server or by Express static serving in production.
Deathwatch RPG Domain Notes
Use these notes when changing the app's roller, mission, simulation, shop, rules, bestiary, and character-sheet flows. They are summarized from the local rules database and app data, not copied from rulebook text. Do not paste long rulebook passages into UI or docs; link/search the local rules DB and summarize mechanics in original wording.
Source Data In This Repo
- Rules index:
database/rules/rules-database.json- Categories include
actions,combat,damage,conditions,requisition,renown,cohesion,squad_mode,psychic,hordes,gm_tables,mission,skills,talents, andtraits.
- Categories include
- Skill import/reference data:
database/deathwatch_skills_p94_107.csv - Armoury/shop data:
public/deathwatch-armoury.json- Major groups include ranged weapons, melee weapons, grenades, other weapons, power armour, helmets, carapace/natural/primitive/xenos armour, shields, and other armour.
- Bestiary data:
public/deathwatch-bestiary-extracted.jsonanddatabase/deathwatch-bestiary-extracted.json- Entries generally include profile, movement, wounds, toughness, skills, talents, traits, armour, book, page, and snippets.
- Backend may load rules, weapons, and bestiary from MariaDB first, then fall back to the JSON files above.
Core Resolution Model
- Deathwatch uses percentile tests: roll
d100and succeed when the roll is equal to or under the effective target. - Effective target is normally characteristic + skill/training + situational modifiers. The app generally clamps practical targets to d100 bounds.
- Degrees of Success/Failure are 10-point bands from the target/roll margin. The app's shared helper returns 1 base degree plus one per full 10 points.
- Basic skills can be attempted broadly; untrained advanced skills should be treated as unavailable or heavily constrained unless the app explicitly allows an override.
- Common characteristics:
WSWeapon Skill for melee attacks and parries.BSBallistic Skill for ranged attacks.S,T,Ag,Int,Per,Wp,Felfor strength, toughness, agility, intelligence, perception, willpower, and fellowship checks.
- When making UI for tests, expose the final target, roll, success/failure, DoS/DoF, and the source of modifiers. This is more useful at the table than only showing pass/fail.
Combat Flow
- Combat is round-based and action-based. Common action concepts include Aim, Charge, Standard Attack, Semi-Auto Burst, Full Auto Burst, Overwatch, Suppressing Fire, Dodge, Parry, Ready, Reload, Move, Run, and Disengage.
- Initiative is relevant to combat order. In the simulator, each combat round
currently rolls player
Agility Bonus + d10and enemyagBonus + d10, then resolves actors from highest to lowest. - Attack flow for app purposes:
- Choose WS or BS based on melee/ranged attack.
- Apply attack-mode and situation modifiers.
- Roll d100 against target.
- On a hit, derive hit count from fire mode and DoS.
- Determine hit location from the reversed d100 attack roll where needed.
- Roll damage, apply weapon qualities such as Tearing/Proven where supported.
- Reduce damage by armour and Toughness Bonus/Penetration handling as the app model supports.
- Track wounds, critical damage threshold, defeat/downed status, and notable events.
- Semi-auto and full-auto are not just labels. They change the attack modifier and how additional hits scale with DoS. Keep roller and simulator hit-count formulas aligned.
- Dodge and Parry are reactions that negate hits when allowed. Dodge is usually the generic ranged/melee avoidance reaction; Parry is melee and WS-based.
- Suppressing fire and pinning matter in Deathwatch combat. Pinned targets are constrained and should be represented as a condition when simulation or mission play needs battlefield pressure.
- Righteous Fury is a special high-damage/exploding-damage style event on successful attacks. The simulator currently records "critical hit"/hero moments for high DoS, while the roller has damage dice mechanics; be explicit if changing this behavior to match a stricter table interpretation.
Weapons, Damage, Armour, And Qualities
- Weapon data often appears as compact strings like range, RoF, damage, penetration, clip, reload, and qualities. Prefer structured parsing helpers over ad hoc display-only splitting when adding behavior.
- Damage expressions use dice notation such as
1d10+9,2d10+2, or3d10+4, with a damage type marker in source data (E,I,R,X, etc.) for energy, impact, rending, explosive, and related categories. - Important weapon qualities represented in app data include Tearing, Reliable, Accurate, Blast, Flame, Power Field, Razor Sharp, Unbalanced, Unwieldy, Volatile, Scatter, Storm, Smoke, Toxic, and others.
- Tearing usually means roll extra damage dice and keep the better result for supported dice. Proven sets a floor on supported damage dice. Only apply qualities that the code explicitly models.
- Armour can be whole-body or location-based. Bestiary and armoury entries may use different shapes for protection values, so normalize before using in combat calculations.
- Penetration should reduce armour effectiveness, not Toughness, unless a local helper intentionally abstracts damage.
Missions, Requisition, Renown, And Economy
- Deathwatch missions are framed around a kill-team selecting mission gear, entering an operation, resolving scenes, earning XP/renown, and returning equipment.
- Requisition Points are mission equipment budget, not ordinary money. The shop
stores purchases as gear and deducts
tabInfo.rp. - Renown gates access to more prestigious or restricted equipment. The app rank
order is
None,Respected,Distinguished,Famed,Hero; keep that order consistent in shop and player-management flows. - Mission scenes in this app can include objectives, complications, checks, enemies, combat state, reveal state, extra challenges, rewards, and ending text.
- Good mission UI should separate GM-only information from player-safe scene
information. The backend
playerScene()projection strips hidden/GM fields.
Skills And Scene Checks
- Useful scene-check skills from the local skill data include Awareness, Command, Tactics, Tech-Use, Medicae, Scrutiny, Search, Logic, Inquiry, Intimidate, Demolition, Tracking, Survival, Security, Psyniscience, and relevant Lore skills.
- Tactics is an Intelligence skill and should be used for battlefield doctrine, priority targets, ambush reads, deployments, or tactical approach. It should not automatically grant Squad Mode abilities or Cohesion benefits unless a mission rule explicitly says so.
- Awareness/Search/Tracking are good for threat and clue discovery.
- Tech-Use/Security/Demolition are good for machines, locks, traps, explosives, and sabotage.
- Medicae/Chem-Use are good for injuries, toxins, infection, biology, and field treatment.
- Command/Charm/Intimidate/Scrutiny/Deceive support social or morale scenes.
- Puzzle scenes should usually produce multiple checks with assigned best-fit players, visible targets, complications on high DoF, and rewards on success.
Cohesion, Squad Mode, Solo Mode, And Fate
- Cohesion is the kill-team resource around coordination and Squad Mode. Existing app coverage is mostly reference/rules-search level; do not invent persistent Cohesion behavior without adding explicit state and tests.
- Squad Mode and Solo Mode are distinct from ordinary skill checks. A successful Tactics or Command roll should not silently toggle Squad Mode.
- Fate points can be spent to improve outcomes. In this app:
- The roller exposes re-roll, +10, and +DoS style fate actions.
useFate.jsreads and persists fate through player endpoints.- The simulator may spend fate once on severe failed checks.
- Keep fate changes persistent and visible because players track remaining fate across scenes/sessions.
Psychic Powers And Warp Risk
- Psychic rules involve Focus Power tests, Psy Rating, and risk modes such as safer/fettered use versus riskier high-output use.
- Psychic Phenomena and Perils of the Warp are significant consequences. If adding psychic automation, model risk and output separately and expose the roll trail clearly.
- Avoid treating psychic powers as generic skills unless the feature explicitly asks for a simplified helper.
Hordes And Large Enemy Groups
- Hordes are a special combat abstraction for many lesser enemies. They should not be treated as a single normal NPC unless the app is intentionally using a simplified profile.
- Horde-relevant UI should track magnitude/remaining threat, area effects, full-auto/multi-hit attacks, Blast, Flame, and morale/breaking behavior.
- Current simulation uses simplified enemy lists and wounds, not a full horde engine.
Bestiary And Enemy Modeling
- Bestiary entries vary by source and import quality. Normalize names, profile stats, wounds, armour, movement, talents, traits, and attacks before using them in roller/simulation logic.
- Common enemy themes in app code include Tyranids, Chaos, Xenos/Tau, Orks, and servitor/Imperial profiles.
- For combat simulation, prefer clear approximations and visible findings over opaque precision. If a stat is missing, surface the fallback rather than pretending it came from the book.
Simulation Design Guidance
- Simulation is a balance/design tool, not an authoritative rules engine.
- Keep simulated rolls categorized. Current categories include:
combatfor attacks and combat-scene tactical checks.puzzlefor non-combat scene checks.fearfor fear tests.
- Reports should show overall success %, combat %, puzzle/check %, XP, rounds, roll count, scene results, player report cards, ammo/fate use, conditions, initiative events, and findings.
- Findings are scripted threshold notes, not AI. They do not use OpenAI/Ollama tokens unless a future feature explicitly calls an AI endpoint.
- Story hooks are scripted from mission scene data. Mission generation stores a
GM-only
storyHook/secreton each scene; simulation reports which checks or combat outcomes revealed, partially revealed, or escalated those hooks. - Scripted findings should give the GM actionable mission edits grounded in the rules model: reduce or increase enemy pressure, add cover/Aim/Dodge/Parry prompts, add non-attack combat objectives, tune puzzle difficulty, allow assists/alternate skills, prevent single-roll clue bottlenecks, add recovery beats for conditions/fear, and match player roles to checks.
- Evaluate combat and puzzle/skill pressure separately. A good sim report should make it clear whether the mission is too lethal, too easy, too attack-only, too clue-blocked, or mismatched to the party's stats.
- Because simulation uses
Math.random()and is unseeded, never make exact roll totals a test expectation. Test shape, categories, persistence, and visible report fields instead.
Copyright And Wording
- The repo contains local summaries, OCR, PDFs, and extracted data for gameplay support. When writing UI/help/docs, use short summaries in original wording.
- Do not reproduce long rulebook sections, tables, or copyrighted passages in new docs or UI. Prefer links/search into local rule entries and cite source title/page metadata where helpful.
- If a requested feature needs exact rules text, build a lookup/display path from the existing rules database instead of embedding copied text in code.
API Surface
Mounted API prefixes in database/server.js include:
/api/players/api/sessions/api/shop/api/rules/api/weapons/api/bestiary/api/rules/staging/api/missions/api/simulations/api/errors/api/gmkit/list/api/gmkit/upload/api/copy-bestiary/api/narrate
Static serving includes /gmkit, /weapon-images, and /avatars.
Files To Treat Carefully
- Do not commit or churn runtime logs such as
database/backend.logordatabase/server.log. - Do not overwrite database files, backups, generated JSON, PDFs, OCR output, or imported rulebook data unless the user specifically asks for data work.
public/anddatabase/contain generated/reference JSON used by the app; update paired files intentionally when scripts require it.- There may be unrelated local changes. Inspect
git status --shortbefore editing and avoid reverting user work.
Documentation Notes
README.mdandDEVELOPMENT_GUIDE.mdare useful, but several docs underdocs/andCLAUDE.mdmention an older splitbackend/+frontend/structure. The current live structure is root CRA frontend plusdatabase/server.jsbackend.- When updating docs, prefer correcting stale structure references rather than propagating them.