Skip to content

feat: support multiple bracket formats and implement round robin - #164

Merged
Dejmenek merged 25 commits into
mainfrom
feat/146-support-multiple-bracket-formats-groundwork-round-robin-implementation
Sep 28, 2026
Merged

Dejmenek merged 25 commits into
mainfrom
feat/146-support-multiple-bracket-formats-groundwork-round-robin-implementation

Conversation

@Dejmenek

Copy link
Copy Markdown
Owner

Summary

Implements Round Robin tournaments, including format-aware bracket generation, match handling, standings, and participant withdrawal, with full test coverage and documentation.

Changes

  • Adds TournamentFormat enum, Format field, and format-aware validation to Tournament and related models.
  • Introduces strategy abstractions (IBracketGenerationStrategy, IBracketCompletionStrategy) and implements RoundRobinBracketStrategy and RoundRobinCompletionStrategy.
  • Updates match logic to support draws (MatchStatus.Drawn), nullable winnerId, and format-specific validation.
  • Adds standings computation and exposes standings on Bracket.
  • Implements WithdrawParticipant mutation for Round Robin
  • Adds comprehensive unit and integration tests
  • Adds documentation using spec and ADR.

Added a new Drawn value to the MatchStatus enum in TournamentAPI.Data.Models to represent matches that end in a draw.
Introduced TournamentFormat enum with SingleElimination and RoundRobin values. Added Format property to Tournament class, defaulting to SingleElimination, to specify tournament format.
The CreateTournamentInput record now includes an optional TournamentFormat property named Format, defaulting to null. This enables specifying a tournament format during creation without making it mandatory.
Added error codes/builders for draw validation. Updated Play and CorrectMatchResult to accept nullable winnerId and set status to Drawn. Added validation for allowed formats and equal scores on draws. Refactored validation order for draw rules. Updated ValidateMatchNotPlayed for Drawn status.
- MatchCorrectionService.ApplyCorrection now takes allowCascade to control cascading corrections.
- BracketCompletionService replaced with IBracketCompletionStrategy collection; strategy selected by tournament format.
- allowCascade set to true only for SingleElimination tournaments.
- bracketCompletionService.SyncChampionAsync calls replaced with completionStrategy.SyncCompletionAsync.
Introduced StandingsEntry, StandingsDataLoaders, StandingsLookupService, and StandingsResolvers to support standings for Bracket. StandingsService computes points, wins, draws, losses, rank, matches played/remaining, and applies head-to-head tiebreakers for round-robin tournaments.
Refactored bracket generation and completion to use IBracketGenerationStrategy and IBracketCompletionStrategy interfaces, enabling support for multiple tournament formats. Implemented RoundRobinBracketStrategy and RoundRobinCompletionStrategy for round-robin tournaments. Renamed and adapted single elimination services to strategy implementations. Updated BracketMutations to resolve strategies by format, improving extensibility and separation of concerns.
Added Bracket.RoundAdvancementNotSupportedForFormat error code and generator. Implemented ValidateFormatSupportsRoundAdvancement to restrict round advancement to SingleElimination formats. Integrated validation into BracketMutations to block unsupported operations.
- Added test to verify round-robin bracket generation with odd participants creates correct matches and byes.
- Added test to ensure advancing round in round-robin returns "format not supported" error.
- Round-robin: Accepts draw with null winnerId and equal scores.
- Round-robin: Rejects null winnerId with unequal scores, returns error.
- Single elimination: Rejects null winnerId regardless of scores, returns error.
Added StandingsQueryTests to verify standings and champion.
Covers round-robin tournament creation, match play, and
asserts correct standings in both in-progress and completed
states, including points, wins, matches, and champion.
Added four integration tests to TournamentMutationTests:
- Verified default format is single elimination if unspecified.
- Tested organizer and participant withdrawal, ensuring forfeits and removal.
- Confirmed unrelated users cannot withdraw others (auth error).
Covers creation defaults, withdrawal scenarios, and authorization.
…ponse model, mutation and query examples

- Added nullable Format to TournamentNode for tournament format.
- Extended BracketNode with nullable Standings (list of StandingEntryNode).
- Introduced StandingEntryNode for participant standings (wins, draws, losses, points, rank, matches played/remaining).
- Added WithdrawParticipantResponse and WithdrawParticipantResult classes for withdrawal modeling.
- Added WithdrawParticipant mutation to TournamentMutations.
- Added CreateTournamentWithFormatReturn mutation to return format on creation.
- Added GetByIdWithBracketStandings query to fetch tournament with bracket standings.
Added StandingsServiceTests to verify standings calculation, including points, wins, draws, losses, matches played, matches remaining, and ranking. Covered tie-breaking by head-to-head, shared ranks for unresolved ties, and correct handling of bye matches as wins. Used diverse match scenarios to ensure ComputeStandings behaves as expected.
Added RoundRobinBracketStrategyTests to verify bracket creation for even/odd participants, unique pairings, correct bye handling, and initial match status and references.
Added unit tests to BracketMutationValidationsTests, MatchValidationsTests, and TournamentValidationsTests. Covered participant count validation, format support for round advancement and withdrawal, draw handling in matches, and authorization for participant withdrawal. Tests assert correct error codes and null results for valid and invalid cases across formats and match statuses.
…rawal, unsupported format, bracket requirements and participant not found
Added WithdrawParticipant mutation enabling authorized users to withdraw a participant from a tournament. Includes validation checks, updates scheduled matches, removes the participant, syncs bracket completion, and persists changes. Introduced WithdrawParticipantInput record for input parameters.
Ensures Tournament.Format is assigned on creation, defaulting to SingleElimination if not provided
Replaces direct BracketService/BracketCompletionService registration with specific strategy implementations for IBracketGenerationStrategy and IBracketCompletionStrategy, enabling multiple strategies via DI. Adds StandingsService and StandingsLookupService to the container for standings-related functionality.
…erSchemaTests

Replaces direct BracketService registrations with strategy-based registrations for SingleElimination and RoundRobin bracket generation and completion. Adds StandingsService and StandingsLookupService to DI for testing. Supports extensibility and improved test coverage.
…Strategy

BracketServiceTests now uses SingleEliminationBracketStrategy with a NullLogger, shifting the test focus from BracketService to the strategy class.
Renamed the test to LogoutUser_ConcurrentRevoke_LeavesNoActiveTokens. Updated logic to:
- Collect all successful responses and assert at least one exists.
- Assert all successful responses indicate logout success.
- For error responses, assert error code is RefreshTokenInvalid or RefreshTokenConflict.
Removed the assertion that all responses must be successful, reflecting expected outcomes for concurrent logout attempts.
Removes unused System.Linq import and adds Microsoft.EntityFrameworkCore.Metadata. Updates the navigation loop to skip navigations where the metadata is an INavigation with IsOnDependent true, preventing processing of dependent-side navigations during soft delete operations.
@Dejmenek Dejmenek linked an issue Sep 28, 2026 that may be closed by this pull request
10 tasks
@Dejmenek
Dejmenek merged commit bbe5669 into main Sep 28, 2026
3 checks passed
@Dejmenek
Dejmenek deleted the feat/146-support-multiple-bracket-formats-groundwork-round-robin-implementation branch September 28, 2026 21:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support multiple bracket formats: groundwork + round-robin implementation

1 participant