Skip to main content

Extensions

Overview

Extensions capture configuration parameters, calculated results, and custom data that are not part of the core TODS specification. They further extend the tournament "time capsule" - ensuring what happened during a tournament can be accurately reconstructed.

Key Concepts

Non-Temporal Data: Unlike Time Items, extensions don't track changes over time
Name-Value Pairs: Each extension has { name, value } structure
Uniqueness: Only one extension with a given name per .extensions array
Hierarchical Scope: Extensions can exist on any TODS document element
Factory Constants: Pre-defined extension names recognized by the factory
Custom Extensions: User-defined extensions for application-specific data

Extension Structure

type Extension = {
name: string; // Unique identifier within the extensions array
value: any; // Any JSON-serializable data
};

// On any TODS element
{
extensions: Extension[];
}

Location in TODS

Extensions can be attached to any element in a tournament record:

  • Tournament Record (top level)
  • Events
  • Draw Definitions
  • Structures
  • MatchUps
  • Participants
  • Venues/Courts

Factory-Recognized Extensions

The factory internally uses and recognizes the following extension names (constants):

Configuration & Policy Extensions

appliedPolicies - Policies applied to tournament element

Attached to: tournamentRecords, events, drawDefinitions, structures

Purpose: Captures which policies are "in scope" within the object hierarchy. Policies can be attached programmatically or automatically during draw generation.

{
name: 'appliedPolicies',
value: {
seeding: { seedingProfile: 'WTN', ... },
avoidance: { roundsToSeparate: 3, ... }
}
}

schedulingProfile - Auto scheduler configuration

Attached to: tournamentRecords, events

Purpose: Stores iteratively-edited scheduling profile before running the auto scheduler.

{
name: 'schedulingProfile',
value: [
{
scheduleDate: '2024-06-15',
venues: [{ venueId: 'venue-1', rounds: [...] }]
}
]
}

scheduleLimits - Match daily limits override

Attached to: matchUps

Purpose: Overrides policy-defined daily limits for specific matchUps.

{
name: 'scheduleLimits',
value: {
SINGLES: 2,
DOUBLES: 1,
TOTAL: 2
}
}

scheduleTiming - Match format timing override

Attached to: matchUps

Purpose: Overrides policy-defined timing for specific matchUp formats.

{
name: 'scheduleTiming',
value: {
'SET3-S:6/TB7': {
averageMinutes: 90,
recoveryMinutes: 30
}
}
}

Draw Generation & Structure Extensions

entryProfile - Entry limitations

Attached to: events

Purpose: Stores limitations on accepted entries including qualifiers, wildcards, and maximum draw size.

{
name: 'entryProfile',
value: {
maxDrawSize: 32,
qualifiers: 4,
wildcards: 4
}
}

flightProfile - Flight names and entries

Attached to: events

Purpose: Captures flight configuration when event entries are split into multiple flights before draw generation.

{
name: 'flightProfile',
value: {
flights: [
{ flightNumber: 1, drawEntries: [...] },
{ flightNumber: 2, drawEntries: [...] }
]
}
}

drawProfile - Draw-specific configuration

Attached to: drawDefinitions

Purpose: Stores draw generation parameters and configuration.

{
name: 'drawProfile',
value: {
automated: true,
seedsCount: 8,
drawType: 'ELIMINATION'
}
}

eventProfile - Event-specific configuration

Attached to: events

Purpose: Stores event-level configuration and parameters.

{
name: 'eventProfile',
value: {
category: 'U18',
gender: 'FEMALE',
surfaceType: 'HARD'
}
}

disableLinks - Link disabling for position swaps

Attached to: structures

Purpose: When positioning policies allow draw position swaps in non-MAIN structures, normal progression logic breaks and links must be disabled to avoid data corruption.

{
name: 'disableLinks',
value: true
}

roundTarget - Qualifying feed-in rounds

Attached to: structures, event.entries

Purpose: Supports qualifying structures feeding into different rounds of MAIN structures; also annotates entries for "staggered entry" structures.

{
name: 'roundTarget',
value: {
roundNumber: 2, // Feed into round 2 of main draw
structureId: 'main-structure-id'
}
}

