feat: initial tournament manager implementation #1

Open
tournament-manager-bot wants to merge 38 commits from tournament-manager-bot/tournament-manager:main into main
First-time contributor

Complete tournament management system with:

  • Single and double elimination brackets
  • Team management
  • Match scoring and progression
  • SQLite persistence
  • Web UI with templates
  • PWA support

See README.md and docs/architecture.md for details.

Complete tournament management system with: - Single and double elimination brackets - Team management - Match scoring and progression - SQLite persistence - Web UI with templates - PWA support See README.md and docs/architecture.md for details.
- Tournament: id, title, date, sport, type, status
- Team: id, tournament_id, name, seed
- Match: id, tournament_id, round, position, date_time, location, winner_team_id, next_match_id
- MatchTeam: match_id, team_id, score (join table)
- Player: id, first_name, last_name, gender, birth_date, location
- TeamPlayer: team_id, player_id (join table)

Updated UI to support new model with sport/date/format fields.
- New /tournament/edit-result endpoint to update scores
- Shows Edit button only on completed matches with 2+ teams (not byes)
- Handles winner changes by cascading updates through bracket
- Mobile-friendly inputs with proper touch targets and numeric keyboard
- Add drag-and-drop reordering for team seeding (mobile-friendly with SortableJS)
- Display team seeds in bracket matches
- Fix bracket alignment so matches center between feeder matches
- Add BYE labels for bye matches
- Replace inline edit/save buttons with click-to-open match dialog
- Add unit tests for bracket seeding and progression
- Consistent match heights for proper alignment across all rounds
- Add teams_per_match column to tournaments table (2-8 teams supported)
- Add sport presets with default team counts:
  - 2-team: Soccer, Basketball, Volleyball, Ultimate, Pickleball,
    Ping Pong, Badminton, Chess, Pool/Billiards
  - 4-team: Dutch Blitz, Otrio
  - Custom option for manual configuration
- Update bracket generation to handle multi-team matches
- Center the create tournament form and edit match dialog
- Fix HTMX updates so Generate Bracket button appears without refresh
- Dynamic match box sizing based on teams per match
- Add web app manifest with app name, icons, and display settings
- Add service worker for offline caching (network-first strategy)
- Add 192x192 and 512x512 app icons (trophy on blue gradient)
- Serve service worker from root path for proper scope coverage
- Add PWA meta tags (theme-color, apple-mobile-web-app-*)
- Add requirePOST middleware to eliminate 9 duplicate method checks
- Add formInt64 helper for parsing form values (simplifies 11 occurrences)
- Add scanTournamentRow to consolidate tournament row scanning
- Add parseMatchScores/updateMatchScores/updateTournamentStatus helpers
- Add renderBracket/renderTeamList/clearTournamentBracket helpers
- Add tournamentTypeLabel template function for type display
- Remove unused standardBracketPositions function
- Remove unused participant_list.html template
- Code reduced from 958 to 903 lines
tournament-manager-bot changed title from Initial tournament manager implementation to feat: initial tournament manager implementation 2025-12-29 07:13:52 -05:00
- Add consistent height (2.25rem) for all standard buttons
- Add btn-lg (2.75rem) and btn-icon (square 1.75rem) variants
- Standardize input/select heights to match button heights
- Convert dialog buttons to use standard btn classes
- Change Delete button to use btn-danger instead of inline style
- Replace inline styles in new tournament form with CSS classes
- Use btn-icon for team remove buttons
- Add focus styles to dialog inputs
Remove duplicate .team-list, .add-team-form styles from tournament.html
and consolidate them in team_list.html where the markup lives.
Move base styles, buttons, form elements, cards, badges, and navigation
from inline <style> in base.html to a separate CSS file for better
caching and maintainability.
Use negative margins to break the bracket container out of the
page container padding on mobile, allowing the bracket to scroll
all the way to the screen edges.
Large brackets need edge-to-edge scrolling on all screen sizes,
not just mobile. A 256-team bracket exceeds any reasonable
desktop width.
- Add standardBracketPositions() function for proper tournament seeding
- Seed 1 now plays seed N, seed 2 plays seed N-1, etc.
- Top seeds only meet in later rounds (1 vs 2 in finals)
- Update generateSingleElimination to use proper seeding for 2-team matches

