Skip to content

This is a Layer 2 document. See CLAUDE.md for project overview.

Match Rotation Engine Specification

Status: Active

Overview

Match rotation is TwoMore's core differentiator. Every club has different preferences for how players are paired and rotated across rounds. The engine accepts a RotationConfig that the admin (총무) customizes per club or per session.

RotationConfig Interface

ts
interface RotationConfig {
  // Format
  format: 'doubles' | 'singles' | 'mixed'; // default: 'doubles'

  // Partner/opponent mixing
  partnerMode:
    | 'rotate_all' // maximize unique partners (default)
    | 'fixed_pairs' // pre-set partner pairs
    | 'skill_balanced' // pair high+low to balance teams
    | 'random'; // pure random each round
  avoidRepeatPartners: boolean; // true = never repeat partner within session
  avoidRepeatOpponents: boolean; // true = try to avoid repeat opponents

  // Skill balancing
  balanceByElo: boolean; // balance team Elo totals (default: true)
  eloTolerance: number; // max acceptable Elo gap between teams (default: 200)

  // Bench/rest
  benchMode:
    | 'fair_rotation' // rotate bench so everyone plays equally (default)
    | 'volunteer' // let players choose to sit out
    | 'none'; // no bench (error if odd players)

  // Round settings
  roundDurationMinutes: number; // default: 30
  maxRounds: number | null; // null = unlimited (play until session ends)

  // Gender constraints (for mixed doubles)
  requireMixedGender: boolean; // force one male + one female per team (default: false)

  // Custom constraints (future extensibility)
  customRules: Record<string, unknown>;
}

Default Presets

Presets are named configs the admin can pick from and tweak. Organized by format.

Doubles (복식)

PresetpartnerModebalanceByElobenchModeUse case
소셜 (Social)rotate_allfalsefair_rotationCasual meetups, maximize mixing
실력별 (Competitive)skill_balancedtruefair_rotationRanked play, balanced matches
고정 복식 (Fixed Doubles)fixed_pairstruevolunteerPre-arranged partner sessions
랜덤 (Random)randomfalsefair_rotationFun/variety-focused

Singles (단식)

PresetbalanceByEloavoidRepeatOpponentsUse case
소셜 단식 (Social Singles)falsetrueCasual, play everyone once
실력별 단식 (Competitive Singles)truetrueElo-matched opponents
랜덤 단식 (Random Singles)falsefalsePure random assignment

UI shows the relevant preset category based on the selected format.

Architecture

  • RotationConfig lives in domain/entities/rotation-config.entity.ts with Zod schema
  • generateRound() and generateAllRounds() in domain/rules/rotation.rules.ts accept RotationConfig as a parameter
  • Clubs store a default RotationConfig (JSON field on clubs table)
  • Sessions can override the club default with a session-specific config
  • Preset templates are constants in domain/rules/rotation-presets.ts
  • UI flow: admin picks a preset, then fine-tunes via a settings form

Markdown remains the source of truth. Run yarn docs:check before handoff.