Initial commit: SportsTime trip planning app
- Three-scenario planning engine (A: date range, B: selected games, C: directional routes) - GeographicRouteExplorer with anchor game support for route exploration - Shared ItineraryBuilder for travel segment calculation - TravelEstimator for driving time/distance estimation - SwiftUI views for trip creation and detail display - CloudKit integration for schedule data - Python scraping scripts for sports schedules 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
145
Scripts/CLOUDKIT_SETUP.md
Normal file
145
Scripts/CLOUDKIT_SETUP.md
Normal file
@@ -0,0 +1,145 @@
|
||||
# CloudKit Setup Guide for SportsTime
|
||||
|
||||
## 1. Configure Container in Apple Developer Portal
|
||||
|
||||
1. Go to [Apple Developer Portal](https://developer.apple.com/account)
|
||||
2. Navigate to **Certificates, Identifiers & Profiles** > **Identifiers**
|
||||
3. Select your App ID or create one for `com.sportstime.app`
|
||||
4. Enable **iCloud** capability
|
||||
5. Click **Configure** and create container: `iCloud.com.sportstime.app`
|
||||
|
||||
## 2. Configure in Xcode
|
||||
|
||||
1. Open `SportsTime.xcodeproj` in Xcode
|
||||
2. Select the SportsTime target
|
||||
3. Go to **Signing & Capabilities**
|
||||
4. Ensure **iCloud** is added (should already be there)
|
||||
5. Check **CloudKit** is selected
|
||||
6. Select container `iCloud.com.sportstime.app`
|
||||
|
||||
## 3. Create Record Types in CloudKit Dashboard
|
||||
|
||||
Go to [CloudKit Dashboard](https://icloud.developer.apple.com/dashboard)
|
||||
|
||||
### Record Type: `Stadium`
|
||||
|
||||
| Field | Type | Notes |
|
||||
|-------|------|-------|
|
||||
| `stadiumId` | String | Unique identifier |
|
||||
| `name` | String | Stadium name |
|
||||
| `city` | String | City |
|
||||
| `state` | String | State/Province |
|
||||
| `location` | Location | CLLocation (lat/lng) |
|
||||
| `capacity` | Int(64) | Seating capacity |
|
||||
| `sport` | String | NBA, MLB, NHL |
|
||||
| `teamAbbrevs` | String (List) | Team abbreviations |
|
||||
| `source` | String | Data source |
|
||||
| `yearOpened` | Int(64) | Optional |
|
||||
|
||||
**Indexes**:
|
||||
- `sport` (Queryable, Sortable)
|
||||
- `location` (Queryable) - for radius searches
|
||||
- `teamAbbrevs` (Queryable)
|
||||
|
||||
### Record Type: `Team`
|
||||
|
||||
| Field | Type | Notes |
|
||||
|-------|------|-------|
|
||||
| `teamId` | String | Unique identifier |
|
||||
| `name` | String | Full team name |
|
||||
| `abbreviation` | String | 3-letter code |
|
||||
| `sport` | String | NBA, MLB, NHL |
|
||||
| `city` | String | City |
|
||||
|
||||
**Indexes**:
|
||||
- `sport` (Queryable, Sortable)
|
||||
- `abbreviation` (Queryable)
|
||||
|
||||
### Record Type: `Game`
|
||||
|
||||
| Field | Type | Notes |
|
||||
|-------|------|-------|
|
||||
| `gameId` | String | Unique identifier |
|
||||
| `sport` | String | NBA, MLB, NHL |
|
||||
| `season` | String | e.g., "2024-25" |
|
||||
| `dateTime` | Date/Time | Game date and time |
|
||||
| `homeTeamRef` | Reference | Reference to Team |
|
||||
| `awayTeamRef` | Reference | Reference to Team |
|
||||
| `venueRef` | Reference | Reference to Stadium |
|
||||
| `isPlayoff` | Int(64) | 0 or 1 |
|
||||
| `broadcastInfo` | String | TV channel |
|
||||
| `source` | String | Data source |
|
||||
|
||||
**Indexes**:
|
||||
- `sport` (Queryable, Sortable)
|
||||
- `dateTime` (Queryable, Sortable)
|
||||
- `homeTeamRef` (Queryable)
|
||||
- `awayTeamRef` (Queryable)
|
||||
- `season` (Queryable)
|
||||
|
||||
## 4. Import Data
|
||||
|
||||
After creating record types:
|
||||
|
||||
```bash
|
||||
# 1. First scrape the data
|
||||
cd Scripts
|
||||
python3 scrape_schedules.py --sport all --season 2025 --output ./data
|
||||
|
||||
# 2. Run the import script (requires running from Xcode or with proper entitlements)
|
||||
# The Swift script cannot run standalone - use the app or create a macOS command-line tool
|
||||
```
|
||||
|
||||
### Alternative: Import via App
|
||||
|
||||
Add this to your app for first-run data import:
|
||||
|
||||
```swift
|
||||
// In AppDelegate or App init
|
||||
Task {
|
||||
let importer = CloudKitImporter()
|
||||
|
||||
// Load JSON from bundle or downloaded file
|
||||
if let stadiumsURL = Bundle.main.url(forResource: "stadiums", withExtension: "json"),
|
||||
let gamesURL = Bundle.main.url(forResource: "games", withExtension: "json") {
|
||||
// Import stadiums first
|
||||
let stadiumsData = try Data(contentsOf: stadiumsURL)
|
||||
let stadiums = try JSONDecoder().decode([ScrapedStadium].self, from: stadiumsData)
|
||||
let count = try await importer.importStadiums(from: stadiums)
|
||||
print("Imported \(count) stadiums")
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 5. Security Roles (CloudKit Dashboard)
|
||||
|
||||
For the **Public Database**:
|
||||
|
||||
| Role | Stadium | Team | Game |
|
||||
|------|---------|------|------|
|
||||
| World | Read | Read | Read |
|
||||
| Authenticated | Read | Read | Read |
|
||||
| Creator | Read/Write | Read/Write | Read/Write |
|
||||
|
||||
Users should only read from public database. Write access is for your admin imports.
|
||||
|
||||
## 6. Testing
|
||||
|
||||
1. Build and run the app on simulator or device
|
||||
2. Check CloudKit Dashboard > **Data** to see imported records
|
||||
3. Use **Logs** tab to debug any issues
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### "Container not found"
|
||||
- Ensure container is created in Developer Portal
|
||||
- Check entitlements file has correct container ID
|
||||
- Clean build and re-run
|
||||
|
||||
### "Permission denied"
|
||||
- Check Security Roles in CloudKit Dashboard
|
||||
- Ensure app is signed with correct provisioning profile
|
||||
|
||||
### "Record type not found"
|
||||
- Create record types in Development environment first
|
||||
- Deploy schema to Production when ready
|
||||
Reference in New Issue
Block a user