Files
Sportstime/docs/stadiumGuide.md
Trey t dbb0099776 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>
2026-01-26 18:13:12 -06:00

284 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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** |