New tests added:
- TestStandardBracketPositionsLargeBrackets (32-512 teams)
- TestSeedSumProperty (seeds in each match sum to N+1)
- TestAllSeedsPresent (every seed appears exactly once)
- TestEdgeCases (0, 1, 2 team brackets)
- TestSeed2Path (verify seed 2's path through bracket)
- TestQuarterfinalsMatchups (8 and 16 team brackets)
- TestTopSeedsOnOppositeSides (seeds 1 & 2 in different halves)
- TestTopFourSeedsInDifferentQuarters
- TestMatchupConsistency (1 vs 2 always in finals)
- TestSpecificMatchups32Teams (exact first-round matchups)
- TestBracketSymmetry
- TestRoundOfMeetings (when specific seeds first meet)
- Fix bracket generation to create correct number of rounds for bracket size
- 258 teams now creates 512-bracket with 9 rounds and 256 first-round matches
- Byes correctly assigned to top seeds
- Seed 255 vs 258 now correctly feeds into seed 2's bracket region

Added tests:
- TestNonPowerOfTwoSeeding (3, 5, 7, 258 teams)
- TestByeDistribution (verifies byes go to top seeds)
- Test258TeamBracketProgression (verifies 255v258 winner meets seed 2)
These tests would have caught the 258-team bug. They test:
- TestGenerateBracketMatchCount: verifies correct matches per round
  for 4, 8, 16, 3, 5, 7, 9, and 258 teams
- TestGenerateBracketTeamPlacement: verifies teams placed in correct
  matches with proper seeding
- TestGenerateBracketByeAdvancement: verifies bye teams auto-advance
- TestGenerateBracketNextMatchConnections: verifies match linking
- TestGenerateBracket258Teams: specific test for the reported bug
  - 511 total matches (512-bracket)
  - 256 first-round matches
  - Seed 255 vs 258 match exists
  - Seed 2 gets bye and advances
  - 255v258 winner feeds into seed 2's round 2 match
Document lessons learned from the 258-team bracket bug:
- Unit tests alone are insufficient
- Always write integration tests with database
- Key edge cases to test (non-power-of-2 teams, bracket structure, seeding, byes)
- Integration test pattern with setupTestDB helper
Extended bracket alignment CSS to support larger tournaments:
- Round 7: 63 unit gap, 31.5 unit padding (64-team semi-finals)
- Round 8: 127 unit gap, 63.5 unit padding (128-team finals)
- Round 9: 255 unit gap, 127.5 unit padding (256-team finals)
- Round 10: 511 unit gap, 255.5 unit padding (512-team finals)

Supports brackets up to 1024 teams.
- Add MaxTeamsPerTournament constant (512)
- Validate team count in handleAddTeam, return 400 if at limit
- Update team list header to show count/limit (e.g., 'Teams (5/512)')
- Hide add form and show warning when limit reached

512 teams = 9 rounds, which is the practical limit for bracket visualization.
Document the exact enum values to use when creating test data
via curl or direct DB operations. Prevents mistakes like using
'single_elim' instead of 'single_elimination'.
- Add Matches view tab that shows upcoming and completed matches
- Upcoming matches sorted by round then position
- Completed matches sorted by most recent first (by match number)
- Click matches to edit scores in dialog
- View toggle preserves state when editing matches
- Shows round name and match number for each match
- Winners highlighted in completed matches
- Add sequential match numbers displayed to left of each match
- Add match number to edit match dialog title
- Add visual L-shaped connector lines between matches using SVG
- Add opaque background to match numbers for better visibility
- Add integration tests for match numbering feature
- Update test schema to include date_time and location fields

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Change background from dark (#0f172a) to slate (#334155)
- Increase border-radius for more prominent rounded corners
- Update text color for better contrast
- Center align text in the pill-shaped background

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Use scrollWidth/scrollHeight instead of getBoundingClientRect()
- Ensures SVG covers full scrollable bracket area
- Fixes missing lines in last 3 rounds of 258-team tournament

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Add scroll offsets to position calculations
- Set explicit SVG dimensions to match scrollable bracket
- Fixes alignment issues and slow loading
- Lines now correctly positioned when bracket is scrolled

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This pull request can be merged automatically.
You are not authorized to merge this pull request.
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u main:tournament-manager-bot-main
git switch tournament-manager-bot-main

Merge

Merge the changes and update on Forgejo.
git switch main
git merge --no-ff tournament-manager-bot-main
git switch tournament-manager-bot-main
git rebase main
git switch main
git merge --ff-only tournament-manager-bot-main
git switch tournament-manager-bot-main
git rebase main
git switch main
git merge --no-ff tournament-manager-bot-main
git switch main
git merge --squash tournament-manager-bot-main
git switch main
git merge --ff-only tournament-manager-bot-main
git switch main
git merge tournament-manager-bot-main
git push origin main
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
kwila/tournament-manager!1
No description provided.