Commit Graph

13 Commits

Author SHA1 Message Date
Trey t
91c5eac22d fix: codebase audit fixes — safety, accessibility, and production hygiene
Address 16 issues from external audit:
- Move StoreKit transaction listener ownership to StoreManager singleton with proper deinit
- Remove noisy VoiceOver announcements, add missing accessibility on StatPill and BootstrapLoadingView
- Replace String @retroactive Identifiable with IdentifiableShareCode wrapper
- Add crash guard in AchievementEngine getContributingVisitIds + cache stadium lookups
- Pre-compute GamesHistoryViewModel filtered properties to avoid redundant SwiftUI recomputation
- Remove force-unwraps in ProgressMapView with safe guard-let fallback
- Add diff-based update gating in ItineraryTableViewWrapper to prevent unnecessary reloads
- Replace deprecated UIScreen.main with UIWindowScene lookup
- Add deinit task cancellation in ScheduleViewModel and SuggestedTripsGenerator
- Wrap ~234 unguarded print() calls across 27 files in #if DEBUG

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 00:07:53 -06:00
Trey t
999b5a1190 Fix game times with UTC data, restructure schedule by date
- Update games_canonical.json to use ISO 8601 UTC timestamps (game_datetime_utc)
- Fix BootstrapService timezone-aware parsing for venue-local fallback
- Fix thread-unsafe shared DateFormatter in RichGame local time display
- Bump SchemaVersion to 4 to force re-bootstrap with correct UTC data
- Restructure schedule view: group by date instead of sport, with sport
  icons on each row and date section headers showing game counts
- Fix schedule row backgrounds using Theme.cardBackground instead of black
- Sort games by UTC time with local-time tiebreaker for same-instant games

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 11:43:39 -06:00
Trey t
d0cbf75fc4 fix: 14 audit fixes — concurrency, memory, performance, accessibility
Second audit round addressing data races, task stacking, unbounded
caches, and VoiceOver gaps across 7 files.

Concurrency:
- Move NSItemProvider @State access into MainActor block (3 drop handlers)
- Cancel stale ScheduleViewModel tasks on rapid filter changes

Memory:
- Replace unbounded image dict with LRUCache(countLimit: 50)
- Replace demo-mode asyncAfter with cancellable Task

Performance:
- Wrap debug NBA print() in #if DEBUG
- Cache visitsById via @State + onChange instead of per-render computed
- Pre-compute sportProgressFractions in ProgressViewModel
- Replace allGames computed property with hasGames bool check
- Cache sortedTrips via @State + onChange in SavedTripsListView

Accessibility:
- Add combined VoiceOver label to progress ring
- Combine away/home team text into single readable phrase
- Hide decorative StadiumDetailSheet icon from VoiceOver
- Add explicit accessibilityLabel to SportFilterChip
- Add combined accessibilityLabel to GameRowView

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 22:30:30 -06:00
Trey t
2917ae22b1 feat: add PostHog analytics with full event tracking across app
Integrate self-hosted PostHog (SPM) with AnalyticsManager singleton wrapping
all SDK calls. Adds ~40 type-safe events covering trip planning, schedule,
progress, IAP, settings, polls, export, and share flows. Includes session
replay, autocapture, network telemetry, privacy opt-out toggle in Settings,
and super properties (app version, device, pro status, selected sports).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-10 15:12:16 -06:00
Trey t
61c4e39807 feat: update bundle ID config, CloudKit container, and add landing page
- Update CloudKit container ID to iCloud.com.88oakapps.SportsTime across all services
- Update IAP product IDs to match new bundle ID (com.88oakapps.SportsTime)
- Add app landing page with light, welcoming design matching app aesthetic
- Update entitlements and project configuration

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 22:47:55 -06:00
Trey t
4d097883a6 fix(data): add timezone handling for Sports-Reference scrapers and new stadiums
- Add ET timezone (America/New_York) to all Sports-Reference scrapers:
  - NBA: Basketball-Reference times parsed as ET
  - NFL: Pro-Football-Reference times parsed as ET
  - NHL: Hockey-Reference times parsed as ET
  - MLB: Baseball-Reference times parsed as ET
