nvj-turnierplaner2/.github/copilot-instructions.md
2026-01-23 10:41:19 +01:00

5.0 KiB

NVJ Turnierplaner - AI Coding Agent Instructions

Project Overview

Volleyball tournament organizer (NVJ = Netzroller Volleyball Jugend) for managing teams, rounds, and scoring across two league types: Bundesliga and Champions League. Built with React/TypeScript.

Architecture

State Management Pattern

Single global context provider in src/context/TournamentContext.tsx:

  • TournamentProvider wraps entire app in App.tsx
  • Access via useTournament() hook - throws error if used outside provider
  • State includes: teams, rounds, field count, match results
  • Critical: Use crypto.randomUUID() for all new IDs (teams, matches, rounds)

Data Flow

  1. Teams created on Index page → stored in context
  2. generateMatches() utility distributes teams across fields/leagues
  3. Rounds track match results and waiting teams
  4. Scores calculated via point differential: pointsA = -(scoreB - scoreA), pointsB = (scoreB - scoreA)

Type System (src/types/tournament.ts)

  • League: 'bundesliga' | 'champions' - string literal types only
  • Match includes result?: MatchResult - undefined until scores entered
  • Round has completed: boolean - only one active round allowed at a time
  • TeamScore maintains pointsHistory: number[] for per-round tracking

Development Workflow

Running the App

npm run dev          # Start development server on port 8080
npm run build        # Production build
npm run build:dev    # Development mode build
npm run test         # Run Vitest once
npm run test:watch   # Watch mode for tests

Vite Configuration

  • Path alias: @/ maps to src/ (configured in vite.config.ts)
  • React deduplication: Critical for preventing hook errors - never remove from config

UI Component Conventions

shadcn/ui Pattern

  • All UI primitives in src/components/ui/ - do not edit these directly
  • Import from @/components/ui/<component>
  • Customization via Tailwind classes and variants, not component modification

Design System (src/index.css)

Custom CSS tokens (use these instead of arbitrary values):

  • card-apple - Standard card styling (rounded-2xl, shadow, border)
  • card-apple-hover - Interactive card with hover effects
  • bg-bundesliga / bg-champions - League-specific colors with matching foregrounds
  • bg-waiting / bg-field - Status colors for team/field states

Color semantics:

  • Bundesliga: Red theme (--bundesliga: 0 72% 51%)
  • Champions: Gold/yellow theme (--champions: 45 93% 47%)
  • Field: Green (--field: 142 71% 45%)
  • All have HSL definitions in CSS custom properties

Component Structure Pattern

See src/components/TournamentView.tsx for reference:

  • Extract sub-components within file for local use (WaitingTeam, LeagueSection)
  • Use typed icon props: icon: typeof Trophy instead of React.ComponentType
  • Filter round data at component level, not in context

Key Files & Responsibilities

Project-Specific Rules

  1. Never modify completed rounds - completed: true rounds are immutable
  2. Field allocation: Bundesliga and Champions always share fields evenly (±1) when both have teams
  3. Waiting teams: Odd-numbered teams in a league → last team waits (see createMatchesForLeague)
  4. Score point mapping: Differential-based, not win/loss binary
  5. Component naming: PascalCase files match export name exactly
  6. Routing: Custom routes MUST be above path="*" catch-all in App.tsx

Dependencies Notes

  • Bun runtime: Package manager is Bun (uses bun.lockb), but npm scripts work
  • React Router: v6 pattern with BrowserRouter
  • React Query: QueryClient setup in App.tsx but minimal usage currently
  • Lucide React: Icon library of choice (see imports in components)
  • Sonner + shadcn Toast: Dual toast systems - prefer Sonner for new toasts

Testing

Common Pitfalls

  • Don't destructure useTournament() before checking context existence
  • TypeScript paths require build tool awareness - always use @/ imports
  • Custom CSS utilities won't work without @layer utilities wrapper
  • Dark mode is class-based - test both light/dark themes