Files
SportstimeAPI/.planning/codebase/INTEGRATIONS.md
2026-01-18 16:55:09 -06:00

190 lines
6.6 KiB
Markdown

# External Integrations
**Analysis Date:** 2026-01-18
## APIs & External Services
**Apple CloudKit (Primary Data Source):**
- Purpose: Sync game schedules, teams, stadiums, league structure to all users
- Container: `iCloud.com.sportstime.app`
- Database: Public (read-only for users, admin writes via Python uploader)
- Client: `Core/Services/CloudKitService.swift`
- Sync: `Core/Services/CanonicalSyncService.swift`
- Record types: `Game`, `Team`, `Stadium`, `LeagueStructure`, `TeamAlias`, `StadiumAlias`, `Sport`
- Auth: User iCloud account (automatic), server-to-server JWT (Python uploader)
**Apple MapKit:**
- Purpose: Geocoding, routing, map snapshots, EV charger search, POI search
- Services used:
- `MKLocalSearch` - Address and POI search (`LocationService.swift`)
- `MKDirections` - Driving routes and ETA (`LocationService.swift`)
- `MKMapSnapshotter` - Static map images for PDF (`Export/Services/MapSnapshotService.swift`)
- `MKLocalPointsOfInterestRequest` - EV chargers (`EVChargingService.swift`)
- Client: `Core/Services/LocationService.swift`, `Core/Services/EVChargingService.swift`
- Auth: Automatic via Apple frameworks
- Rate limits: Apple's standard MapKit limits
**Apple StoreKit 2:**
- Purpose: In-app subscriptions (Pro tier)
- Products: `com.sportstime.pro.monthly`, `com.sportstime.pro.annual`
- Client: `Core/Store/StoreManager.swift`
- Features gated: Trip limit (1 free, unlimited Pro)
**Sports League APIs (Official):**
| API | URL | Sport | Reliability | Client |
|-----|-----|-------|-------------|--------|
| MLB Stats API | `https://statsapi.mlb.com/api/v1` | MLB | Official | `ScoreAPIProviders/MLBStatsProvider.swift` |
| NHL Stats API | `https://api-web.nhle.com/v1` | NHL | Official | `ScoreAPIProviders/NHLStatsProvider.swift` |
| NBA Stats API | `https://stats.nba.com/stats` | NBA | Unofficial | `ScoreAPIProviders/NBAStatsProvider.swift` |
**NBA Stats API Notes:**
- Requires specific headers to avoid 403 (User-Agent, Referer, x-nba-stats-origin, x-nba-stats-token)
- May break without notice (unofficial)
**Sports Reference Sites (Scraping Fallback):**
| Site | URL Pattern | Sport | Client |
|------|-------------|-------|--------|
| Baseball-Reference | `baseball-reference.com/boxes/?month=M&day=D&year=Y` | MLB | `HistoricalGameScraper.swift` |
| Basketball-Reference | `basketball-reference.com/boxscores/?month=M&day=D&year=Y` | NBA | `HistoricalGameScraper.swift` |
| Hockey-Reference | `hockey-reference.com/boxscores/?month=M&day=D&year=Y` | NHL | `HistoricalGameScraper.swift` |
| Pro-Football-Reference | `pro-football-reference.com/boxscores/...` | NFL | `HistoricalGameScraper.swift` |
- Uses SwiftSoup for HTML parsing
- On-device scraping (no server costs, unlimited scale)
- Cached per-session to avoid redundant requests
## Data Storage
**SwiftData (Local):**
- Purpose: Offline-first data storage, user trips, preferences
- Location: App sandbox (automatic)
- CloudKit sync: Disabled (`cloudKitDatabase: .none`)
- Schema: See `SportsTimeApp.swift` ModelContainer configuration
**CloudKit Public Database (Remote):**
- Purpose: Shared schedule data for all users
- Container: `iCloud.com.sportstime.app`
- Access: Read (all users), Write (admin via Python uploader)
- Sync method: Date-based delta sync (modificationDate filtering)
**URLCache (Images):**
- Purpose: Cache team logos and stadium photos
- Memory: 50 MB
- Disk: 100 MB
- Path: `ImageCache`
- Client: `Export/Services/RemoteImageService.swift`
**File Storage:**
- Local filesystem only for PDF export (temporary)
- Photo library access for visit photo imports
**Caching:**
- In-memory game score cache: `ScoreResolutionCache.swift`
- In-memory scraper cache: `HistoricalGameScraper.swift`
- URLSession cache: Team logos, stadium photos
## Authentication & Identity
**iCloud (Automatic):**
- Users authenticate via their iCloud account
- Required for: CloudKit sync, poll voting identity
- Optional: App works offline without iCloud
**CloudKit Server-to-Server (Python Uploader):**
- JWT authentication with ECDSA P-256 key
- Key ID and team ID from Apple Developer portal
- Used by `Scripts/sportstime_parser/uploaders/cloudkit.py`
## Monitoring & Observability
**Error Tracking:**
- None (no Sentry, Crashlytics, etc.)
- Errors logged to console via `os.Logger`
**Logs:**
- `os.Logger` subsystem: `com.sportstime.app`
- Categories: `BackgroundSyncManager`, `NetworkMonitor`
- Rich console output in Python scraper
## CI/CD & Deployment
**Hosting:**
- iOS App Store (planned)
- CloudKit public database (Apple infrastructure)
**CI Pipeline:**
- None configured (no GitHub Actions, Xcode Cloud, etc.)
**Data Pipeline:**
- Python CLI (`sportstime-parser`) scrapes schedules
- Uploads to CloudKit via CloudKit Web Services API
- iOS apps sync from CloudKit automatically
## Background Processing
**BGTaskScheduler:**
- Refresh task: `com.sportstime.app.refresh` (periodic CloudKit sync)
- Processing task: `com.sportstime.app.db-cleanup` (overnight heavy sync)
- Manager: `Core/Services/BackgroundSyncManager.swift`
**Network Monitoring:**
- `NWPathMonitor` triggers sync on connectivity restoration
- Debounce: 2.5 seconds (handles WiFi/cellular handoffs)
- Manager: `Core/Services/NetworkMonitor.swift`
**Push Notifications:**
- CloudKit subscriptions for data changes
- Silent notifications (`shouldSendContentAvailable`)
- Subscription IDs: `game-updates`, `league-structure-updates`, `team-alias-updates`, `stadium-alias-updates`
## Environment Configuration
**Required Environment Variables:**
*iOS App:*
- None required (CloudKit container ID hardcoded)
*Python Uploader:*
- CloudKit key ID (or in config)
- CloudKit team ID (or in config)
- ECDSA private key path
**Secrets Location:**
- iOS: Entitlements file (`SportsTime.entitlements`)
- Python: Environment variables or local config file
## Webhooks & Callbacks
**Incoming:**
- CloudKit silent push notifications (background sync trigger)
- Deep links: `sportstime://poll/{shareCode}` (poll sharing)
**Outgoing:**
- None
## Rate Limiting
**Internal Rate Limiter:**
- `Core/Services/RateLimiter.swift`
- Per-provider keys: `mlb_stats`, `nba_stats`, `nhl_stats`
- Prevents API abuse when resolving historical game scores
**Provider Auto-Disable:**
- Official APIs: Never auto-disabled
- Unofficial APIs: Disabled after 3 failures (24h cooldown)
- Scraped sources: Disabled after 2 failures (24h cooldown)
## Polls (Group Trip Planning)
**CloudKit-Based Polling:**
- Record type: `TripPoll`, `PollVote`
- Share codes: 6-character uppercase alphanumeric
- Deep link: `sportstime://poll/{shareCode}`
- Service: `Core/Services/PollService.swift`
---
*Integration audit: 2026-01-18*