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:
328
ARCHITECTURE.md
Normal file
328
ARCHITECTURE.md
Normal file
@@ -0,0 +1,328 @@
|
||||
# Sport Travel Planner - Architecture Document
|
||||
|
||||
## 1. High-Level Architecture
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
│ PRESENTATION LAYER │
|
||||
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
|
||||
│ │ HomeView │ │ TripView │ │ScheduleView│ │ SettingsView│ │
|
||||
│ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ │
|
||||
│ │ │ │ │ │
|
||||
│ ┌──────▼──────┐ ┌──────▼──────┐ ┌──────▼──────┐ ┌──────▼──────┐ │
|
||||
│ │HomeViewModel│ │TripViewModel│ │ScheduleVM │ │ SettingsVM │ │
|
||||
│ └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘ │
|
||||
└─────────────────────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
│ DOMAIN LAYER │
|
||||
│ ┌─────────────────────┐ ┌─────────────────────┐ ┌─────────────────────┐ │
|
||||
│ │ TripPlanner │ │ RouteOptimizer │ │ ScheduleMatcher │ │
|
||||
│ │ (Orchestrator) │ │ (Algorithm) │ │ (Game Finder) │ │
|
||||
│ └──────────┬──────────┘ └──────────┬──────────┘ └──────────┬──────────┘ │
|
||||
│ │ │ │ │
|
||||
│ ┌──────────▼────────────────────────▼────────────────────────▼──────────┐ │
|
||||
│ │ TripPlanningEngine │ │
|
||||
│ │ • Constraint Solver • Route Graph • Scoring (CoreML) │ │
|
||||
│ └───────────────────────────────────────────────────────────────────────┘ │
|
||||
└─────────────────────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
│ DATA LAYER │
|
||||
│ ┌─────────────────────┐ ┌─────────────────────┐ ┌─────────────────────┐ │
|
||||
│ │ TripRepository │ │ ScheduleRepository │ │ StadiumRepository │ │
|
||||
│ │ (SwiftData) │ │ (CloudKit) │ │ (CloudKit) │ │
|
||||
│ └─────────────────────┘ └─────────────────────┘ └─────────────────────┘ │
|
||||
│ │
|
||||
│ ┌─────────────────────────────────────────────────────────────────────────┐│
|
||||
│ │ CloudKit Sync Manager ││
|
||||
│ │ • Public Database (Schedules, Stadiums) ││
|
||||
│ │ • Shared Database (Collaborative Trips - Phase 2) ││
|
||||
│ └─────────────────────────────────────────────────────────────────────────┘│
|
||||
└─────────────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## 2. Project Structure
|
||||
|
||||
```
|
||||
SportsTime/
|
||||
├── Core/
|
||||
│ ├── Models/
|
||||
│ │ ├── Domain/ # Pure Swift domain models
|
||||
│ │ │ ├── Sport.swift
|
||||
│ │ │ ├── Team.swift
|
||||
│ │ │ ├── Game.swift
|
||||
│ │ │ ├── Stadium.swift
|
||||
│ │ │ ├── Trip.swift
|
||||
│ │ │ ├── TripStop.swift
|
||||
│ │ │ ├── TravelSegment.swift
|
||||
│ │ │ └── TripPreferences.swift
|
||||
│ │ ├── CloudKit/ # CKRecord-backed models
|
||||
│ │ │ ├── CKGame.swift
|
||||
│ │ │ ├── CKStadium.swift
|
||||
│ │ │ └── CKTeam.swift
|
||||
│ │ └── Local/ # SwiftData models
|
||||
│ │ ├── SavedTrip.swift
|
||||
│ │ ├── UserPreferences.swift
|
||||
│ │ └── CachedSchedule.swift
|
||||
│ ├── Services/
|
||||
│ │ ├── CloudKitService.swift
|
||||
│ │ ├── LocationService.swift
|
||||
│ │ ├── DistanceMatrixService.swift
|
||||
│ │ └── ExportService.swift
|
||||
│ ├── Utilities/
|
||||
│ │ └── DateFormatter+Extensions.swift
|
||||
│ └── Extensions/
|
||||
│ └── CLLocation+Extensions.swift
|
||||
├── Features/
|
||||
│ ├── Home/
|
||||
│ │ ├── Views/
|
||||
│ │ │ └── HomeView.swift
|
||||
│ │ └── ViewModels/
|
||||
│ │ └── HomeViewModel.swift
|
||||
│ ├── Trip/
|
||||
│ │ ├── Views/
|
||||
│ │ │ ├── TripCreationView.swift
|
||||
│ │ │ ├── TripDetailView.swift
|
||||
│ │ │ ├── TripStopCard.swift
|
||||
│ │ │ └── TripPreferencesForm.swift
|
||||
│ │ └── ViewModels/
|
||||
│ │ ├── TripCreationViewModel.swift
|
||||
│ │ └── TripDetailViewModel.swift
|
||||
│ ├── Schedule/
|
||||
│ │ ├── Views/
|
||||
│ │ │ ├── ScheduleListView.swift
|
||||
│ │ │ └── GameCard.swift
|
||||
│ │ └── ViewModels/
|
||||
│ │ └── ScheduleViewModel.swift
|
||||
│ └── Settings/
|
||||
│ ├── Views/
|
||||
│ │ └── SettingsView.swift
|
||||
│ └── ViewModels/
|
||||
│ └── SettingsViewModel.swift
|
||||
├── Planning/
|
||||
│ ├── Engine/
|
||||
│ │ ├── TripPlanningEngine.swift
|
||||
│ │ ├── RouteOptimizer.swift
|
||||
│ │ ├── ScheduleMatcher.swift
|
||||
│ │ └── ConstraintSolver.swift
|
||||
│ ├── Scoring/
|
||||
│ │ ├── TripScorer.swift
|
||||
│ │ └── RoutePreferenceModel.mlmodel
|
||||
│ └── Models/
|
||||
│ ├── PlanningRequest.swift
|
||||
│ ├── PlanningResult.swift
|
||||
│ └── RouteGraph.swift
|
||||
├── Export/
|
||||
│ ├── PDFGenerator.swift
|
||||
│ ├── TripShareManager.swift
|
||||
│ └── Templates/
|
||||
│ └── TripPDFTemplate.swift
|
||||
└── Resources/
|
||||
└── Assets.xcassets
|
||||
```
|
||||
|
||||
## 3. Data Flow
|
||||
|
||||
### Trip Creation Flow
|
||||
```
|
||||
User Input → TripCreationViewModel → PlanningRequest
|
||||
│
|
||||
▼
|
||||
TripPlanningEngine
|
||||
│
|
||||
┌──────────────────────┼──────────────────────┐
|
||||
▼ ▼ ▼
|
||||
ScheduleMatcher RouteOptimizer ConstraintSolver
|
||||
│ │ │
|
||||
└──────────────────────┼──────────────────────┘
|
||||
▼
|
||||
TripScorer (CoreML)
|
||||
│
|
||||
▼
|
||||
PlanningResult → Trip
|
||||
│
|
||||
▼
|
||||
TripDetailView (Display)
|
||||
│
|
||||
▼
|
||||
SavedTrip (SwiftData persist)
|
||||
```
|
||||
|
||||
## 4. CloudKit Schema
|
||||
|
||||
### Public Database Records
|
||||
|
||||
| Record Type | Fields |
|
||||
|-------------|--------|
|
||||
| `Team` | `id`, `name`, `abbreviation`, `sport`, `city`, `stadiumRef` |
|
||||
| `Stadium` | `id`, `name`, `city`, `state`, `latitude`, `longitude`, `capacity`, `teamRefs` |
|
||||
| `Game` | `id`, `homeTeamRef`, `awayTeamRef`, `stadiumRef`, `dateTime`, `sport`, `season` |
|
||||
| `Sport` | `id`, `name`, `seasonStart`, `seasonEnd`, `iconName` |
|
||||
|
||||
### Relationships
|
||||
- Team → Stadium (reference)
|
||||
- Game → Team (home, away references)
|
||||
- Game → Stadium (reference)
|
||||
|
||||
## 5. Trip Planning Algorithm
|
||||
|
||||
### Step 1: Input Parsing
|
||||
```
|
||||
Parse user preferences into PlanningRequest:
|
||||
- Start/End locations (geocoded)
|
||||
- Date range
|
||||
- Must-see games (locked stops)
|
||||
- Travel mode (drive/fly)
|
||||
- Constraints (max hours/day, EV, lodging type)
|
||||
```
|
||||
|
||||
### Step 2: Game Discovery
|
||||
```
|
||||
FOR each sport in selected sports:
|
||||
Query games within date range
|
||||
Filter by geographic relevance (within reasonable detour)
|
||||
Include must-see games regardless of detour
|
||||
Score games by:
|
||||
- Team popularity
|
||||
- Rivalry factor
|
||||
- Venue uniqueness
|
||||
```
|
||||
|
||||
### Step 3: Route Graph Construction
|
||||
```
|
||||
Build weighted graph:
|
||||
Nodes = [Start, Stadiums with games, End]
|
||||
Edges = Travel segments with:
|
||||
- Distance
|
||||
- Drive time (or flight availability)
|
||||
- Scenic score (if scenic preference)
|
||||
- EV charging availability
|
||||
```
|
||||
|
||||
### Step 4: Constraint Solving
|
||||
```
|
||||
Apply hard constraints:
|
||||
- Must-see games are mandatory nodes
|
||||
- Max stops OR max duration
|
||||
- Game times must be reachable
|
||||
|
||||
Apply soft constraints (scored):
|
||||
- Leisure level (rest days)
|
||||
- Driving hours per day
|
||||
- Scenic preference
|
||||
```
|
||||
|
||||
### Step 5: Route Optimization
|
||||
```
|
||||
IF stops < 8:
|
||||
Use exact TSP solution (branch and bound)
|
||||
ELSE:
|
||||
Use nearest-neighbor heuristic + 2-opt improvement
|
||||
|
||||
Respect temporal constraints (game dates)
|
||||
```
|
||||
|
||||
### Step 6: Itinerary Generation
|
||||
```
|
||||
FOR each day in trip:
|
||||
Assign:
|
||||
- Travel segments
|
||||
- Game attendance
|
||||
- Lodging location
|
||||
- Rest periods (based on leisure level)
|
||||
- EV charging stops (if applicable)
|
||||
```
|
||||
|
||||
### Step 7: Scoring & Ranking
|
||||
```
|
||||
Score final itinerary:
|
||||
- Game quality score
|
||||
- Route efficiency score
|
||||
- Fatigue score (inverse)
|
||||
- User preference alignment
|
||||
|
||||
Return top 3 alternatives if possible
|
||||
```
|
||||
|
||||
## 6. CoreML Strategy
|
||||
|
||||
### On-Device Models
|
||||
|
||||
| Model | Purpose | Input | Output |
|
||||
|-------|---------|-------|--------|
|
||||
| `RoutePreferenceModel` | Score route alternatives | Route features vector | Preference score 0-1 |
|
||||
| `LeisureBalancer` | Optimize rest distribution | Trip features | Rest day placement |
|
||||
| `PersonalizationModel` | Learn user preferences | Historical trips | Preference weights |
|
||||
|
||||
### Training Approach
|
||||
1. **Initial Model**: Pre-trained on synthetic trip data
|
||||
2. **On-Device Learning**: Core ML updatable model
|
||||
3. **Features**: Trip duration, sports mix, driving hours, scenic detours, game density
|
||||
|
||||
### Model Integration
|
||||
```swift
|
||||
// Scoring a route option
|
||||
let scorer = try RoutePreferenceModel()
|
||||
let input = RoutePreferenceModelInput(
|
||||
totalDistance: route.distance,
|
||||
gameCount: route.games.count,
|
||||
scenicScore: route.scenicRating,
|
||||
avgDriveHours: route.averageDailyDrive,
|
||||
leisureRatio: route.restDays / route.totalDays
|
||||
)
|
||||
let score = try scorer.prediction(input: input).preferenceScore
|
||||
```
|
||||
|
||||
## 7. SwiftUI Screen Flow
|
||||
|
||||
```
|
||||
┌─────────────────┐
|
||||
│ Launch/Splash │
|
||||
└────────┬────────┘
|
||||
▼
|
||||
┌─────────────────┐
|
||||
│ HomeView │◄──────────────────────────────────┐
|
||||
│ - Saved Trips │ │
|
||||
│ - Quick Start │ │
|
||||
│ - Schedule │ │
|
||||
└────────┬────────┘ │
|
||||
│ │
|
||||
▼ │
|
||||
┌─────────────────┐ ┌─────────────────┐ │
|
||||
│TripCreationView │────►│ GamePickerSheet │ │
|
||||
│ - Preferences │ │ (Must-See Games)│ │
|
||||
│ - Locations │ └─────────────────┘ │
|
||||
│ - Constraints │ │
|
||||
└────────┬────────┘ │
|
||||
│ "Plan Trip" │
|
||||
▼ │
|
||||
┌─────────────────┐ │
|
||||
│ PlanningView │ │
|
||||
│ (Loading State) │ │
|
||||
└────────┬────────┘ │
|
||||
▼ │
|
||||
┌─────────────────┐ ┌─────────────────┐ │
|
||||
│ TripDetailView │────►│ ExportSheet │ │
|
||||
│ - Day-by-Day │ │ - PDF │ │
|
||||
│ - Map View │ │ - Share │ │
|
||||
│ - Games List │ │ - Email │ │
|
||||
│ - Save Trip │ └─────────────────┘ │
|
||||
└────────┬────────┘ │
|
||||
│ Save │
|
||||
▼ │
|
||||
┌─────────────────┐ │
|
||||
│ SavedTripsView │───────────────────────────────────┘
|
||||
└─────────────────┘
|
||||
```
|
||||
|
||||
## 8. Key Dependencies
|
||||
|
||||
- **SwiftData**: Local persistence for trips and preferences
|
||||
- **CloudKit**: Shared schedules and stadium data
|
||||
- **MapKit**: Route visualization and distance calculations
|
||||
- **CoreML**: On-device trip scoring and personalization
|
||||
- **PDFKit**: Trip export functionality
|
||||
- **CoreLocation**: User location and geocoding
|
||||
Reference in New Issue
Block a user