Repository navigation
Application Requirements
Ultra-Tracker is a cross-platform desktop application designed to track athletes in real-time during ultra-marathon events. It operates locally at race aid stations, providing race operators with tools to log athlete arrival/departure times, manage athlete rosters, and export data intermittently to race organizers. The system is built to function reliably in offline or remote environments using a local database architecture.
- Aid Station Operators: Field volunteers logging athlete times, adding notes, and tracking station status.
- Race Leadership / Organizers: Central data recipients who import files generated by individual stations.
- Developers: Technical teams diagnosing errors using verbose system logs.
-
FR-1.1: The system must allow operators to load configuration files from a localized system path:
-
Windows:
%userprofile%\Documents\ultra-tracker\ -
Linux:
$HOME/Documents/ultra-tracker -
MacOS:
/Users/username/Documents/ultra-tracker
-
Windows:
-
FR-1.2: The system must import JSON files for Station Configuration (e.g.,
eventname-YYYY-stations.json) containing metadata such as station names, locations, mileage, and cutoff times. - FR-1.3: The system must ingest CSV data files for Athletes and unified Drops lists provided by race organizers. A Drop Reason identifies athletes who did not start, withdrew, timed out, received medical attention, or have an unknown reason.
- FR-1.4: The system must handle incremental updates of Drops files, ignoring drop records logged at points past the current station's mileage marker.
- FR-2.1: The system must provide a primary input block for BIB# entries. It must accept input from standard 10-key numpads and top-row keys.
- FR-2.2: The system must support the following fast-key keyboard shortcuts when focused on the BIB# field:
| Action | Standard Layout | Numpad Layout |
|---|---|---|
| Log In Time | Equal (=) |
Subtract (-) |
| Log Out Time | Minus (-) |
Add (+) |
| Log In & Out |
Slash (/) or Backslash (\)
|
Divide (/) or Enter
|
- FR-2.3: Data grids must support ascending/descending column sorting upon clicking a column header, alongside independent column text filtering via a three-dot menu icon.
- FR-2.4: The UI layout must adapt across HD resolutions so filtering items do not overlap column headers under normal system scaling.
- FR-3.1: The UI must feature an edit drawer on the far right of any row entry to modify or delete logged athlete times, Drop Reasons, and notes.
- FR-3.2: The interface must display the athlete's full name alongside a shortcut to their entry in the Roster tab if the BIB# successfully matches an imported file record.
- FR-3.3: The system must throw a warning condition if a record is added for an unknown BIB# not present in the master Athlete file.
-
FR-3.4: Validation constraints must strictly block illegal data states:
- Records must contain an In time to exist.
- The In time must chronologically occur prior to any Out time.
- The system must automatically sanitize input by replacing commas (
,) in the Notes field with semicolons (;).
- FR-4.1: The Roster Page must maintain a searchable index of all athletes by name, bib number, city, start time, station incoming/outgoing timestamps, and notes.
-
FR-4.2: The system must assign a status tracker flag to filter athletes by:
Incoming,DNS,In,Out,Medical,Timeout, andWithdrew.
-
FR-5.1: The system must auto-generate local event logging files viewable in two discrete interface options:
- Normal Log: Tracking regular software usage, duplicate time updates, and typical operational events.
- Verbose Log: Collecting granular system telemetry, deep debug messages, and trace histories for the development team.
-
FR-6.1: Incremental CSV Export: The tool must generate sequential, auto-incrementing files (e.g.,
Aid05Times_04i.csv) isolating only unsent or newly updated time rows since the prior generation. - FR-6.2: Full CSV Export: The system must export a flat document containing every logged station time entry to act as a master final report.
- FR-6.3: Drops Export: The program must export a unified Drops file containing records from the current or earlier station, with one Drop Reason per athlete.
- FR-6.4: A successful incremental or full CSV export must mark its included timing records as exported. When OpenSplitTime is not authenticated, the timing-record indicator must show a gray hollow circle for records not exported to CSV and a green hollow circle for exported records.
- FR-7.1: The system must provide controls to initialize and cease an embedded background service handling automated RFID tracking data.
- FR-7.2: Automated RFID hardware services must restrict execution capabilities strictly to stations configured as the event's designated Start Line or Finish Line.
- FR-7.3: The integration layer must natively interface with Zebra FXR90 telemetry protocols.
- FR-8.1: The system must allow operators to authenticate against OpenSplitTime using an email/password login, selectable between
stagingandproductionenvironments. - FR-8.2: Saved credentials must be stored using OS-level secure storage (
safeStorage) rather than plaintext, with only the email and an availability flag exposed to the renderer. - FR-8.3: The system must automatically push newly logged timing records (bib number, split name, in/out sub-split, entered time, pacer flag) to the configured OpenSplitTime event group as raw times.
- FR-8.4: Automatic push must be gated on a valid, non-expired authentication token; unauthenticated or expired sessions must block pushes and surface a clear status to the operator rather than fail silently.
- FR-8.5: The system must support pausing and resuming the automatic push queue, and allow manual per-record retry for records that failed to push.
- FR-8.6: The most recent OpenSplitTime push outcome (success or error) must persist in a dedicated database table so status survives app restarts and is cleared when the underlying timing record is deleted or edited. This status is independent of CSV export state.
- FR-8.7: The interface must display a background connectivity monitor (in the application footer) showing distinct states for general internet connectivity and reachability of the OpenSplitTime host, polled on a fixed interval (~15s) using a short-timeout probe distinct from authenticated request timeouts.
- FR-8.8: Duplicate raw-time submissions detected by OpenSplitTime must be surfaced to the operator as a distinct status rather than treated as a generic failure.
- FR-8.9: While OpenSplitTime is authenticated, its timing-record indicator must take precedence over CSV export state: yellow solid for pending upload, green solid for uploaded, and red solid for upload failure. Signing out must restore the CSV export indicator without changing CSV export state.
- NFR-1.1: The application environment must run natively across Windows, Linux, and MacOS operating systems with a uniform feature set.
- NFR-2.1: Database transactions must persist completely to disk in real-time, preventing state degradation or loss if the system window closes suddenly.
- NFR-2.2: An automated background routine must backup the active operational state to a secondary file storage block on a strict 5-minute interval clock.
- NFR-3.1: The software must provide a dark and light configuration mode to optimize readability across contrasting environments (e.g., intense direct daylight or pitch-black nighttime operations).
- ADM-1.1: UI administration options built to delete table configurations or recreate blank local databases must feature clear color indicators (RED warning colors) to halt accidents by active line operators.
- ADM-1.2: Emergency tools must support a clean data recovery flow that parses historical continuous-logging CSV files to reconstruct active database layouts automatically following corruption.
-
ADM-2.1: The core framework must support recovery execution exactly via these operational steps:
- Execute full Database Recreation.
- Load baseline Stations schema.
- Import Master Athletes registry.
- Apply the current Drops file.
- Re-import historical session records using the CSV Recovery parser.
- Runtime Shell: Electron
- Frontend Engine: React + TypeScript
- Styling Layer: Tailwind CSS
- Data Tier: Embedded local relational/transactional database platform
To ensure absolute system alignment and machine readability during remote cross-station text transmissions, all imported and exported payloads must adhere strictly to the schemas defined below.
A structured configuration metadata payload loaded via the Setup Menu to determine localized race profiles.
- Format: JSON Array
-
Default Filename Pattern:
eventname-YYYY-stations.json
{
"$schema": "https://json-schema.org",
"title": "StationsConfiguration",
"type": "array",
"items": {
"type": "object",
"required": ["stationId", "stationName", "mileage", "cutoffTime"],
"properties": {
"stationId": { "type": "string", "pattern": "^Aid[0-9]{2}$" },
"stationName": { "type": "string" },
"mileage": { "type": "number", "minimum": 0.0 },
"cutoffTime": { "type": "string", "pattern": "^(2[0-3]|[0-9]):([0-5][0-9])$" },
"operatorCallsign": { "type": "string" }
}
}
}Contains metadata for every athlete registered to run the event.
- Format: RFC 4180 Comma-Separated Values (CSV)
- Header Row Requirement: Mandatory
-
Fields:
-
BibID(Integer, Primary Key) -
FirstName(String) -
LastName(String) -
City(String) -
StartTime(String, ISO 8601 or HH:MM Format)
-
Pre-populated status sheets containing drop records managed by race organizers.
- Format: Comma-Separated Values (CSV)
-
Title Row:
{eventName},{stationIdentifier},drops-export -
Header Row:
stationId,bibId,dropReason,dropDateTime,note -
Fields:
-
stationId(String, start-line or drop station identifier) -
bibId(Integer, Foreign Key to Athlete Table) -
dropReason(Enum:did-not-start,withdrew,timeout,medical, orunknown) -
dropDateTime(String,HH:MM:SS DD Mon YYYY) -
note(String, commas replaced with semicolons)
-
This output targets low-bandwidth physical radio packet operations by only writing rows modified since the preceding output loop.
- Format: Comma-Separated Values (CSV)
-
Default Filename Pattern:
Aid[StationID]Times_[IncrementalIndex]i.csv(e.g.,Aid05Times_04i.csv)
| Column Pos | Field Label | Data Type | Validation Constraints / Format |
|---|---|---|---|
| 1 | BibID | Integer | Must match master list format. |
| 2 | TimeIn | String | Format: HH:MM:SS (24hr clock). Mandatory field. |
| 3 | TimeOut | String | Format: HH:MM:SS (24hr clock). |
| 4 | DropReason | String / Enum | Allowed: did-not-start, withdrew, timeout, medical, unknown, or empty. |
| 5 | Notes | String | Length <= 250 characters. No commas permitted. |
Acts as the holistic master ledger for a station's complete operations.
- Format: Comma-Separated Values (CSV)
-
Default Filename Pattern:
Aid[StationID]Times_FULL.csv - Field Mapping: Mirrors fields 1 through 5 of the Incremental CSV, but writes all localized row indices across database bounds regardless of transmission state history.
The runtime framework handles data integrity assertions via strict structural validation mechanics. Issues are isolated into warnings or critical block errors depending on risk profiles.
[User / CSV / RFID Action]
|
v
[Data Integrity Engine]
/ \
(Fails Schema / Syntax) (Fails Temporal/State Rules)
/ \
v v
+------------------+ +--------------------+
| CRITICAL BLOCK | | OPERATIONAL CAUTION|
| (System halts | | (Logs entry safely |
| un-saved rows) | | with UI Warnings) |
+------------------+ +--------------------+
When a user updates details inside the Stats Edit panel or triggers a Manual Entry, the software actively blocks database execution and prints UI alerts under the following failures:
-
Rule-1: Chronological Order Fault
-
Assertion:
TimeIn<TimeOut. -
UI Error Behavior: Throws error text block below input fields:
"Validation Error: Time Out cannot be recorded prior to Time In."Saves are cancelled until adjusted.
-
Assertion:
-
Rule-2: Missing Anchoring Timestamp
-
Assertion: Every row item must possess a verified
TimeInvalue. -
UI Error Behavior: Rejects submission and highlights the input block in red. Displays message:
"Validation Error: Record must have a valid In time."
-
Assertion: Every row item must possess a verified
-
Rule-3: Illegal Character Suffix (Comma Inject)
-
Assertion: Commas (
,) break field layout bounds across flat-file CSV streams. -
System Sanitization Behavior: Rather than triggering an operation halt, the input wrapper sanitizes data immediately upon focus loss. All typed commas inside the Note box are replaced globally with semicolons (
;).
-
Assertion: Commas (
These assertions detect race anomalies but permit database storage so field personnel do not lose tracking access during critical events:
-
Warning-1: Unknown Bib Registry
-
Trigger: A user enters a
BibIDinteger that does not map to any athlete row inside the imported master registry. - System Behavior: Allows the entry but attaches an active flag to the data row.
-
UI Feedback: Displays an orange highlight box on the entry line. The Athlete Name cell explicitly renders:
"WARNING: Unknown Athlete". The interface restricts deep row updates inside the Edit pane until resolved to a known ID.
-
Trigger: A user enters a
-
Warning-2: Upstream Progression Check (Drop Validation)
- Trigger: An operator loads a new Drops payload containing a drop record for an athlete whose station identifier is past the current aid station.
- System Behavior: The database ingests the record but strips out or suppresses the status changes locally.
- Log Output: Logs the ignored record with its Bib ID and station identifier for operator diagnosis.
| Failure Event | System Diagnostics Impact | Immediate UI Alert/Behavior |
|---|---|---|
| Malformed CSV / JSON Syntax | Halts the import parser loop entirely to avoid data corruption. | Modal Alert: "Error Loading File: Structural syntax error detected. Check delimiters or brackets."
|
| Missing Header Row | Misaligns table bindings, rendering cell values unparseable. | System aborts transaction and reverts to state defaults. UI prints error banner. |
| Duplicate Timestamps | Overwrites are flagged to prevent logging loss. | Writes event to Normal Station Log. Keeps both values and notes entry within database fields. |