Team Event Extensions

groupingAttribute - Team generation attribute

Attached to: participants (TEAM type)

Purpose: Stores the person/participant attribute used to generate TEAM participants.

{
name: 'groupingAttribute',
value: 'club' // Teams generated by club affiliation
}

lineUps - Team lineup defaults

Attached to: structures

Purpose: Stores most recent lineup for each TEAM progressing through structure. Enables default assignments in hydrated SINGLES/DOUBLES tie matchUps before actual lineups are saved.

{
name: 'lineUps',
value: {
'team-1': [
{ participantId: 'player-1', collectionPosition: 1 },
{ participantId: 'player-2', collectionPosition: 2 }
]
}
}

disableAutoCalc - Manual TEAM scoring

Attached to: matchUps (TEAM type)

Purpose: When manual scoring is enabled for TEAM matchUps, disables automatic calculation of team results.

{
name: 'disableAutoCalc',
value: true
}

Scoring & Results Extensions

delegatedOutcome - Unofficial results

Attached to: matchUps

Purpose: Captures matchUp outcomes sourced from third-party applications for display purposes prior to official result entry.

{
name: 'delegatedOutcome',
value: {
score: {
sets: [
{ side1Score: 6, side2Score: 4, winningSide: 1 },
{ side1Score: 6, side2Score: 2, winningSide: 1 }
]
},
winningSide: 1,
source: 'external-app'
}
}

tally - Round robin results

Attached to: positionAssignments (within structures)

Purpose: Stores calculated participant results for structure positions. Used to determine group order in round robin structures.

{
name: 'tally',
value: {
matchUpsWon: 4,
matchUpsLost: 1,
setsWon: 9,
setsLost: 3,
gamesWon: 54,
gamesLost: 38
}
}

subOrder - Tie-breaking order

Attached to: positionAssignments

Purpose: When ties occur in round robin group order calculation, captures manual determination of order for tied positions.

{
name: 'subOrder',
value: 2 // Second place among tied participants
}

rankingPoints - Points awarded

Attached to: tournamentRecords

Purpose: Enables capturing points generated by event outcomes for real-time display as participants advance through structures.

{
name: 'rankingPoints',
value: {
'player-1': { singles: 250, doubles: 100 },
'player-2': { singles: 150 }
}
}

Scheduling & Venue Extensions

disabled - Resource disabling

Attached to: courts, venues

Purpose: Indicates resource has been disabled and scheduling methods cannot use it.

{
name: 'disabled',
value: true
}

linkedTournamentsIds - Multi-tournament scheduling

Attached to: tournamentRecords

Purpose: When multiple tournaments share venues, captures the association so client applications know to load all tournament records for scheduling.

{
name: 'linkedTournamentsIds',
value: ['tournament-1', 'tournament-2', 'tournament-3']
}

personRequests - Scheduling requests

Attached to: participants, events, tournamentRecords

Purpose: Captures scheduling requests from participants. Consumed by scheduler to accommodate requests or simply display them.

{
name: 'personRequests',
value: [
{
personId: 'person-1',
requestType: 'DO_NOT_SCHEDULE',
date: '2024-06-15',
startTime: '09:00',
endTime: '11:00'
}
]
}

Participant & Registration Extensions

registration - Registration data

Attached to: participants

Purpose: Captures registration-related information and metadata.

{
name: 'registration',
value: {
registrationDate: '2024-05-01',
registrationId: 'REG-12345',
paymentStatus: 'PAID'
}
}

participantRepresentatives - Draw witnesses

Attached to: drawDefinitions

Purpose: Records participant representatives present as witnesses during manual draw creation (traditional "hat draw").

{
name: 'participantRepresentatives',
value: [
{ participantId: 'player-1', representativeName: 'John Coach' },
{ participantId: 'player-2', representativeName: 'Jane Manager' }
]
}

statusDetail - Entry status annotation

Attached to: event.entries

Purpose: Third-party extension (not used by factory) for annotating entry status of participants.

{
name: 'statusDetail',
value: {
status: 'CONFIRMED',
notes: 'Paid in full, medical clearance received'
}
}

