A Sri Lankan New Year (Avurudu) community event on 18 April 2026 needed live scores for its traditional games. Game leaders had to score from their phones, and everyone else needed a leaderboard and a schedule without logging in. I built it as an installable web app over 17 and 18 April, finishing on the day of the event.
My role: sole developer. I scoped it, designed the data model and the interface, and built and shipped the app.
The brief
The plan was 20 players and 15 traditional games, some played solo and some in teams. The spec set two targets that everything else served:
- a game leader records a place in three taps or fewer, and
- the leaderboard updates within two seconds of a score being saved.
Everything else (gallery, animations, admin tools) stayed in scope only while those two held. Offline mode, push notifications and multi-event support were cut on purpose, so the build would fit the time.

Who does what
Three roles, enforced in the database with row-level security as well as in the app.
| Role | Can see | Can change |
|---|---|---|
| Admin | Everything, including the activity log | Games, schedule, teams, players, scoring rules, photos |
| Game leader | Their assigned games | Scores for their own games only |
| Viewer (no login) | Leaderboard, per-game results, schedule, TV mode, gallery | Nothing |

From a score to every screen
Score to screen
Connections: Game leader's phone to Server action; Server action to Postgres; Server action to Activity log (logs the entry); Postgres to Realtime; Realtime to Leaderboard; Realtime to TV display.
A score never goes straight from the browser to a table. The server action checks the user's role and validates the payload, then calls one database function that writes every placing for the game at once. Row-level security decides whether this user leads that game, so the database is the real gate and the app check is a second layer. The action then writes the entry to the activity log, and Supabase Realtime pushes the change to every open leaderboard and the TV display.

Scoring rules as data
Each game carries its own scoring rule as configuration, so a game leader never does arithmetic and the admin can change a rule mid-event without a deploy. There are four rule types: by rank, by points, by time, and win or loss. Each has a weight multiplier and a flag for splitting team points between members. Here is a made-up game:
{
"scoring_type": "rank",
"points_per_place": [10, 7, 5, 3, 2, 1],
"participation": 1,
"weight": 1.0,
"team_split": false
}First place earns 10 points, sixth earns 1, and everyone who took part gets 1 more. A heavier final game could set weight to 1.5 without touching code.
Two days, from git
The build, in commit order
- 117 April, 1:41 pm: spec and schemaFirst commit: the written spec and a starter database schema.
- 217 April, afternoon: foundationNext.js scaffold, design tokens, Sinhala and Latin fonts, then the tables, row-level security and the leaderboard views.
- 317 April, evening: public views and loginLeaderboard, schedule, per-game pages and the TV display, all wired to Realtime, with role-based login built alongside.
- 418 April, after midnight: score entryThe three-tap entry flow, the validated scoring payload and the activity log.
- 518 April, early morning: admin and installAdmin screens for games, teams, players and schedule, then an installable app with a service worker and an iOS install prompt.
- 618 April, morning: login changeSwapped emailed sign-in links for email and password, with a reset flow.
- 718 April, 2:32 pm: last commitDebugging score validation on event day.
- planned tasks done
- 41 of 42
- One image-generation task deferred
- Source: Project plan state, 18 April 2026
- games planned
- 15
- With 20 players; the counts on the day were not recorded
- Source: Spec
- leaderboard target
- 2 s
- A design target, not a measurement
- Source: Spec
What was still open
Five human checks were still pending at the last update: installing on iOS and Android, contrast outdoors, a native review of the Sinhala text, and keyboard navigation. I have not recorded how many people used the app on the day.
The game content is bilingual: every game has an English and a Sinhala name and rules. The public interface is bilingual too: headings, navigation, filters and status messages carry Sinhala beside English. The admin screens (scoring, game editing) are mostly English, which was a deliberate cut.
What I'd do next
- Measure the score-to-leaderboard time on a real event network, instead of trusting the target.
- Close the five open checks before reusing it.
- Turn the single hard-coded event into a template, so the next festival is a configuration change rather than a fork.


