Files
Sportstime/CLAUDE.md
Trey t 2281440bf8 Update CLAUDE.md with export layer docs and future roadmap
- Document Export layer (PDFGenerator, asset services)
- Add iOS 26 API notes (deprecated CLGeocoder, Swift 6 patterns)
- Add Documentation section pointing to docs/
- Expand Future Phases with market research findings (bucket list, group coordination, fan community)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-08 13:30:49 -06:00

207 lines
8.9 KiB
Markdown

# 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)
4. **Export Layer** (`Export/`):
- `PDFGenerator` - Generates PDF trip itineraries with maps, photos, and attractions
- `ExportService` - Orchestrates PDF export with asset prefetching
- `Services/MapSnapshotService` - Generates static map images via MKMapSnapshotter
- `Services/RemoteImageService` - Downloads/caches team logos and stadium photos
- `Services/POISearchService` - Finds nearby restaurants, attractions via MKLocalSearch
- `Services/PDFAssetPrefetcher` - Parallel prefetching of all PDF assets
### 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`
- `PDFGenerator` and `ExportService` are `@MainActor final class` (not actors) because they access MainActor-isolated UI properties and use UIKit drawing
### iOS 26 API Notes
**Deprecated APIs** (use with `@available(iOS, deprecated: 26.0)` annotation):
- `CLGeocoder` → Use `MKLocalSearch` with `.address` result type instead
- `MKPlacemark` properties (locality, administrativeArea, etc.) → Still work but deprecated; use `MKMapItem` properties where possible
- `MKMapItem.location` is non-optional in iOS 26 (returns `CLLocation`, not `CLLocation?`)
**Swift 6 Concurrency**:
- Use `@retroactive` for protocol conformances on types you don't own (e.g., `CLLocationCoordinate2D: @retroactive Codable`)
- When capturing `var` in `async let`, create immutable copies first to avoid Swift 6 warnings
## 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.
## Documentation
The `docs/` directory contains project documentation:
- `MARKET_RESEARCH.md` - Competitive analysis and feature recommendations based on sports travel app market research (January 2026)
## 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
See `docs/MARKET_RESEARCH.md` for full competitive analysis and feature prioritization.
### 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
### Phase 3: Stadium Bucket List
**Progress Tracking**
- Visual map showing visited vs. remaining stadiums per league
- Digital passport/stamps for each visited stadium
- Achievement badges (e.g., "All NL West", "Coast to Coast", "10 Stadiums")
- Shareable progress cards for social media
**Competitors**: Baseball Bucket List, Sports Venue Tracker, MLB BallPark Pass-Port (physical)
### Phase 4: Group Trip Coordination
**Collaborative Planning**
- Invite friends to collaborate on trip planning
- Polling/voting on game choices and destinations
- Expense splitting integration
- Shared itinerary with real-time sync
- Role delegation (lodging, tickets, restaurants)
**Competitors**: SquadTrip, Troupe, Howbout
### Phase 5: Fan Community
**Social Features**
- Stadium tips from locals (best food, parking, pre-game bars)
- Fan meetup coordination for away games
- Trip reviews and ratings
- Discussion forums for specific stadiums
**Competitor**: Fantrip (fan-to-fan stays and local tips)
## User Instruction
Do not commit code without prompting the user first.