- Document source timezones in scraper docstrings
- Add 11 new stadiums to STADIUM_MAPPINGS:
  - NFL: 5 international venues (Corinthians Arena, Croke Park,
    Olympic Stadium Berlin, Santiago Bernabéu, Tom Benson Hall of Fame)
  - MLS: 4 alternate venues (Miami Freedom Park, Citi Field,
    LA Memorial Coliseum, M&T Bank Stadium)
  - NWSL: 2 alternate venues (Northwestern Medicine Field, ONE Spokane)
- Add 15 stadium aliases for MLS/NWSL team-based lookups
- Fix CanonicalSyncService to sync timezone identifier to SwiftData
- Update debug logging to use stadium timezone for display

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-21 16:04:45 -06:00
Trey t
87079b434d fix(schedule): use start of day for date range queries
- Fix startDate to use Calendar.startOfDay instead of Date() to include
  games earlier in the current day
- Add SyncLogger for file-based sync logging viewable in Settings
- Add "View Sync Logs" button in Settings debug section
- Add diagnostics and NBA game logging to ScheduleViewModel
- Add dropped game logging to DataProvider.filterRichGames
- Use SyncLogger in SportsTimeApp and CloudKitService for sync operations

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-20 22:25:44 -06:00
Trey t
37a1347ce3 perf: lazy hierarchical loading for game picker
Replace upfront loading of all games with lazy Sport → Team → Game
hierarchy. Games are now fetched per-team when expanded and cached
to prevent re-fetching. Also removes pagination workaround and
pre-computes groupings in ScheduleViewModel to avoid per-render work.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-12 20:19:46 -06:00
Trey t
746b56bc77 perf: add pagination to schedule list
Loads 50 games at a time to fix lag with large datasets.

- Add pagination state (displayedGames, currentPage, allFilteredGames)
- Add loadInitialGames() and loadMoreGames() methods
- Update gamesBySport to use displayedGames
- Add infinite scroll trigger via onAppear on last game
- Add ProgressView indicator when more games available
- Reset pagination when search text changes

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-12 19:07:54 -06:00
Trey t
3978429716 feat: complete delta sync implementation - add allGames, update callers
- Add allRichGames method to DataProvider
- Update TripCreationViewModel.loadGamesForBrowsing to use allGames (removes 90-day limit)
- Update MockCloudKitService sync methods to use new delta sync signatures
- Update MockAppDataProvider with renamed methods and new allGames/allRichGames
- Fix all callers: ScheduleViewModel, TripCreationViewModel, SuggestedTripsGenerator, GameMatcher
- Update CLAUDE.md documentation with new method names

This completes the delta sync implementation:
- CloudKit sync now uses modificationDate for proper delta sync
- First sync fetches ALL data, subsequent syncs only fetch modified records
- "By Games" mode now shows all available games (not just 90 days)
- All data types (stadiums, teams, games) use consistent delta sync pattern

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-12 11:04:52 -06:00
Trey t
5ed4e309bd feat(schedule): group games by sport instead of date
Games in schedule view now display in sport sections (MLB, NBA, etc.)
with games sorted by date within each section. Each game row shows its
date since the section header now shows sport instead.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-10 17:36:22 -06:00
Trey t
045fcd9c07 Remove debug prints and fix build warnings
- Remove all print statements from planning engine, data providers, and PDF generation
- Fix deprecated CLGeocoder usage with MKLocalSearch for iOS 26
- Fix Swift 6 actor isolation by converting PDFGenerator/ExportService to @MainActor
- Add @retroactive to CLLocationCoordinate2D protocol conformances
- Fix unused variable warnings in GameDAGRouter and scenario planners
- Remove unreachable catch blocks in SettingsViewModel

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-08 13:25:27 -06:00
Trey t
9088b46563 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>
2026-01-07 00:46:40 -06:00