Omnium developer docs
Omnium scoring, explained
How a score gets in, stays right, and goes out to every client, in plain words and drawings.
In one minute
Omnium holds the live scores and results of 25 and more sports in one data model, and serves them through one API and one set of client files.
Every change, whether a scorer's tap, a staff fix in the console or a row from a provider import, takes one road: it becomes a command, the command is checked and saved in Postgres, and then screens, files and clients are told. These pages explain that road, one part at a time, down to the tables and the code.

How to read these docs
Start with The big picture and Life of a score. Together they take about 45 minutes and give you the whole shape. Then read any part in any order.
Every topic page has the same parts, in the same order:
- In one minute: the answer, before any detail.
- How it works: a drawing and the steps, in plain words.
- A worked example: real values, followed through.
- Low-level design: tables, SQL, code and settings.
- When things go wrong: each failure and what happens.
- Decisions: what we agreed, and why.
- Built today, or still to build: an honest line between the two.
Built today, or agreed design?
These docs describe two things at once, and each page keeps them apart:
- What runs today. The code that carried the Asian Games 2026: the workflow engine, the bridge, the console, Scout imports, the feed builder and the delivery worker.
- What we agreed to build. The rebuild design, decided section by section between 29 Sep and 7 Oct 2026. It fixes what the Games taught us: one build path in the delivery-worker, Redis for pull, a central alert service, a read-only copy, and more.
"Built today" was checked against the code on branch feat/result-feeds at commit 76ef1e2 (24 Sep 2026), the code the Games ran on. main has 10 newer commits. Most merge this same branch; the one real change is a schema addition on 30 Sep (PR #155), covered on The data model page.
Where a number appears, it says where it came from: measured (and where), taken from the code, or an estimate.
Every page
Start here
- The big pictureEvery part of omnium on one page, and how a change moves through it.
- Life of a scoreOne goal, followed from the scorer's tap to the client's file, step by step.
- GlossaryEvery word we use, in one plain sentence each.
Foundations
- Goals, users and numbersWho uses omnium, what it must do, and the numbers it is held to.
- Truth and ownershipWhich record is the truth, who may change it, and how pins protect hand edits.
- The data modelSport, competition, fixture, participant: the tables everything hangs on.
Getting data in
- Imports from ScoutHow provider data arrives, is compared, and becomes commands.
- Commands and the workflow engineThe one road every change takes: key, lock, check, apply, answer.
- Writing a workflow in codeCommands, validations and actions, read line by line from the real flows plugin.
- The live scoring engineScorecard and event-by-event scoring, saved state, replay and checks.
- Sport plugins and rule versionsHow a sport is added, released, pinned and changed safely.
People and screens
- Console and scorer appsThe screens people score and fix data in, and how they stay fast.
- Bridge and live updatesHow a second screen sees a change in under a second.
Getting data out
- Stats, feeds and deliveryBuilding client files, sending them, Redis for pull, and proof of delivery.
Running it
- Database and the read-only copyWho reads where, lag, growth, partitions and retention.
- Monitoring, logs and alertsOne alert per problem, heartbeats, and one id through every log.
- Lessons from the GamesWhat the Asian Games taught us, and where each lesson landed in the design.
- Build order and what is parkedWhat we build first, and the sections waiting their turn.