This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
This is a pnpm monorepo managed by Turborepo. The Next.js app lives in apps/web/.
├── apps/web/ # Next.js app (pattern-analyzer.app)
├── packages/xws/ # @pattern-analyzer/xws (npm published)
├── turbo.json # Turborepo task config
├── pnpm-workspace.yaml
└── package.json # Root (turbo + prettier)
Root-level commands run via Turborepo across all workspaces:
pnpm dev # Start development server
pnpm build # Production build
pnpm lint # ESLint
pnpm format # Prettier (auto-sorts Tailwind classes via prettier-plugin-tailwindcss)
pnpm typecheck # tsc --noEmit
pnpm test # Jest (all tests)
pnpm test -- --testPathPattern=xws # Run a single test file by pattern
pnpm clean # Remove .next build output
# Database (run from apps/web)
pnpm --filter pattern-analyzer.app db:setup # Full DB rebuild from Listfortress (destructive)
pnpm --filter pattern-analyzer.app db:sync # Incremental sync from Listfortress
# Data updates (run from apps/web)
pnpm --filter pattern-analyzer.app update:xwing # Refresh apps/web/lib/data/display-values.json etc. from xwing-data2
pnpm --filter pattern-analyzer.app update:yasb # Refresh apps/web/lib/data/yasb.json point costsRequired env vars (apps/web/.env.local): DATABASE_HOST, DATABASE_USERNAME, DATABASE_PASSWORD, NEXT_PUBLIC_APP_URL or NEXT_PUBLIC_VERCEL_URL, SYNC_TOKEN.
Note: apps/web/next.config.js sets ignoreBuildErrors: true to work around a cmdk source path alias — TypeScript errors won't fail next build, so always run pnpm typecheck separately.
X-Wing Miniatures Game tournament analytics app. Core domain concepts: factions (7: rebelalliance, galacticempire, scumandvillainy, resistance, firstorder, galacticrepublic, separatistalliance), ships, pilots, upgrades, and squads in XWS format. Tournament data is sourced from Listfortress (DB), Longshanks, and Rollbetter (live proxy).
Plugin architecture for single-pass aggregation over all squads. setup.ts takes an array of module factories; each module (e.g. faction.ts, pilot.ts, upgrade.ts) implements StatModule<T> with hooks squad, xws, pilot, ship, upgrade. The pipeline calls each hook while iterating squads, then calls get() on each module for final results. Compose new stat views by creating a module and passing it to setup().
Listfortress API
→ apps/web/lib/db/sync.ts (incremental, via POST /api/sync — called 4x/day by GitHub Actions)
→ MySQL (Kysely: apps/web/lib/db/{db,squads,tournaments,system}.ts)
→ apps/web/lib/stats/setup.ts (pipeline) + apps/web/lib/stats/module/*.ts
→ apps/web/app/(stats)/*/page.tsx (React Server Components)
→ apps/web/ui/stats/*.tsx (@nivo charts)
Longshanks / Rollbetter APIs
→ apps/web/app/api/{longshanks,rollbetter}/ (proxy routes)
→ apps/web/app/tournament/[vendor]/[id]/ (live tournament view)
Critical: tournament platforms export inconsistent XWS. normalize() applies a PILOT_ID_MAP lookup to fix known spelling errors across platforms. toXWS() parses single-quoted JSON strings (Launch Bay Next / Longshanks format). toCompositionId() produces a canonical squad fingerprint (sorted ship IDs joined by .).
All stats pages follow: page.tsx (server, fetches data) + content.tsx (client, URL-param filters) + loading.tsx (Suspense skeleton). URL params drive filtering; see apps/web/ui/params/ and apps/web/lib/utils/params.utils.ts.
~50 components, barrel-exported from apps/web/ui/index.ts. Built on Radix UI primitives. Charts via @nivo. cmdk (command palette) is imported from source via a tsconfig.json path alias pointing to node_modules/cmdk/cmdk/src — this is why ignoreBuildErrors is needed. Ship icons use a custom font (xwing-miniatures-ships.ttf); faction icons are inline SVG in apps/web/ui/faction-icon.tsx.
This repo uses Changesets for versioning. When creating a PR, always include a changeset:
pnpm changeset # Interactive prompt to select packages and bump typeOr create a changeset file manually in .changeset/ (e.g. .changeset/my-change.md):
---
'pattern-analyzer.app': patch
---
Description of the change.Use patch for fixes/small changes, minor for new features, major for breaking changes. Include all affected packages.
JSON files generated by update:xwing and update:yasb scripts. apps/web/lib/get-value.ts provides lookups (human-readable names, icons) from these files. Do not hand-edit these files.