eventWithdrawalRequests - Withdrawal tracking

Attached to: events

Purpose: Tracks participant withdrawal requests from events.

{
name: 'eventWithdrawalRequests',
value: [
{
participantId: 'player-1',
requestDate: '2024-06-10',
reason: 'Injury'
}
]
}

activeSuspension - Participant suspension

Attached to: participants

Purpose: Indicates participant has active suspension affecting eligibility.

{
name: 'activeSuspension',
value: {
startDate: '2024-05-01',
endDate: '2024-08-31',
reason: 'Code violation'
}
}

Auditing & System Extensions

factory - Factory version tracking

Attached to: tournamentRecords

Purpose: Captures version of factory (and other TODS processors) that created/mutated the tournament record.

{
name: 'factory',
value: {
version: '2.2.49',
lastModified: '2024-06-15T10:30:00Z'
}
}

drawDeletions - Deleted draw audit

Attached to: tournamentRecords

Purpose: When no external auditing service is available, stores deleted draw definitions for audit purposes.

{
name: 'drawDeletions',
value: [
{
drawId: 'draw-123',
drawName: 'Main Draw',
deletedAt: '2024-06-14T15:00:00Z',
deletedBy: 'user-456'
}
]
}

positionActions - Position action telemetry

Attached to: tournamentRecords

Purpose: When no external auditing service is available, stores position action telemetry.

{
name: 'positionActions',
value: [
{
action: 'ASSIGN_PARTICIPANT',
drawPosition: 1,
participantId: 'player-1',
timestamp: '2024-06-14T14:00:00Z'
}
]
}

tieFormatModifications - Tie format audit

Attached to: tournamentRecords

Purpose: When no external auditing service is available, captures modifications to tie formats during the course of an event.

{
name: 'tieFormatModifications',
value: [
{
tieFormatId: 'format-1',
modifiedAt: '2024-06-15T09:00:00Z',
changes: { collectionDefinitions: [...] }
}
]
}

context - Creation context

Attached to: venues, courts, and other elements

Purpose: Captures context in which a resource was added (metadata about creation).

{
name: 'context',
value: {
createdBy: 'user-123',
createdAt: '2024-06-01T10:00:00Z',
source: 'mobile-app'
}
}

Display & UI Extensions

display - Display preferences

Attached to: events, drawDefinitions, structures

Purpose: Client application-specific storage for display preferences.

{
name: 'display',
value: {
viewMode: 'bracket',
showSeeds: true,
highlightedParticipants: ['player-1', 'player-2']
}
}

Custom Extensions

Applications can define custom extensions for application-specific data not covered by factory constants.

Naming Conventions

Use descriptive, unique names that won't conflict with factory extensions:

// ✓ GOOD - Clear, specific names
{ name: 'broadcastSchedule', value: { ... } }
{ name: 'sponsorData', value: { ... } }
{ name: 'mediaRequirements', value: { ... } }
{ name: 'facilityAccess', value: { ... } }

// ✗ AVOID - Generic or conflicting names
{ name: 'data', value: { ... } }
{ name: 'info', value: { ... } }
{ name: 'config', value: { ... } }

Custom Extension Examples

Broadcast Information:

tournamentEngine.addMatchUpExtension({
matchUpId: 'match-123',
drawId: 'draw-456',
extension: {
name: 'broadcastSchedule',
value: {
channel: 'ESPN',
broadcastTime: '14:00',
commentators: ['John Smith', 'Jane Doe'],
},
},
});

Facility Requirements:

tournamentEngine.addEventExtension({
eventId: 'singles-main',
extension: {
name: 'facilityRequirements',
value: {
courtSurface: 'HARD',
lighting: 'REQUIRED',
spectatorCapacity: 500,
},
},
});

Sponsor Data:

tournamentEngine.addTournamentExtension({
extension: {
name: 'sponsorData',
value: {
titleSponsor: 'Acme Corp',
courtSponsors: {
'court-1': 'Beta LLC',
'court-2': 'Gamma Inc',
},
},
},
});

Working with Extensions

Adding Extensions

