Add specialized row components for the new unified itinerary system:
- DayHeaderRow: Day number, date display, and add item button
- GameItemRow: Prominent card with sport color bar for games
- TravelItemRow: Gold-styled travel segments with drag handle
- CustomItemRow: Minimal custom items with icon, title, and optional time
All views follow existing Theme patterns and use SportColorBar for consistency.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Removed:
- CustomItineraryItem
- TravelDayOverride
- CustomItemService
- CustomItemSubscriptionService
- TravelOverrideService
- CustomItemRow
These are replaced by unified ItineraryItem model and service.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Debounced updates (1.5s), local-first with silent retry.
Supports game, travel, and custom item kinds.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Validates travel positions based on game locations:
- Travel must be after ALL departure city games
- Travel must be before ALL arrival city games
- Custom items have no constraints
- Games are fixed (cannot be moved)
12 tests covering all constraint scenarios including edge cases.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replaces CustomItineraryItem and TravelDayOverride with single model.
Supports game, travel, and custom item kinds.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Complete design for TripDetailView refactor with constrained drag-and-drop:
- Games are fixed anchors (immovable, ordered by time)
- Travel is movable with hard constraints (after departure games, before arrival games)
- Custom items are freely movable anywhere
Key decisions from 100-question brainstorming session:
- Unified ItineraryItem model (replaces CustomItineraryItem + TravelDayOverride)
- Separate testable ItineraryConstraints type
- Full structure stored (not derived)
- Debounced sync, local-first, last-write-wins
- Invalid zones dim during drag, barrier games highlight
- Gap opens at drop position, haptic feedback throughout
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Unified data model approach:
- Single ItineraryItem type (travel becomes a category)
- Constraint validation layer for travel rules
- Red zone visual feedback for invalid drops
- Simplified flattening logic
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
13-task plan covering:
- TravelDayOverride model update with sortOrder
- CloudKit schema update
- Flattening logic to sort games/travel/custom together
- Drag constraint updates for flexible custom items
- Regression tests
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Design for fully customizable item ordering in trip itineraries:
- Custom items can go anywhere (before/after games, any day)
- Travel constrained to valid day range but freely positioned within days
- Games get sortOrder for positioning but remain immovable
- TravelPosition stored in SwiftData, synced to CloudKit
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Merge Add button into DaySectionHeaderView to prevent items from being
dragged between the day header and Add button. The Add button now uses
a SwiftUI Button with its own tap handler instead of row selection.
Changes:
- Remove .addButton case from ItineraryRowItem enum
- Update DaySectionHeaderView to include Add button on the right
- Pass onAddTapped callback through configureDayHeaderCell
- Remove AddButtonRowView (no longer needed)
- Update documentation to reflect new row structure
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Move Add button to appear immediately after Day header (before games)
- Split games out of dayHeader into separate row for correct ordering
- Add 600+ lines of inline documentation to ItineraryTableViewController
- Document architecture decisions, data flow, constraints, and algorithms
- Add function-level comments explaining drag/drop, sortOrder calculation
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
11 bite-sized TDD tasks to replace anchor-based positioning with
simple (day, sortOrder) model. Includes migration path for CloudKit.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replace anchor-based positioning with simple sort-order system:
- Custom items use (day, sortOrder: Double) instead of anchors
- Travel segments have hard guardrails based on city game schedules
- Route waypoints follow exact visual display order
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Fixed map header not updating in ItineraryTableViewWrapper using Coordinator pattern
- Added routeVersion UUID to force Map re-render when routes change
- Fixed determineAnchor to scan backwards for correct anchor context
- Added location support to CustomItineraryItem (lat/lng/address)
- Added MapKit place search to AddItemSheet
- Added extensive debug logging for route waypoint calculation
Known issues:
- Custom items still not routing correctly after drag/drop
- Anchor type determination may still have bugs
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Replace SwiftUI drag-drop with native UITableViewController for fluid reordering
- Add ItineraryTableViewController with native cell reordering and validation
- Add ItineraryTableViewWrapper for SwiftUI integration with header support
- Fix infinite layout loop by tracking header adjustment state
- Map and stats now scroll as table header with itinerary content
- Travel segments constrained to valid day ranges during drag
- One Add button per day (after game > after travel > rest day)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add TravelDayOverride model for storing user-customized travel day positions
- Add TravelOverrideService for CloudKit CRUD operations on travel overrides
- Add CKTravelDayOverride CloudKit model wrapper
- Refactor itinerarySections to validate travel day bounds (must be after last game in departure city)
- Travel segments can now be dragged to different days within valid range
- Persist travel day overrides to CloudKit for cross-device sync
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Only load polls once on initial view appearance, not every tab switch
- Only show spinner when there's no existing data (first load)
- Subsequent refreshes update content in place without showing spinner
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add visual drop target indicator showing where items will land
- Use stable travel anchor IDs (city names) instead of UUIDs that regenerate
- Fix findDayForTravelSegment to look forward to arrival day, not backward
- Add moveItemToBeginning() for inserting at position 0 when dropping on sections
- Sort custom items by sortOrder in all filters
- Sync shifted items to CloudKit after reorder
- Add opaque backgrounds to CustomItemRow and TravelSection to hide timeline
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Specification-first + property-based TDD methodology to surface
logic bugs by testing expected behavior, not current implementation.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Comprehensive plan to delete broken tests and create new Swift Testing
coverage for Planning Engine, Domain Models, and Services with parallel
execution across multiple simulators.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Detailed step-by-step plan for extending brutalist style to:
- TripDetailView
- SavedTripsListView
- ScheduleListView
- SettingsView
Includes StyleProvider protocol, adaptive routers, and complete
code snippets for each task.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Design for extending Brutalist style from home-screen-only to app-wide:
- StyleProvider protocol for shape/typography language
- Adaptive view routers for each major screen
- Brutalist variants for TripDetail, MyTrips, Schedule, Settings
- Colors still controlled by user's selected Theme
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add CustomItineraryItem domain model with sortOrder for ordering
- Add CKCustomItineraryItem CloudKit wrapper for persistence
- Create CustomItemService for CRUD operations
- Create CustomItemSubscriptionService for real-time sync
- Add AppDelegate for push notification handling
- Add AddItemSheet for creating/editing items
- Add CustomItemRow with drag handle
- Update TripDetailView with continuous vertical timeline
- Enable drag-to-reorder using .draggable/.dropDestination
- Add inline "Add" buttons after games and travel segments
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Design for allowing users to add personal items (restaurants, hotels,
activities, notes) to saved trip itineraries with drag-to-reorder and
CloudKit sync.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Two fixes for route planning and display:
1. GameDAGRouter: Same-day game transitions now respect maxDailyDrivingHours
constraint. Previously, a 12:05 AM game in Arlington could connect to an
11:40 PM game in Milwaukee (19+ hour drive) because the code only checked
available time, not the 8-hour daily limit.
2. TripDetailView: Itinerary sections now group by (day, city) not just day.
Games in different cities on the same calendar day are shown as separate
sections with travel segments between them.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When updating a vote, CloudKit requires the server's changeTag to modify
existing records. Creating a new CKRecord caused "record to insert already
exists" errors. Now fetches the existing record first before saving.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add GamePickerStep with sheet-based Sport → Team → Game selection
- Add TeamPickerStep with sheet-based Sport → Team selection
- Add LocationsStep for start/end location selection with round trip toggle
- Update TripWizardViewModel with mode-specific fields and validation
- Update TripWizardView with conditional step rendering per mode
- Update ReviewStep with mode-aware validation display
- Fix gameFirst mode to derive date range from selected games
Each planning mode now shows only relevant steps:
- By Dates: Dates → Sports → Regions → Route → Repeat → Must Stops
- By Games: Game Picker → Route → Repeat → Must Stops
- By Route: Locations → Dates → Sports → Route → Repeat → Must Stops
- Follow Team: Team Picker → Dates → Route → Repeat → Must Stops
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Increase card height from 160 to 175 and add extra bottom padding
to prevent date text from being cut off.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
New design style combines the Classic layout with subtle animated
backgrounds featuring floating sports icons and route lines.
Animations are slow and unobtrusive to avoid distracting from content.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add AppearanceMode enum with system, light, and dark options
- Add AppearanceManager singleton to persist user preference
- Add appearance section in SettingsView with icon and description
- Apply preferredColorScheme at app root for immediate effect
- Include appearance mode in reset to defaults
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add ShareCardSportBackground with floating sport icons for share cards
- Share cards now show sport-specific backgrounds (single or multiple sports)
- Achievement collection share respects sport filter selection
- Add ability to share individual achievements from detail sheet
- Trip wizard ReviewStep highlights missing required fields in red
- Add FieldValidation model to TripWizardViewModel
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add `displayName` computed property to Trip model that always
generates city list with " → " separator for consistent display
- Replace all `trip.name` usages with `trip.displayName` in UI files
- Update SuggestedTripsGenerator to use " → " separator
- Update PDFGenerator to use displayName for PDF titles
This ensures all trip names display consistently regardless of when
the trip was created or how the name was originally stored.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Refactor TripDetailView to fetch games from AppDataProvider when not
provided, adding loading state indicator for better UX
- Update all callers (25+ HomeContent variants, TripOptionsView, HomeView)
to use simpler TripDetailView(trip:) initializer
- Fix PollDetailView sheet issue by using sheet(item:) instead of
sheet(isPresented:) to prevent blank screen on first tap
- Improve PollDetailView UI with Theme styling, icons, and better
visual hierarchy for share code, voting status, and results sections
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Delete TripCreationView.swift and TripCreationViewModel.swift (unused)
- Extract TripOptionsView to standalone file
- Extract DateRangePicker and DayCell to standalone file
- Extract LocationSearchSheet and CityInputType to standalone file
- Fix TripWizardView to pass games dictionary to TripOptionsView
- Remove debug print statements from TripDetailView
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Fix suggested trips showing wrong sports for cross-country trips
- Remove quick start sections from home variants (Classic, Spotify)
- Remove dead quickActions code from HomeView
- Fix pace capsule animation in TripCreationView
- Add text wrapping to achievement descriptions
- Improve poll parsing with better error handling
- Various sharing system improvements
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replace old ProgressCardGenerator with protocol-based sharing architecture
supporting trips, achievements, and stadium progress. Features 8 color
themes, Instagram Stories optimization (1080x1920), and reusable card
components with map snapshots.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
13-task plan covering:
- Delete old ProgressCardGenerator
- Create ShareableContent protocol and 8 theme presets
- Create shared card components (header, footer, stats, maps)
- Create generators for progress, trip, and achievement cards
- Create ShareService for Instagram and system sharing
- Create SharePreviewView and ShareButton
- Integrate into ProgressTabView, TripDetailView, AchievementsListView
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Extract deep link handling into dedicated DeepLinkHandler service
- Add MockData+Polls.swift with reusable test mocks for Trip, TripStop,
TripPoll, PollVote, and PollResults
- Update SportsTimeApp to use DeepLinkHandler.shared
- Add error alert for deep link failures
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add complete group trip polling feature allowing users to share trips
with friends for voting using Borda count scoring.
New components:
- TripPoll and PollVote domain models with share codes and rankings
- LocalTripPoll and LocalPollVote SwiftData models for persistence
- CKTripPoll and CKPollVote CloudKit record wrappers
- PollService actor for CloudKit CRUD operations and subscriptions
- PollCreation/Detail/Voting views and view models
- Deep link handling for sportstime://poll/{code} URLs
- Debug Pro status override toggle in Settings
Integration:
- HomeView shows polls section in My Trips
- SportsTimeApp registers SwiftData models and handles deep links
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add debug toggle in Settings to override Pro subscription status (DEBUG builds only, defaults to true)
- Auto-validate wizard step flags on appear so button enables without explicit user interaction:
- DatesStep: calls updateHasSetDates() on appear
- RoutePreferenceStep: sets hasSetRoutePreference on appear
- RepeatCitiesStep: sets hasSetRepeatCities on appear
Previously, canPlanTrip required all flags to be explicitly set by user interaction, even when valid defaults were showing.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
12 tasks with TDD workflow:
- Domain, CloudKit, and SwiftData models
- PollService for CloudKit operations
- Creation and detail ViewModels
- SwiftUI views with vote ranking
- Deep link handling