Realtime Sports Board
Build an iOS app that shows live sports scores that update by themselves, using WebSockets through URLSession. The hard part isn't showing scores, it's staying correct when the connection is unreliable: the app reconnects automatically with increasing waits, marks scores as possibly out of date while disconnected, ignores updates that arrive out of order, and reloads the full picture after reconnecting so nothing is missed. Favorite teams and the last known scores are saved with SwiftData, so the app opens with data even offline. You'll learn URLSessionWebSocketTask, async/await and AsyncStream, reconnection with backoff, handling out-of-order and duplicate messages, and testing networking code.
- Estimate
- ~12.5h
- Steps
- 7
- Completed by
- 0
- Proposed by
- codeseed.app
SwiftUI · SwiftData · URLSession
Project roadmap
- 01
Define the messages and build a test server
~2hWrite PROTOCOL.md describing the JSON messages: a snapshot (all current games) and a score update (game id, a version number that increases with every change, scores, the minute and status). Write a small test server (for example in Node.js with the ws package, or Python) that sends a snapshot on connect, then random updates, and can be told to drop the connection. Done when: the test server sends snapshots and updates.
- 02
Model games and store them
~1.5hCreate Codable message types and SwiftData models: Game (id, teams, scores, minute, status, version, last updated) and FavoriteTeam. Build a scoreboard screen showing today's games, with favorite teams' games first. Done when: games saved in SwiftData show on the scoreboard, and are still there after restarting.
- 03
Connect with a WebSocket
~2.5hWrite a ScoresClient that opens a URLSessionWebSocketTask, reads messages in a loop with receive(), decodes them and passes them to the app as an AsyncStream. Apply a snapshot by replacing all games, and an update only when its version is newer than the stored one, so old or repeated updates are ignored. Send a ping every 20 seconds to detect dead connections. Done when: scores update live on screen as the test server sends changes.
- 04
Reconnect automatically
~2hWhen the connection drops, reconnect after 1, 2, 4 and up to 30 seconds (plus some random jitter), resetting the wait after a successful connection. Watch network availability with NWPathMonitor to reconnect as soon as the network is back, and disconnect when the app goes to the background. After reconnecting, rely on the new snapshot to catch up. Done when: stopping and restarting the test server makes the app reconnect by itself and show current scores.
- 05
Show connection state and stale data
~1.5hShow a banner with the connection state (Live, Reconnecting or Offline). While not live, show each game's last update time and dim the scores, so the user knows they may be out of date. Animate score changes briefly so updates are noticeable. Done when: disconnecting shows the banner and dimmed scores, and they return to normal after reconnecting.
- 06
Add favorites
~1hLet users mark teams as favorites from a game's detail screen, save them with SwiftData, and pin their games to the top of the scoreboard. Done when: favorite teams' games always appear first, even after restarting.
- 07
Test the client
~2hPut the WebSocket behind a protocol so tests can use a fake connection. Test that old versions are ignored, a snapshot replaces the games, reconnect waits grow and reset correctly, and decoding a broken message doesn't close the connection. Done when: the unit tests pass.
Ready to build this?
Get a GitHub repo and start building. Your AI reviewer checks each step as you go.
Tech stack