// Add to tournament
tournamentEngine.addTournamentExtension({
extension: {
name: 'customData',
value: { ... }
}
});

// Add to event
tournamentEngine.addEventExtension({
eventId: 'singles-main',
extension: {
name: 'eventCustomData',
value: { ... }
}
});

// Add to draw
tournamentEngine.addDrawDefinitionExtension({
drawId: 'draw-123',
extension: {
name: 'drawCustomData',
value: { ... }
}
});

// Add to matchUp
tournamentEngine.addMatchUpExtension({
matchUpId: 'match-456',
drawId: 'draw-123',
extension: {
name: 'matchUpCustomData',
value: { ... }
}
});

Retrieving Extensions

// From tournament record
const tournament = tournamentEngine.getTournament();
const customExt = tournament.extensions?.find((e) => e.name === 'customData');

// From event
const { event } = tournamentEngine.getEvent({ eventId: 'singles-main' });
const eventExt = event.extensions?.find((e) => e.name === 'eventCustomData');

// From draw
const { drawDefinition } = tournamentEngine.getDrawDefinition({ drawId: 'draw-123' });
const drawExt = drawDefinition.extensions?.find((e) => e.name === 'drawCustomData');

// From matchUp (with context)
const { matchUp } = tournamentEngine.findMatchUp({
matchUpId: 'match-456',
inContext: true,
});
const matchUpExt = matchUp.extensions?.find((e) => e.name === 'matchUpCustomData');

Updating Extensions

Extensions are updated by removing the old one and adding the new one (or using update methods):

// Remove extension
tournamentEngine.removeTournamentExtension({
name: 'customData',
});

// Add updated version
tournamentEngine.addTournamentExtension({
extension: {
name: 'customData',
value: updatedValue,
},
});

Extension Hydration

When retrieving data with inContext: true, extensions are automatically converted to underscore-prefixed attributes:

// MatchUp has extension
{
extensions: [
{
name: 'broadcastSchedule',
value: { channel: 'ESPN' },
},
];
}

// When hydrated
const { matchUps } = tournamentEngine.allTournamentMatchUps({
inContext: true,
});

console.log(matchUps[0]._broadcastSchedule); // { channel: 'ESPN' }
console.log(matchUps[0].extensions); // Original array still present

See: MatchUp Context for details on extension hydration.

Extensions vs Time Items

Choose the appropriate mechanism for your data:

FeatureExtensionsTime Items
PurposeConfiguration, calculated results, custom dataTemporal data with effective dates
HistorySingle value (current state)Multiple values over time
TimestampsNo timestampsitemDate and createdAt
Use CasesPolicies, profiles, preferences, metadataRankings, ratings, schedule changes, status transitions
HydrationUnderscore-prefixed attributesExtracted to .schedule for matchUps

Example Decision:

  • Use Extension: Store broadcast channel assignment (doesn't change over time)
  • Use Time Item: Track court assignments (may change, need history)

Best Practices

Uniqueness

Only one extension with a given name per element:

// ✓ CORRECT - One extension per name
{
extensions: [{ name: 'customData', value: { field1: 'value1', field2: 'value2' } }];
}

// ✗ WRONG - Duplicate names
{
extensions: [
{ name: 'customData', value: { field1: 'value1' } },
{ name: 'customData', value: { field2: 'value2' } }, // Duplicate!
];
}

Value Types

Use appropriate JSON-serializable types:

// ✓ GOOD - JSON-serializable
{ name: 'config', value: { enabled: true, count: 5, items: ['a', 'b'] } }
{ name: 'timestamp', value: '2024-06-15T10:00:00Z' }

// ✗ AVOID - Non-serializable
{ name: 'config', value: new Date() } // Date object
{ name: 'callback', value: function() {} } // Function

Factory Constant Names

Avoid using factory-recognized extension names for custom extensions:

// ✗ AVOID - Conflicts with factory constants
{ name: 'appliedPolicies', value: myCustomValue }
{ name: 'schedulingProfile', value: myCustomValue }

// ✓ GOOD - Unique custom names
{ name: 'myApp_policies', value: myCustomValue }
{ name: 'myApp_schedule', value: myCustomValue }