5.0 KiB
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
- Teams created on Index page → stored in context
generateMatches()utility distributes teams across fields/leagues- Rounds track match results and waiting teams
- 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 tosrc/(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 effectsbg-bundesliga/bg-champions- League-specific colors with matching foregroundsbg-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 Trophyinstead of React.ComponentType - Filter round data at component level, not in context
Key Files & Responsibilities
- src/utils/tournamentUtils.ts - Match generation with field distribution logic
- src/context/TournamentContext.tsx - All tournament state mutations
- src/pages/Index.tsx - Team setup interface
- src/pages/Tournament.tsx - Active tournament management
- src/components/MatchScoreInput.tsx - Score entry with point calculation
Project-Specific Rules
- Never modify completed rounds -
completed: truerounds are immutable - Field allocation: Bundesliga and Champions always share fields evenly (±1) when both have teams
- Waiting teams: Odd-numbered teams in a league → last team waits (see
createMatchesForLeague) - Score point mapping: Differential-based, not win/loss binary
- Component naming: PascalCase files match export name exactly
- 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
- Vitest + Testing Library configured (vitest.config.ts)
- Test setup in src/test/setup.ts
- Run with
npm run test:watchfor development
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 utilitieswrapper - Dark mode is class-based - test both light/dark themes