chore: remove scraper, add docs, add marketing-videos gitignore
- Remove Scripts/ directory (scraper no longer needed) - Add themed background documentation to CLAUDE.md - Add .gitignore for marketing-videos to prevent node_modules tracking Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
283
docs/stadiumGuide.md
Normal file
283
docs/stadiumGuide.md
Normal file
@@ -0,0 +1,283 @@
|
||||
# Team-First Planning Mode Implementation Plan
|
||||
|
||||
## Overview
|
||||
|
||||
**Feature:** Select teams (not dates), find optimal trip windows across the entire season.
|
||||
|
||||
**Use Case:** User has 3 stadiums left on bucket list. Select those 3 teams, app finds all windows throughout the season where all 3 teams play at home within a reasonable trip duration.
|
||||
|
||||
## Requirements
|
||||
|
||||
| Constraint | Value |
|
||||
|------------|-------|
|
||||
| Sport scope | Single sport per search |
|
||||
| Start city | Flexible (algorithm picks optimal) |
|
||||
| Max duration | `teams × 2` days (3 teams = 6 days) |
|
||||
| Drive limit | Existing settings value |
|
||||
| Optimize for | Shortest duration + minimal backtracking |
|
||||
| Results | Top 10 options with reasoning |
|
||||
| Season | Current season only |
|
||||
|
||||
---
|
||||
|
||||
## Architecture
|
||||
|
||||
### Current Flow (Date-First)
|
||||
```
|
||||
User picks dates → Fetch games in range → Find routes → Rank → Display
|
||||
```
|
||||
|
||||
### New Flow (Team-First)
|
||||
```
|
||||
User picks teams → Fetch ALL home games for those teams (full season)
|
||||
→ Generate sliding windows (N-day chunks)
|
||||
→ Filter to windows where all teams have ≥1 home game
|
||||
→ For each valid window: find optimal routes
|
||||
→ Rank by duration + miles → Return top 10
|
||||
```
|
||||
|
||||
### Reuse Ratio: ~90%
|
||||
|
||||
| Component | Status | Notes |
|
||||
|-----------|--------|-------|
|
||||
| `allGames(for sports:)` | ✅ Exists | Full season fetch |
|
||||
| Sliding window generator | ✅ Exists | In ScenarioBPlanner |
|
||||
| GameDAGRouter | ✅ Exists | Supports anchor constraints |
|
||||
| ItineraryBuilder | ✅ Exists | No changes needed |
|
||||
| Max driving time | ✅ Exists | `UserPreferences.maxDrivingHoursPerDriver` |
|
||||
| Multi-team selection UI | ❌ New | Currently single-team only |
|
||||
| Team-first planner | ❌ New | ~300 lines adapting Scenario B |
|
||||
| Window optimization | ⚠️ Adapt | Season = 180+ days → need sampling |
|
||||
|
||||
---
|
||||
|
||||
## Parallel Track Structure
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
│ PHASE 1 (Parallel) │
|
||||
├──────────────────────┬──────────────────────┬──────────────────────────────┤
|
||||
│ Track A: Models │ Track B: Planner │ Track C: UI Components │
|
||||
│ (Agent 1) │ (Agent 2) │ (Agent 3) │
|
||||
├──────────────────────┼──────────────────────┼──────────────────────────────┤
|
||||
│ A1. Add teamFirst │ B1. Create │ C1. Create TeamPickerView │
|
||||
│ to PlanningMode │ ScenarioEPlanner │ (multi-select grid) │
|
||||
│ │ skeleton │ │
|
||||
│ A2. Add │ B2. Implement │ C2. Create │
|
||||
│ selectedTeamIds │ window generator │ TeamFirstWizardStep │
|
||||
│ to TripPrefs │ for teams │ │
|
||||
│ │ │ │
|
||||
│ A3. Update │ B3. Implement route │ C3. Update WizardViewModel │
|
||||
│ PlanningRequest │ finding with │ for teamFirst mode │
|
||||
│ computed props │ team anchors │ │
|
||||
└──────────────────────┴──────────────────────┴──────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
│ PHASE 2 (Parallel) │
|
||||
├─────────────────────────────────┬───────────────────────────────────────────┤
|
||||
│ Track D: Integration │ Track E: Tests │
|
||||
│ (Agent 4) │ (Agent 5) │
|
||||
├─────────────────────────────────┼───────────────────────────────────────────┤
|
||||
│ D1. Update ScenarioPlannerFactory│ E1. Unit tests for window generator │
|
||||
│ to detect teamFirst mode │ │
|
||||
│ │ E2. Unit tests for ScenarioEPlanner │
|
||||
│ D2. Wire TeamPickerView into │ │
|
||||
│ existing wizard flow │ E3. Integration test: 3 teams → routes │
|
||||
│ │ │
|
||||
│ D3. Add teamFirst option to │ E4. Edge case tests (no windows, etc.) │
|
||||
│ planning mode selector │ │
|
||||
└─────────────────────────────────┴───────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
│ PHASE 3 (Sequential) │
|
||||
├─────────────────────────────────────────────────────────────────────────────┤
|
||||
│ F1. End-to-end testing & bug fixes │
|
||||
│ F2. Performance optimization (if needed) │
|
||||
└─────────────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Detailed Task Specifications
|
||||
|
||||
### Track A: Data Models (Agent 1)
|
||||
|
||||
**A1. Add `teamFirst` to PlanningMode**
|
||||
```
|
||||
File: SportsTime/Core/Models/Domain/TripPreferences.swift
|
||||
Action: Add case to PlanningMode enum
|
||||
```
|
||||
|
||||
**A2. Add `selectedTeamIds` to TripPreferences**
|
||||
```
|
||||
File: SportsTime/Core/Models/Domain/TripPreferences.swift
|
||||
Action: Add `var selectedTeamIds: Set<String> = []`
|
||||
Action: Add `var teamFirstMaxDays: Int` computed as `selectedTeamIds.count * 2`
|
||||
```
|
||||
|
||||
**A3. Update PlanningRequest computed properties**
|
||||
```
|
||||
File: SportsTime/Planning/Models/PlanningModels.swift
|
||||
Action: Add computed property to extract teams for selected IDs
|
||||
Action: Add helper to get all home games for selected teams
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Track B: Scenario Planner (Agent 2)
|
||||
|
||||
**B1. Create ScenarioEPlanner skeleton**
|
||||
```
|
||||
File: SportsTime/Planning/Scenarios/ScenarioEPlanner.swift (NEW)
|
||||
Action: Create class conforming to ScenarioPlanner protocol
|
||||
Action: Implement required methods with TODOs
|
||||
```
|
||||
|
||||
**B2. Implement window generator for teams**
|
||||
```
|
||||
File: SportsTime/Planning/Scenarios/ScenarioEPlanner.swift
|
||||
Action: Generate all N-day windows across season
|
||||
Action: Filter to windows where ALL selected teams have ≥1 home game
|
||||
Action: Cap at 50 windows (sample if more)
|
||||
```
|
||||
|
||||
**B3. Implement route finding with team anchors**
|
||||
```
|
||||
File: SportsTime/Planning/Scenarios/ScenarioEPlanner.swift
|
||||
Action: For each valid window, collect all home games for selected teams
|
||||
Action: Pass to GameDAGRouter with those games as anchors
|
||||
Action: Build itineraries, rank by duration + miles
|
||||
Action: Return top 10
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Track C: UI Components (Agent 3)
|
||||
|
||||
**C1. Create TeamPickerView**
|
||||
```
|
||||
File: SportsTime/Features/Trip/Views/TeamPickerView.swift (NEW)
|
||||
Action: Grid of team logos/names for selected sport
|
||||
Action: Multi-select with checkmarks
|
||||
Action: Show count badge "3 selected"
|
||||
Action: Binding to Set<String> for team IDs
|
||||
```
|
||||
|
||||
**C2. Create TeamFirstWizardStep**
|
||||
```
|
||||
File: SportsTime/Features/Trip/Views/Wizard/TeamFirstWizardStep.swift (NEW)
|
||||
Action: Wrapper that uses TeamPickerView
|
||||
Action: Validation: require ≥2 teams selected
|
||||
Action: "Find trips for these teams" CTA
|
||||
```
|
||||
|
||||
**C3. Update WizardViewModel for teamFirst mode**
|
||||
```
|
||||
File: SportsTime/Features/Trip/ViewModels/TripWizardViewModel.swift
|
||||
Action: Add teamFirst step configuration
|
||||
Action: Handle selectedTeamIds state
|
||||
Action: Skip date selection step when in teamFirst mode
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Track D: Integration (Agent 4)
|
||||
|
||||
**D1. Update ScenarioPlannerFactory**
|
||||
```
|
||||
File: SportsTime/Planning/Scenarios/ScenarioPlannerFactory.swift
|
||||
Action: Add detection for teamFirst mode
|
||||
Action: Return ScenarioEPlanner when selectedTeamIds.count >= 2
|
||||
```
|
||||
|
||||
**D2. Wire TeamPickerView into wizard**
|
||||
```
|
||||
File: SportsTime/Features/Trip/Views/Wizard/TripWizardView.swift
|
||||
Action: Add case for teamFirst step
|
||||
Action: Navigation flow: Sport → Teams → (skip dates) → Results
|
||||
```
|
||||
|
||||
**D3. Add teamFirst to mode selector**
|
||||
```
|
||||
File: SportsTime/Features/Trip/Views/Wizard/PlanningModeSelector.swift
|
||||
Action: Add "Teams First" option with icon
|
||||
Action: Description: "Pick teams, we'll find the best windows"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Track E: Tests (Agent 5)
|
||||
|
||||
**E1. Unit tests for window generator**
|
||||
```
|
||||
File: SportsTimeTests/Planning/ScenarioEPlannerTests.swift (NEW)
|
||||
Tests:
|
||||
- 3 teams, 6-day window → finds valid windows
|
||||
- Window with only 2 of 3 teams → excluded
|
||||
- Empty season → returns empty
|
||||
- Sampling works when >50 windows
|
||||
```
|
||||
|
||||
**E2. Unit tests for ScenarioEPlanner**
|
||||
```
|
||||
File: SportsTimeTests/Planning/ScenarioEPlannerTests.swift
|
||||
Tests:
|
||||
- Returns PlanningResult with routes
|
||||
- All routes include all selected teams
|
||||
- Routes sorted by duration ascending
|
||||
- Respects max driving time constraint
|
||||
```
|
||||
|
||||
**E3. Integration test**
|
||||
```
|
||||
File: SportsTimeTests/Planning/TeamFirstIntegrationTests.swift (NEW)
|
||||
Tests:
|
||||
- Full flow: 3 MLB teams → top 10 routes
|
||||
- Each route visits all 3 stadiums
|
||||
- Total duration ≤ 6 days
|
||||
```
|
||||
|
||||
**E4. Edge case tests**
|
||||
```
|
||||
File: SportsTimeTests/Planning/ScenarioEPlannerTests.swift
|
||||
Tests:
|
||||
- Teams with no overlapping games → graceful error
|
||||
- Single team selected → validation error
|
||||
- Teams in same city → treated as separate stops
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Risks & Mitigations
|
||||
|
||||
| Risk | Mitigation |
|
||||
|------|------------|
|
||||
| Season = 180+ days = too many windows | Sample every 2nd day, or limit to weekends |
|
||||
| No valid windows (teams never align) | Early validation + user feedback |
|
||||
| Slow computation (10+ windows × routing) | Cap at 50 windows, parallelize |
|
||||
| Teams in same city (e.g., 2 NYC teams) | Treat as separate stops (different stadiums) |
|
||||
|
||||
---
|
||||
|
||||
## Test Strategy
|
||||
|
||||
1. **Unit:** Window generator finds correct multi-team windows
|
||||
2. **Unit:** Anchor constraints include all teams' home games
|
||||
3. **Integration:** 3 teams → returns routes visiting all 3
|
||||
4. **Edge:** Teams with non-overlapping seasons → graceful "no trips found"
|
||||
5. **Perf:** Full MLB season (2,430 games) completes in <5s
|
||||
|
||||
---
|
||||
|
||||
## Estimated Effort
|
||||
|
||||
| Track | New Code | Modified Code | Total |
|
||||
|-------|----------|---------------|-------|
|
||||
| A: Models | 50 lines | 20 lines | 70 lines |
|
||||
| B: Planner | 300 lines | 0 lines | 300 lines |
|
||||
| C: UI | 250 lines | 50 lines | 300 lines |
|
||||
| D: Integration | 30 lines | 80 lines | 110 lines |
|
||||
| E: Tests | 400 lines | 0 lines | 400 lines |
|
||||
| **Total** | **1,030 lines** | **150 lines** | **1,180 lines** |
|
||||
Reference in New Issue
Block a user