refactor: change domain model IDs from UUID to String canonical IDs

This refactor fixes the achievement system by using stable canonical string
IDs (e.g., "stadium_mlb_fenway_park") instead of random UUIDs. This ensures
stadium mappings for achievements are consistent across app launches and
CloudKit sync operations.

Changes:
- Stadium, Team, Game: id property changed from UUID to String
- Trip, TripStop, TripPreferences: updated to use String IDs for games/stadiums
- CKModels: removed UUID parsing, use canonical IDs directly
- AchievementEngine: now matches against canonical stadium IDs
- All test files updated to use String IDs instead of UUID()

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Trey t
2026-01-12 09:24:33 -06:00
parent 4b2cacaeba
commit 1703ca5b0f
53 changed files with 642 additions and 727 deletions

View File

@@ -275,7 +275,7 @@ final class ScenarioDPlanner: ScenarioPlanner {
// MARK: - Team Filtering
/// Filters games to those involving the followed team (home or away).
private func filterToTeam(_ games: [Game], teamId: UUID) -> [Game] {
private func filterToTeam(_ games: [Game], teamId: String) -> [Game] {
games.filter { game in
game.homeTeamId == teamId || game.awayTeamId == teamId
}
@@ -287,7 +287,7 @@ final class ScenarioDPlanner: ScenarioPlanner {
private func applyRepeatCityFilter(
_ games: [Game],
allowRepeat: Bool,
stadiums: [UUID: Stadium]
stadiums: [String: Stadium]
) -> [Game] {
guard !allowRepeat else {
print("🔍 applyRepeatCityFilter: allowRepeat=true, returning all \(games.count) games")
@@ -317,14 +317,14 @@ final class ScenarioDPlanner: ScenarioPlanner {
/// Same logic as ScenarioAPlanner.
private func buildStops(
from games: [Game],
stadiums: [UUID: Stadium]
stadiums: [String: Stadium]
) -> [ItineraryStop] {
guard !games.isEmpty else { return [] }
let sortedGames = games.sorted { $0.startTime < $1.startTime }
var stops: [ItineraryStop] = []
var currentStadiumId: UUID? = nil
var currentStadiumId: String? = nil
var currentGames: [Game] = []
for game in sortedGames {
@@ -354,8 +354,8 @@ final class ScenarioDPlanner: ScenarioPlanner {
/// Creates an ItineraryStop from a group of games at the same stadium.
private func createStop(
from games: [Game],
stadiumId: UUID,
stadiums: [UUID: Stadium]
stadiumId: String,
stadiums: [String: Stadium]
) -> ItineraryStop? {
guard !games.isEmpty else { return nil }
@@ -393,7 +393,7 @@ final class ScenarioDPlanner: ScenarioPlanner {
var unique: [[Game]] = []
for route in routes {
let key = route.map { $0.id.uuidString }.sorted().joined(separator: "-")
let key = route.map { $0.id }.sorted().joined(separator: "-")
if !seen.contains(key) {
seen.insert(key)
unique.append(route)