Skip to content

Latest commit

 

History

History
103 lines (69 loc) · 4.95 KB

File metadata and controls

103 lines (69 loc) · 4.95 KB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Monorepo Structure

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)

Commands

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 costs

Required 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.

Architecture

Domain

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).

Stats Pipeline (apps/web/lib/stats/)

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().

Data Flow

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)

XWS Normalization (apps/web/lib/xws.ts)

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 .).

Page Structure

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.

UI Components (apps/web/ui/)

~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.

Changesets

This repo uses Changesets for versioning. When creating a PR, always include a changeset:

pnpm changeset  # Interactive prompt to select packages and bump type

Or 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.

Static Game Data (apps/web/lib/data/)

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.