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.
Backend layer diagram
The backend follows a layered architecture with clear dependency boundaries. LA v2 introduces a Providers layer for event detection, display state building, and delivery coordination.Event-driven pipeline
The core of LA v2. Data flows through the pipeline on every poll tick: Tier0 events are high-priority (wickets, centuries, hat-tricks) and getapns-priority: 10 for immediate delivery. Tier1 events are routine updates (score ticks, over completions) and get apns-priority: 5.
CooldownFilter prevents event flooding (e.g., suppressing repeated wicket alerts within a window). StalenessFilter drops events derived from data that has not actually changed since the last push.
Layer responsibilities
Routes
HTTP handlers that parse requests, validate input with Zod schemas, call the appropriate service, and return responses. Routes contain no business logic.Middleware
Runs before route handlers. Handles:- Auth — verifies Cognito JWT tokens, extracts user context
- Logging — request/response logging with correlation IDs
Services
Business logic for API-facing operations. Services orchestrate between repositories, providers, and other services. HubDataService builds data for the admin UI (Pavilion).Providers
The event detection and delivery layer. This is where the LA v2 pipeline lives:| Provider | Responsibility |
|---|---|
| MatchEventBus | Routes raw poll data through the detection pipeline |
| LACoordinator | Coordinates APNs delivery with priority and batching |
| Tier0EventDetector | Detects high-priority events (wickets, milestones) |
| Tier1EventDetector | Detects routine score changes and over completions |
| CooldownFilter | Suppresses repeated events within a cooldown window |
| StalenessFilter | Drops events when underlying data has not changed |
| DisplayStateBuilder | Builds UnifiedDisplayState from match data |
| ApnsDeliveryService | Clean interface for sending APNs pushes |
| LivescoreProvider | Fetches and normalizes live score data from SportMonks |
| LiveMatchReconciler | Reconciles matches that drop off SportMonks livescores |
Clients
Thin wrappers around external HTTP APIs. Handle request formatting, auth headers, rate limiting, and response parsing. The SportMonks client lives here, wrapped in Cockatiel resilience policies.Repositories
CRUD abstractions over DynamoDB tables. Each repository owns one table and exposes typed methods (getById, query, put, delete). Key repositories in LA v2:
- ActiveMatchRepository — owns the
active-matchestable (match processing state, previous scores, cooldowns) - LiveActivityRepository — owns the
live-activitiestable (LA sessions, update tokens)
Schemas
Zod schemas for request validation, response shaping, and internal data type definitions. Shared across layers.Jobs
Background tasks that run on schedules or triggers:| Job | Responsibility |
|---|---|
| MatchOrchestrator | Manages full match lifecycle (replaces prematch job). Starts/stops pollers, handles transitions. |
| ScorePoller | Reusable poller with Cockatiel resilience. Runs for live and replay matches. |
| MarqueePoller | Polls the marquee league at higher frequency with ball-by-ball data. |
| FixtureSyncJob | Syncs fixture lists from SportMonks on a schedule. |
Dependency injection via factories
How factories.ts works
How factories.ts works
The backend uses a factory-based dependency injection pattern defined in
factories.ts. The composition order is:createRepositories()— instantiates all repository instances (ActiveMatchRepository, LiveActivityRepository, etc.)createClients()— instantiates external API clients (SportMonks)createServices()— instantiates services with repository and client dependenciescreateProviders()— instantiates providers (MatchEventBus, LACoordinator, detectors, filters, DisplayStateBuilder) with service and repository dependencies
- No layer creates its own dependencies
- Swapping implementations (e.g., for testing) only requires changing the factory
- Circular dependencies are caught at startup, not at runtime
- The full dependency graph is visible in one file
Rules of thumb
- Routes never import repositories or clients directly
- Services never make HTTP calls — that is what clients and providers are for
- Repositories never contain business logic or call other repositories
- Providers own the event detection pipeline — services call providers, not the other way around
- Jobs always go through services or providers, never bypass them
- If you are unsure where code belongs, ask: “Does this make a decision?” If yes, it belongs in a service. “Does this detect or deliver?” If yes, it belongs in a provider.