Skip to main content

Introduction

The Competition Factory represents a fundamental shift in how tournament management systems are architected. By separating tournament operations from infrastructure concerns, it enables unprecedented flexibility in deployment architectures while ensuring data integrity and long-term accessibility.

Configurable Tournament Operations​

The Competition Factory is a collection of functions for transforming and mutating tournament records. Core engines capture the types of state transitions fundamental to running tournaments - draw generation, participant assignments, matchUp scheduling, score recording, and outcome determination.

Rather than hardcoding tournament structures or embedding business rules in database stored procedures, the factory is configured through JSON policy definitions and JSON-described tournament structures. This architectural approach provides:

  • Deployment Flexibility: Operations can execute on standalone clients, servers, or both
  • Platform Independence: An entire tournament management solution can run in a browser, communicate with a server, or operate entirely offline
  • Scalable Architectures: Server deployments support highly scalable asynchronous processing models in Node.js
  • Configurable Behavior: Reasonable defaults for all operations, with extensive configuration options through policy definitions
  • Consistent Results: The same configuration produces identical tournament structures regardless of where operations execute
  • Zero Dependencies: The factory has no runtime dependencies — every utility, from date/time handling to timezone conversion, is built on platform APIs (Intl.DateTimeFormat, Date). This eliminates supply-chain risk, keeps bundle sizes minimal, and guarantees the factory runs anywhere JavaScript runs without version conflicts or transitive vulnerabilities

Cross-Sport Applicability​

While the Competition Factory was originally inspired by the Tennis Open Data Standards (TODS), the data structures and configurable operations apply to tournaments across many sports. The factory has already been successfully deployed across five racquet sports, demonstrating the universality of its approach. This cross-sport reality is now reflected in CODES (Competition Open Data Exchange Standards), the factory's expanded data model.

discipline is an open vocabulary — any string is accepted — with a curated known set covering tennis, beach tennis, wheelchair tennis, padel, pickleball, squash and badminton, plus first-class non-racquet entries for volleyball and beach volleyball. Cross-sport support is concrete rather than aspirational: the matchUpFormat grammar parses and round-trips each sport's scoring, and 14 rating systems ship as fixtures spanning tennis, squash, table tennis, badminton and pickleball, each declaring which end of its scale is the top so a lower-is-better system is never silently inverted.

Engines and Governors​

Operations are exposed as engine methods — 700+ of them, organized into 24 governors that group business rules by entity: draws, entries, events, participants, scheduling, scoring, publishing, ranking, officiating, sanctioning, venues, tieFormats, policies, practice, reports and more.

Several engine variants assemble those governors for different jobs: syncEngine/tournamentEngine for client-side and in-process use; asyncEngine for servers, which uses Node.js async_hooks to isolate state per request; plus focused ask, matchUp, mock, scale, scoring, availability, officiating and sanctioning engines. Every method resolves its own context from ids — pass a drawId or eventId, never a resolved object. See Mutation Engines and Engine Methods.

State Management and Extensibility​

The Competition Factory includes synchronous and asynchronous state engines that provide services for:

  • Managing tournament record state throughout event lifecycles
  • Publishing subscriptions for real-time data synchronization
  • Notifications and logging for audit trails
  • Middleware integration for custom business logic

This architecture enables both real-time tournament management during active events and comprehensive historical analysis of completed competitions.

Liberation from Legacy Constraints​

Traditional tournament management systems have created significant operational and financial burdens:

  • Vendor Lock-In: Dependence on active maintenance contracts to access historical data
  • Database Complexity: Reliance on specific database platforms, versions, and licensing
  • Schema Evolution: Business logic tightly coupled to database schemas that evolve over time
  • Deployment Overhead: Complex infrastructure requirements including third-party database licenses
  • Data Migration: Painful transitions when systems are upgraded or replaced

The Competition Factory eliminates these constraints through document-based data standards and configurable tournament operations, providing organizations with complete control over their tournament data and operational infrastructure.

Draw Types and Linked Structures​

The pre-defined catalog covers single and double elimination, round robin and round robin with playoff, Swiss, feed-in championships (to SF, to QF, and modified), consolation draws including Curtis and first-match/first-round loser consolation, compass and Olympic draws, Page playoffs, playoff structures, ad hoc / flexible rounds, and adaptive draws.

Beyond the catalog, the factory's linked structure architecture enables tournament topologies of arbitrary complexity. Structures can be connected in any configuration — multiple qualifying stages feeding into different rounds, consolation brackets with custom feed patterns, or entirely novel formats. Positions propagate along links by winner, loser, or finishing position, and exits — walkovers and defaults — cascade through the topology idempotently.

