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:
148
CLAUDE.md
Normal file
148
CLAUDE.md
Normal file
@@ -0,0 +1,148 @@
|
||||
# CLAUDE.md
|
||||
|
||||
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||
|
||||
## Build & Run Commands
|
||||
|
||||
```bash
|
||||
# Build the iOS app
|
||||
xcodebuild -project SportsTime.xcodeproj -scheme SportsTime -destination 'platform=iOS Simulator,name=iPhone 17,OS=26.2' build
|
||||
|
||||
# Run tests
|
||||
xcodebuild -project SportsTime.xcodeproj -scheme SportsTime -destination 'platform=iOS Simulator,name=iPhone 17,OS=26.2' test
|
||||
|
||||
# Run specific test suite
|
||||
xcodebuild -project SportsTime.xcodeproj -scheme SportsTime -destination 'platform=iOS Simulator,name=iPhone 17,OS=26.2' -only-testing:SportsTimeTests/TripPlanningEngineTests test
|
||||
|
||||
# Run a single test
|
||||
xcodebuild -project SportsTime.xcodeproj -scheme SportsTime -destination 'platform=iOS Simulator,name=iPhone 17,OS=26.2' -only-testing:SportsTimeTests/TestClassName/testMethodName test
|
||||
|
||||
# Data scraping (Python)
|
||||
cd Scripts && pip install -r requirements.txt
|
||||
python scrape_schedules.py --sport all --season 2026
|
||||
```
|
||||
|
||||
## Architecture Overview
|
||||
|
||||
This is an iOS app for planning multi-stop sports road trips. It uses **Clean MVVM** with feature-based modules.
|
||||
|
||||
### Three-Layer Architecture
|
||||
|
||||
1. **Presentation Layer** (`Features/`): SwiftUI Views + @Observable ViewModels organized by feature (Home, Trip, Schedule, Settings)
|
||||
|
||||
2. **Domain Layer** (`Planning/`): Trip planning logic
|
||||
- `TripPlanningEngine` - Main orchestrator, 7-step algorithm
|
||||
- `RouteOptimizer` - TSP solver (exact for <8 stops, heuristic otherwise)
|
||||
- `ScheduleMatcher` - Finds games along route corridor
|
||||
- `TripScorer` - Multi-factor scoring (game quality, route efficiency, leisure balance)
|
||||
|
||||
3. **Data Layer** (`Core/`):
|
||||
- `Models/Domain/` - Pure Swift structs (Trip, Game, Stadium, Team)
|
||||
- `Models/CloudKit/` - CKRecord wrappers for public database
|
||||
- `Models/Local/` - SwiftData models for local persistence (SavedTrip, UserPreferences)
|
||||
- `Services/` - CloudKitService (schedules), LocationService (geocoding/routing)
|
||||
|
||||
### Data Storage Strategy
|
||||
|
||||
- **CloudKit Public DB**: Read-only schedules, stadiums, teams (shared across all users)
|
||||
- **SwiftData Local**: User's saved trips, preferences, cached schedules
|
||||
- **No network dependency** for trip planning once schedules are synced
|
||||
|
||||
### Key Data Flow
|
||||
|
||||
```
|
||||
TripCreationView → TripCreationViewModel → PlanningRequest
|
||||
→ TripPlanningEngine (ScheduleMatcher + RouteOptimizer + TripScorer)
|
||||
→ PlanningResult → Trip → TripDetailView → SavedTrip (persist)
|
||||
```
|
||||
|
||||
## Important Patterns
|
||||
|
||||
- ViewModels use `@Observable` (not ObservableObject)
|
||||
- All planning engine components are `actor` types for thread safety
|
||||
- Domain models are pure Codable structs; SwiftData models wrap them via encoded `Data` fields
|
||||
- CloudKit container ID: `iCloud.com.sportstime.app`
|
||||
|
||||
## Key View Components
|
||||
|
||||
### TripDetailView (`Features/Trip/Views/TripDetailView.swift`)
|
||||
|
||||
Displays trip itinerary with conflict detection for same-day games in different cities.
|
||||
|
||||
**Conflict Detection System:**
|
||||
- `detectConflicts(for: ItineraryDay)` - Checks if multiple stops have games on the same calendar day
|
||||
- Returns `DayConflictInfo` with `hasConflict`, `conflictingStops`, and `conflictingCities`
|
||||
|
||||
**RouteOptionsCard (Expandable):**
|
||||
- Shows when multiple route options exist for the same day (conflicting games in different cities)
|
||||
- Collapsed: Shows "N route options" with city list, tap to expand
|
||||
- Expanded: Shows each option as a `RouteOptionCard` with numbered badge (Option 1, Option 2, etc.)
|
||||
- Single routes (no conflict): Uses regular `DayCard`, auto-expanded
|
||||
|
||||
**RouteOptionCard:**
|
||||
- Individual option within the expandable RouteOptionsCard
|
||||
- Shows option number badge, city name, games at that stop, and travel info
|
||||
|
||||
**DayCard Component (non-conflict mode):**
|
||||
- `specificStop: TripStop?` - When provided, shows only that stop's games
|
||||
- `primaryCityForDay` - Returns the city for the card
|
||||
- `gamesOnThisDay` - Returns games filtered to the calendar day
|
||||
|
||||
**Visual Design:**
|
||||
- Expandable cards have orange border and branch icon
|
||||
- Option badges are blue capsules
|
||||
- Chevron indicates expand/collapse state
|
||||
|
||||
## Scripts
|
||||
|
||||
`Scripts/scrape_schedules.py` scrapes NBA/MLB/NHL schedules from multiple sources (Basketball-Reference, Baseball-Reference, Hockey-Reference, official APIs) for cross-validation. See `Scripts/DATA_SOURCES.md` for source URLs and rate limits.
|
||||
|
||||
## Test Suites
|
||||
|
||||
- **TripPlanningEngineTests** (50 tests) - Routing logic, must-see games, required destinations, EV charging, edge cases
|
||||
- **DayCardTests** (11 tests) - DayCard conflict detection, warning display, stop filtering, edge cases
|
||||
- **DuplicateGameIdTests** (2 tests) - Regression tests for handling duplicate game IDs in JSON data
|
||||
|
||||
## Bug Fix Protocol
|
||||
|
||||
Whenever fixing a bug:
|
||||
1. **Write a regression test** that reproduces the bug before fixing it
|
||||
2. **Include edge cases** - test boundary conditions, null/empty inputs, and related scenarios
|
||||
3. **Confirm all tests pass** by running the test suite before considering the fix complete
|
||||
4. **Name tests descriptively** - e.g., `test_DayCard_OnlyShowsGamesFromPrimaryStop_WhenMultipleStopsOverlapSameDay`
|
||||
|
||||
Example workflow:
|
||||
```bash
|
||||
# 1. Write failing test that reproduces the bug
|
||||
# 2. Fix the bug
|
||||
# 3. Verify the new test passes along with all existing tests
|
||||
xcodebuild -project SportsTime.xcodeproj -scheme SportsTime -destination 'platform=iOS Simulator,name=iPhone 17,OS=26.2' test
|
||||
```
|
||||
|
||||
## Future Phases
|
||||
|
||||
### Phase 2: AI-Powered Trip Planning
|
||||
|
||||
**Natural Language Trip Planning**
|
||||
- Allow users to describe trips in plain English: "plan me a baseball trip from Texas" or "I want to see the Yankees and Red Sox in one weekend"
|
||||
- Parse intent, extract constraints (sports, dates, locations, budget)
|
||||
- Generate trip suggestions from natural language input
|
||||
|
||||
**On-Device Intelligence (Apple Foundation Models)**
|
||||
- Use Apple's Foundation Models framework (iOS 26+) for on-device AI processing
|
||||
- Privacy-preserving - no data leaves the device
|
||||
- Features to enable:
|
||||
- Smart trip suggestions based on user history
|
||||
- Natural language query understanding
|
||||
- Personalized game recommendations
|
||||
- Conversational trip refinement ("add another game" / "make it shorter")
|
||||
|
||||
**Implementation Notes:**
|
||||
- Foundation Models requires iOS 26+ and Apple Silicon
|
||||
- Use `@Generable` for structured output parsing
|
||||
- Implement graceful fallback for unsupported devices
|
||||
- See `axiom:axiom-foundation-models` skill for patterns
|
||||
|
||||
## User Instruction
|
||||
|
||||
Do not commit code without prompting the user first.
|
||||
Reference in New Issue
Block a user