Skip to content

Latest commit

 

History

History
91 lines (72 loc) · 4.83 KB

File metadata and controls

91 lines (72 loc) · 4.83 KB

Claude Code Context — Reward Tracking

Project overview

A full-stack Next.js + PostgreSQL app for Pathfinder 2E Game Masters to track party treasure progress against the PF2e rulebook benchmark (Table 10-9). GMs record per-session rewards; the app compares cumulative totals against expected wealth-by-level with variable party size.

Tech stack

  • Framework: Next.js 14 (App Router)
  • Language: TypeScript (strict mode)
  • Database: PostgreSQL via Prisma ORM
  • Auth: NextAuth.js
  • Testing: Jest + React Testing Library (unit), Playwright (e2e)
  • Dev infrastructure: Docker Compose (app + db)
  • Linting/formatting: ESLint (Next.js config) + Prettier
  • Git hooks: Husky + lint-staged (enforce formatting + tests on commit)

Common commands

npm run dev          # start dev server
npm test             # run unit tests (jest)
npm run test:e2e     # run e2e tests (playwright)
npm run lint         # eslint
npm run typecheck    # tsc --noEmit
npm run format       # prettier --write .
npm run migrate      # prisma migrate dev
npm run db:seed      # prisma db seed
docker compose up --build  # start full stack (app + postgres)

Project structure

app/              # Next.js App Router pages/routes
  campaigns/
  sessions/
  auth/
components/       # reusable UI components
lib/              # business logic + DB access
  auth/
  db/
  model/
prisma/
  schema.prisma   # source of truth for data model
  migrations/
tests/
  unit/
  integration/
  e2e/

Data model (prisma/schema.prisma)

  • User — authenticated users (email + password)
  • Campaign — owns startLevel, currentLevel, partySize, and a materialized reward balance: coinsOwedGp: Float, permanentsOwed: Json, consumablesOwed: Json
  • CampaignMemberremoved; party size is a count on Campaign. Only GMs (authenticated users) exist.
  • CampaignEvent — immutable log of events that add to rewards owed: CAMPAIGN_CREATED, LEVEL_UP, PARTY_SIZE_CHANGE. Stores typed nullable fields (fromLevel, toLevel, fromPartySize, toPartySize) rather than a JSON payload.
  • Session — an editable play session (date, notes). No level or party size — those live on Campaign.
  • Reward — a reward distributed in a session. category: COINS | PERMANENT | CONSUMABLE. For COINS: valueGp is set, itemLevel is null. For PERMANENT/CONSUMABLE: itemLevel and quantity are set, valueGp is null.

Balance design

The reward balance on Campaign is a materialized cache — delta-updated on writes, but fully recomputable from scratch at any time by replaying all CampaignEvent records and subtracting all Session rewards.

  • permanentsOwed / consumablesOwed JSON shape: [{ level: number, qty: number }, ...]
  • coinsOwedGp is a flat float (coins have no item level)
  • RewardCategory: COINS, PERMANENT (lasting items), CONSUMABLE (temporary/one-use items)

Interaction style

  • Questions are not change requests. If the user asks about code, explain or discuss — do not modify anything unless a change is explicitly requested.
  • State assumptions before acting on non-trivial changes. Briefly describe what you're about to do and why before writing code, so the user can redirect if the interpretation is wrong. Trivial changes (simple renames, formatting fixes) can proceed without this.
  • Push back when there's a genuine reason. If a request has a meaningful tradeoff, a better alternative, or conflicts with something already established, say so before proceeding. A concern stated is enough — "proceed" or similar is sufficient to continue.
  • Clarifying questions on genuine ambiguity only. Don't ask questions on routine tasks. Do ask when the right approach depends on a decision that hasn't been made yet.
  • Connect explanations to backend/Rails concepts where there's a useful analogy — scoped to explanations only, not implementation choices, as Rails patterns don't always map cleanly to Next.js.

Development approach

  • TDD by default: write failing tests first, then implement (Red → Green → Refactor)
  • Test conventions: follow the patterns in TESTING.md — nested describe/beforeEach structure and factory usage
  • All new features belong to a feature/<short-description> branch
  • Commit convention: feat, fix, chore, test prefixes
  • Prisma transactions for any multi-step DB operations
  • All authenticated users are GMs. Auth check: the requesting user must own the campaign (created it).

Domain knowledge

  • PF2e Table 10-9 defines expected treasure per level per player. The benchmark scales with party size — always factor partySize when comparing session rewards to expected values.
  • RewardCategory: COINS, PERMANENT (lasting items), CONSUMABLE (temporary/one-use items)
  • A campaign is owned by the GM who created it; no other user roles exist