All TypeScript interfaces described on this page are defined inDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/SdazaP/ruTournament/llms.txt
Use this file to discover all available pages before exploring further.
src/common/db.ts and represent every piece of data stored in the RuTournamentDB IndexedDB database. The database is managed by Dexie.js and contains a single top-level table — tournaments — which holds self-contained TournamentLocal documents. All related data (categories, rounds, results, competitors) is embedded directly inside each tournament document rather than in separate tables.
id fields for top-level tournaments are generated as Date.now().toString(). Category IDs are formed as tournamentId + index (e.g. "1718000000000_0"), and competitor IDs are formed as tournamentId + 'c' + index (e.g. "1718000000000c0"). These conventions are applied in the creation wizards and are not enforced by Dexie itself.TournamentLocal
The root document stored in thetournaments table. Every tournament is a single record of this type.
Primary key used by Dexie. Generated as
Date.now().toString() at creation time. Dexie indexes this field alongside name, status, and date for efficient querying.Human-readable tournament name displayed throughout the UI (e.g.
"Open Regional 2026").Free-text description shown on the tournament dashboard. May be an empty string.
Venue or city name (e.g.
"Bogotá, Colombia").Lifecycle state of the tournament. Controls UI permissions via the
useTournamentStatus hook:| Value | canEdit | canUploadResults |
|---|---|---|
activo | ✅ | ✅ |
proximamente | ✅ | ❌ |
finalizado | ❌ | ❌ |
Competition date in
YYYY-MM-DD ISO format (e.g. "2026-06-15").Optional tournament logo stored as a base64-encoded image string or raw SVG markup. The upload UI automatically resizes images to 200 px wide before encoding.
Ordered list of competition categories (events). Each element is a
CategoryLocal object. See CategoryLocal below.Flat list of all registered competitors. Category membership is stored on the competitor (via category IDs), not on the category itself.
CategoryLocal
Represents one competition event within a tournament (e.g. “3x3”, “Megaminx”).Generated as
tournamentId + "_" + index during category creation.Display name of the category. For WCA events this should match a key in
WCA_EVENT_CONFIG (e.g. "3x3", "Megaminx"). Custom names are also supported.Determines which result-entry and bracket UI is used.
'wca' uses the standard average-based results view; 'redbull' uses a head-to-head bracket.Scheduled start time in
HH:MM 24-hour format.Scheduled end time in
HH:MM 24-hour format.Name of the room or station where the category takes place.
Ordered list of rounds for this category. See RoundLocal.
When
true, the first round is treated as a seeding round. Seeding results determine bracket seeding for subsequent rounds.Round format used for the seeding round. Only relevant when
hasSeeding is true.Controls how competitors are assigned to bracket slots in Red Bull categories.
'random' shuffles competitors; 'manual' lets the organiser drag-and-drop.RoundLocal
One round within a category.Optional round identifier.
Round number (1-based). Used to determine which competitors advance from the previous round.
Solving format.
'ao3' = average of 3, 'ao5' = average of 5, 'rb' = Red Bull head-to-head.Array of entered results, one per competitor who has at least one recorded solve. See ResultLocal.
How many top-ranked competitors advance to the next round. The special value
'all' passes every competitor through.Round-level scrambles generated by the csTimer engine. See ScrambleRecord.
Competitor groups for this round. Organises competitors and staff across stations and time slots.
Head-to-head match bracket. Only populated when
format is 'rb'. See RedBullMatchLocal.Per-round bracket assignment override, mirroring the category-level field.
Marks this round as the seeding round. Set automatically when
CategoryLocal.hasSeeding is true.GroupLocal
A competitor group within a round, used to organise who solves at the same time and who staffs them.Unique group identifier.
Display name (e.g.
"Group A").Group start time in
HH:MM format.Group end time in
HH:MM format.Array of competitor IDs who are solving in this group.
Staff assignments for this group.
Group-specific scrambles. When present, these take precedence over round-level scrambles for this group.
CompetitorLocal
A registered competitor. Category membership and role assignments are stored on this object.Generated as
tournamentId + "c" + index during competitor registration.Full display name of the competitor.
List of category IDs the competitor is registered to compete in.
Global role labels available to this competitor (e.g.
['judge', 'scrambler']).Per-category role assignments. Each key is a category ID; the value is an array of role strings assigned to this competitor within that category.Example:
ResultLocal
Stores the raw solve times and computed average for one competitor in one round.The ID of the competitor this result belongs to.
Array of individual solve times. Elements may be plain
number values (legacy) or TimeRecord objects. Use normalizeTime() to convert any element to a consistent TimeRecord before processing.Computed average stored as a formatted string (e.g.
"12.34"). "-1" indicates a DNF average. Recalculated on every save by calculateRulesStats().TimeRecord
The canonical representation of a single solve time, including any WCA penalty.Raw solve time in seconds as a floating-point number (e.g.
9.53, 67.12). This is the time before applying a +2 penalty. A value of 0 with penalty: 'DNF' represents a pure DNF with no recorded time.WCA penalty applied to this solve:
''— no penalty; effective time equalsbase.'+2'— 2-second penalty; effective time equalsbase + 2.'DNF'— Did Not Finish; solve does not count towards the average.
ScrambleRecord
A single scramble sequence together with its rendered puzzle-state image.The scramble sequence in standard WCA notation.
SVG markup string rendered by the csTimer engine, showing the puzzle state after applying the scramble. Displayed inline in the Scrambles view.
RedBullMatchLocal
One head-to-head match in a Red Bull bracket round.Unique match identifier within the bracket.
ID of the first competitor in this match.
ID of the second competitor in this match.
Competitor ID of the match winner. Populated after the match concludes.
Per-solve times for both competitors in this match. Each array element corresponds to one solve leg; elements may be
null if not yet entered.Running win count for each competitor within the match.
Database access
The singletondb instance is exported from src/common/db.ts and should be used throughout the application for all IndexedDB operations.
The Dexie table is indexed on
id, name, status, and date. All other fields (categories, competitors, rounds, results) are stored as plain JSON inside the document and are not individually indexed. Queries on non-indexed fields require loading the full tournament document first.Utility functions
These helper functions are exported alongside the data types and used throughout the results views.normalizeTime
TimeRecord. Handles three input forms:
- Object with
base— returned as-is withbasecast toNumber. number— becomes{ base: t, penalty: '' }for positive values, or{ base: 0, penalty: 'DNF' }for negative values.- Numeric string — parsed and treated the same as a plain number.
calculateRulesStats or rendering it in the UI.
calculateRulesStats
best— fastest non-DNF time in seconds;-1if all solves are DNF.average— computed average in seconds;-1for a DNF average;0if not all solves have been entered yet.- ao3 — any DNF produces a DNF average; otherwise the sum of all three times divided by 3.
- ao5 — two or more DNFs produce a DNF average; one DNF eliminates the DNF and the best time, averaging the remaining three; no DNFs eliminate the best and worst, averaging the middle three.
sortWCA
- Competitors with a valid positive average rank above those with a DNF average, who rank above those with no average.
- Among competitors with valid averages, sort ascending by average.
- Tiebreak on ascending best single.
- Final tiebreak on competitor name (alphabetical).
Array.prototype.sort.
parseTimeToSeconds
TimeRecord.base.
number— returned as-is.stringwith:— split on:and parsed asminutes * 60 + seconds(e.g."1:07.78"→67.78).- Other string — parsed as
parseFloat; returns0if parsing fails or the value is empty.
TimeRecord.
isDuplicateName
true if name (case-insensitive, trimmed) already exists in existingNames. Pass excludeIndex to skip a specific index — useful when validating an in-place edit where the item being edited should not be compared against itself.