Draw Type Innovations​

Beyond draw type extensibility, the factory introduces formats never before possible with traditional tournament management systems:

  • DrawMatic — A probabilistic pairing algorithm for flexible-round events that dynamically adjusts pairings based on skill ratings, avoids repeat opponents, and respects team boundaries
  • Lucky Draw — Supports any participant count without requiring power-of-2 draw sizes, automatically handling odd-count rounds through "lucky loser" advancement
  • Draft Draws — Gives participants agency over their draw positioning through a tiered preference system, where unseeded participants nominate preferred positions after seeds are placed and preferences are resolved with full transparency
  • Ladder — A continuous, challenge-driven competition with no rounds, no bracket, no fixed field, and often no end date

Ladder​

A ladder shares the AD_HOC structure shape but not its meaning: its positionAssignments are the standing and drawPosition reads as rank, where 1 is the top. Participants challenge upward, results rearrange the standing, and the lifecycle is driven from the engine — seating and removal, challenge issue, acceptance and decline, result submission, confirmation and dispute, movement, standing and lapse queries — each resolving the ladder from drawId alone.

Ordering is by RANK (mutated by SWAP or INSERTION movement rules, which are genuinely different competitions) or by RATING (derived from the scale, with direction read from the rating system rather than assumed). Self-reported results are gated on an attestation policy — peer confirmation, operator confirmation, or either — and a disputed result is blocked from moving the standing. Declines, expiry and no-shows are unified as a single lapse with a policy-driven consequence, evaluated when a challenge resolves rather than by a periodic sweep.

Every rank change is mirrored to a dated scale item as a side effect of the position mutation, never as a separate call a caller might skip, so standing history is an ordinary scale lookup rather than a second store. CHALLENGED is the first matchUpStatus whose context is enforced — valid only in a LADDER draw, via a general scope mechanism rather than a special case in the setter.

Team Competition​

Team events are modelled as tieFormats — a declarative description of the collections (singles, doubles, or any custom grouping) that make up a dual match, their matchUpFormats, and how collection results aggregate into a tie score. Collections can be added, modified, reordered, removed and grouped at tournament, event, draw, structure or individual matchUp scope, with orphaned formats cleaned up automatically.

LineUps assign individual participants to collection positions with validation, and team scores are computed from collection value, match value, set value, or group aggregation. Nineteen tieFormats ship as fixtures — collegiate formats, national federation team championships, and multi-team exhibition formats among them. See the tieFormat governor.

Participants, Entries and Seeding​

Participants may be individuals, pairs, teams or groups, carrying the full CODES record — person details, memberships, sign-in and payment status, timeItems, and scale items. Entry management covers event and draw entries, entry status transitions, alternates and promotion, pair entry construction, entry positions, and per-stage entries, with eligibility enforced against category and policy constraints.

Seeding is policy-driven — seed counts by draw size, seed blocks, grouping and separation — and is complemented by an avoidance system that separates participants by any attribute path (country, club, team, rating band) during position assignment. Position actions and matchUp actions queries return the legal operations available in a given draw state, so a client can render exactly the affordances the rules allow rather than reimplementing them.

Scheduling​

The Competition Factory provides two complementary scheduling approaches. Garman scheduling is a fully automated algorithm that assigns match times across courts while respecting participant recovery periods, daily match limits, and court availability windows — ideal for multi-day tournaments where hundreds of matches need to be distributed efficiently. Pro scheduling offers grid-based control with fixed time slots and follow-on support, comprehensive conflict detection (court double-bookings, participant timing clashes, match ordering violations), and fine-grained court order assignments — the model used by professional tour events.

Both approaches are driven by scheduling policies that define match duration estimates, recovery times, and daily limits per format and category, and by scheduling profiles — declarative, persistent configurations that map specific rounds to dates and venues across the entire tournament. Profiles can be built incrementally, validated before execution, and adjusted as conditions change.

The Availability Engine extends this further by modelling court availability as continuous capacity streams, enabling "what-if" scenario simulation — tournament directors can test scheduling changes, visualize capacity, and detect conflicts before committing to the tournament record.

Venues, courts and their availability windows are first-class records. Practice courts are handled separately, as time-bounded registrations against a court with configurable booking capacity and participant conflict detection — see the practice governor.

Publishing and Embargo​

