Dartobert
A darts scoring app I built because existing apps kept throwing away the data I actually wanted. Every throw is stored. Every stat is calculable.
Tech Stack
Angular because it's the framework I know best — and a mobile-first SPA with Angular Material felt right for a game tracking app. NestJS keeps TypeScript across the entire stack. PostgreSQL because I need a real SQL engine to run arbitrary stats queries over the full throw history.
Dartobert is a full-stack darts game tracking app I built from scratch — because every app I tried either made scoring awkward for groups, or quietly discarded the data I actually wanted to analyze.
Why I built it
Two things frustrated me with existing darts apps:
Shared scoring is a mess. Most apps are designed for one player, on one phone. If you’re playing with friends, everyone either needs their own device or you pass one phone around. That kills the flow of the game. Dartobert puts scoring on a single shared device — anyone can enter their throw, and each player still gets their own account and stats after the game.
Stats get thrown away. Almost every darts app aggregates data at recording time. They store your average, not your throws. Once the game is done, that’s it. I wanted the opposite: every single dart in the database, forever. That way I can calculate anything, retroactively, without having to decide upfront what metrics matter.
What it does
The core loop is simple: create a game, add players, enter throws. But there’s a lot built around that:
- Player profiles with full statistics — averages, checkout percentages, 180s, highest finishes, score distributions, streaks
- Skill profiles — a radar chart breaking down different aspects of a player’s game
- Game overview with per-leg burndown charts, comparison tables, and dartboard heatmaps for every player
- Head-to-head records between players, visible on public profiles
- Tournament and league mode for more structured competition
- Real-time updates via WebSockets — scores update instantly across all connected devices
- Freemium model — free users get access to their last 20 games; Pro users get full history
How it’s built
The backend is a NestJS 11 REST API with WebSocket support, using TypeORM and PostgreSQL 16. Feature modules handle auth, games, players, statistics, tournaments, leagues, notifications, and more. Migrations are required — no synchronize: true in production.
The frontend is an Angular 21 SPA using Angular Material with a custom dark theme, optimized for mobile (max-width 420px default). Newer components use Angular signals for state; RxJS stays for HTTP and WebSocket streams.
Everything runs in Docker containers on a Kubernetes cluster, with separate images for frontend and backend. GitHub Actions handles CI and builds.
Current state
Started in September 2024. Now at v0.24, actively maintained. The most recent version added per-player time statistics, public profile filter controls, and a significant backend performance overhaul (up to 10x faster statistics endpoints).
The app is running — I use it with friends regularly. Turns out we are better software developers than dart players.
Related posts
