Documentation Index
Fetch the complete documentation index at: https://285e39fd5e337e58f16290.sightscreen.app/llms.txt
Use this file to discover all available pages before exploring further.
LA start: two triggers
A Live Activity can be started by two paths. Both converge on the same token registration flow.Trigger 1: User follows a live match
Trigger 2: Orchestrator detects match going live
MatchOrchestrator runs a 30-second polling loop. It detects matches transitioning to live status and handles startup recovery — if the backend restarts while matches are live, the Orchestrator picks them up on the next cycle and creates any missing PENDING records.
LA update
Once a Live Activity is active (has a registered update token), it receives score updates through the event-driven pipeline.LA end: four reasons
A Live Activity can end for four distinct reasons. Each has a different trigger path.1. Match ends
2. User unfollows
3. User dismisses LA on device
4. Token becomes invalid
Token invalidation is self-healing. The Orchestrator’s 30-second loop detects followers who should have an active LA but don’t, and re-sends push-to-start. This handles device restarts, OS-terminated activities, and token rotation.
Token management
Three token types
| Token | Source | Purpose | Lifetime |
|---|---|---|---|
| pushToken | Device registration | Standard push notifications (not LA-specific) | Until app uninstall or OS rotation |
| pushToStartToken | ActivityKit | Allows backend to remotely start a Live Activity | Until app uninstall; registered once |
| updateToken | Per-activity pushTokenUpdates | Update or end a specific Live Activity instance | Tied to the LA instance lifecycle |
Token rotation
iOS can rotate theupdateToken for an active Live Activity at any time. The flow:
- iOS fires
pushTokenUpdateson the Activity object TokenManagerobserves the new token, deduplicates (skips if same as current)- Posts to
POST /matches/:matchId/activity-tokenwith the new token - Backend updates the
live-activitiesrecord in-place (same PK/SK, new token value)
Multi-device support
A single user can have active LAs on multiple devices simultaneously. Thelive-activities table uses userId#deviceId as the sort key, so each device gets its own record. When the LACoordinator fans out pushes, it sends to all active tokens for a match — regardless of how many belong to the same user.
iOS service architecture
The old monolithicLiveActivityService has been split into three focused managers:
TokenManager
Handles all token observation and registration.- Observes
pushToStartTokenchanges on app launch - Observes
pushTokenUpdatesfor each active Live Activity - Deduplicates tokens (skips POST if token hasn’t changed)
- Retries failed token registrations
LifecycleManager
Manages the Activity object lifecycle.- Calls
Activity.request()to create new LAs - Restores existing activities on app relaunch (checks ActivityKit state)
- Runs a stale check: if no update received in 30 minutes, ends the LA locally
- Adopts push-started activities (activities created via push-to-start that need local tracking)
FollowManager
Manages the follow/unfollow user intent and local state.- Calls
POST /user/follow/matchandDELETE /user/follow/match - Persists followed match IDs in
UserDefaultsfor instant UI state - Retries pending unfollows on next app launch (handles offline unfollow)
- Drives the bell icon states:
| State | Bell icon | Meaning |
|---|---|---|
| Not following | Outline bell | Tap to follow |
| Following, LA active | Filled bell | Match followed, LA running |
| Following, LA disabled | Filled bell + warning | Match followed, but no LA permission |
| Pending | Loading indicator | Follow/unfollow in progress |
DynamoDB schema
live-activities table
| Attribute | Type | Description |
|---|---|---|
matchId (PK) | String | The match being followed |
userId#deviceId (SK) | String | Composite key for user + device |
status | String | pending, active, or ended |
updateToken | String | Current APNs update token for this LA |
endReason | String | match_end, user_unfollow, user_dismissed, token_invalid |
createdAt | Number | Epoch timestamp |
ttl | Number | Auto-cleanup after match ends |
active-matches table
| Attribute | Type | Description |
|---|---|---|
matchId (PK) | String | The match being polled |
previousScores | Map | Last known scores per innings (for Tier0 detection) |
cooldowns | Map | Event type → expiry timestamp |
lastBalls | List | Last 30 balls (for Tier1 detection) |
pollerState | String | polling, paused, ended |
lastUpdatedAt | Number | Epoch timestamp |
Related pages
- Live score pipeline — how scores flow from SportMonks through the EventBus to APNs
- Match following — the user action that triggers LA creation
- Device registration — push token types and multi-device support