The Competition Factory gives tournament directors precise control over what information is publicly visible and when. Publishing operates at every level of granularity — tournament, event, draw, stage, structure, and individual rounds — so an organizer can, for example, publish qualifying draws immediately while holding the main draw under embargo until 3 AM the following morning.

Embargo extends this with time-based visibility gates. An embargoed element is marked as published but remains hidden from public-facing queries until the embargo timestamp passes — no cron jobs, no second mutation. This enables workflows like finalizing the order of play in the evening and setting it to go live automatically at a specific hour, or coordinating draw releases with media partners. Embargoes can be applied independently at any level: a draw, a stage within a draw, a structure, or even a single round's schedule data.

All embargo timestamps require explicit timezone context (UTC or offset), ensuring consistent behavior regardless of where the client or server is running. Admin queries always see the full publish state including active embargoes, while public queries respect embargo gates transparently.

Ranking Points and Scale Engine​

The Scale Engine computes ranking points in real time from tournament results using configurable ranking policies. Points are calculated from finishing positions, per-win bonuses, champion/finalist awards, and quality win bonuses for defeating ranked opponents — all scoped by event type, draw size, tournament level, category, and stage.

Built-in policies cover ATP, WTA, ITF, and national federation systems, but any custom point table can be defined as a JSON policy. The engine handles complex draw topologies (feed-in consolation, compass draws, qualifying stages) by normalizing finishing positions across structures and selecting the maximum award.

For ranking list generation pipelines, the Scale Engine supports multi-tournament aggregation with counting buckets, rolling period windows, and configurable tiebreak criteria. applyTournamentRankingPoints() persists computed awards as scale items on participant records, enabling bulk processing workflows where tournaments are fed through the pipeline sequentially to produce cumulative ranking lists.

The same machinery handles ratings as well as rankings — including dynamic ratings computed from match results and seeded from each participant's published value, the mechanism that also drives DrawMatic pairing and rating-ordered ladders. The factory deliberately does not fetch third-party ratings: those are other people's systems with their own credentials and terms, so retrieving values belongs in an operator's ingest adapter rather than in a competition engine.

Scoring Engine​

The Scoring Engine provides point-by-point match scoring across multiple sports and formats — standard tennis, tiebreak-only (pickleball, squash, badminton), timed sets, aggregate scoring, and rally scoring. It supports undo/redo, server tracking, substitutions, and mixed-mode entry, combining point-by-point with manual set/game entry.

Formats themselves are expressed as matchUpFormat codes — a compact, parseable grammar (SET3-S:6/TB7) that round-trips to a structured object, so a format is validated data rather than a string every client has to interpret. Score parsing, analysis and outcome determination are driven from the same codes.

Officiating Engine​

The Officiating Engine manages official assignments, certifications, evaluations, and suspension tracking. It supports policy-driven eligibility checks against certification requirements and evaluation score thresholds, enabling governing bodies to define and enforce officiating standards across tournaments.

Sanctioning Engine​

The Sanctioning Engine provides a state machine for governing body tournament sanctioning workflows. It manages the lifecycle from application through approval, with policy-driven validation of tournament parameters against tier-specific constraints — allowed formats, draw types, categories, prize money ranges, court requirements, and calendar conflict detection.

Reporting​

Report queries derive operational and statistical views from a tournament record without a separate reporting store — structure reports, entry status reports, venue and court utilization, participant statistics, and a generic report generator driven by a report context. Because the record is self-contained, the same reports run against a live tournament or one archived years earlier.

Policies​

Behavior is configured by JSON policy definitions attached at tournament, event, draw or structure scope. The factory ships a catalog of defaults covering seeding, avoidance, draws, progression, scheduling, scoring, round naming, round robin tallies, matchUp and position actions, ranking points, sanctioning, participant privacy, printing and competitive bands — including named variants for governing bodies and specific competition formats. Any policy can be replaced wholesale with your own JSON.

Mock Data Generation​

mocksEngine generates complete, valid tournament records from a compact profile — participants, events, draws, outcomes, venues, schedules and team competitions — with deterministic seeded randomness. It is how the factory's own suite is set up, and it makes reproducing a reported defect a matter of sharing a profile rather than a database dump.

import { mocksEngine } from 'tods-competition-factory';

const { tournamentRecord } = mocksEngine.generateTournamentRecord({
drawProfiles: [{ drawSize: 32, drawType: 'FEED_IN_CHAMPIONSHIP', outcomes: [] }],
setState: true,
});

Learn More​