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

@@ -591,7 +591,7 @@ enum AchievementRegistry {
sport: .mlb,
iconName: "building.columns.fill",
iconColor: .green,
requirement: .specificStadium("stadium_mlb_bos"),
requirement: .specificStadium("stadium_mlb_fenway_park"),
sortOrder: 600
),
AchievementDefinition(
@@ -602,7 +602,7 @@ enum AchievementRegistry {
sport: .mlb,
iconName: "leaf.fill",
iconColor: .green,
requirement: .specificStadium("stadium_mlb_chc"),
requirement: .specificStadium("stadium_mlb_wrigley_field"),
sortOrder: 601
),
AchievementDefinition(
@@ -613,7 +613,7 @@ enum AchievementRegistry {
sport: .nba,
iconName: "sparkles",
iconColor: .orange,
requirement: .specificStadium("stadium_nba_nyk"),
requirement: .specificStadium("stadium_nba_madison_square_garden"),
sortOrder: 602
)
]

View File

@@ -6,10 +6,10 @@
import Foundation
struct Game: Identifiable, Codable, Hashable {
let id: UUID
let homeTeamId: UUID
let awayTeamId: UUID
let stadiumId: UUID
let id: String // Canonical ID: "game_mlb_2026_bos_nyy_0401"
let homeTeamId: String // FK: "team_mlb_bos"
let awayTeamId: String // FK: "team_mlb_nyy"
let stadiumId: String // FK: "stadium_mlb_fenway_park"
let dateTime: Date
let sport: Sport
let season: String
@@ -17,10 +17,10 @@ struct Game: Identifiable, Codable, Hashable {
let broadcastInfo: String?
init(
id: UUID ,
homeTeamId: UUID,
awayTeamId: UUID,
stadiumId: UUID,
id: String,
homeTeamId: String,
awayTeamId: String,
stadiumId: String,
dateTime: Date,
sport: Sport,
season: String,
@@ -78,7 +78,7 @@ struct RichGame: Identifiable, Hashable, Codable {
let awayTeam: Team
let stadium: Stadium
var id: UUID { game.id }
var id: String { game.id }
var matchupDescription: String {
"\(awayTeam.abbreviation) @ \(homeTeam.abbreviation)"

View File

@@ -7,7 +7,7 @@ import Foundation
import CoreLocation
struct Stadium: Identifiable, Codable, Hashable {
let id: UUID
let id: String // Canonical ID: "stadium_mlb_fenway_park"
let name: String
let city: String
let state: String
@@ -19,7 +19,7 @@ struct Stadium: Identifiable, Codable, Hashable {
let imageURL: URL?
init(
id: UUID,
id: String,
name: String,
city: String,
state: String,

View File

@@ -6,23 +6,23 @@
import Foundation
struct Team: Identifiable, Codable, Hashable {
let id: UUID
let id: String // Canonical ID: "team_mlb_bos"
let name: String
let abbreviation: String
let sport: Sport
let city: String
let stadiumId: UUID
let stadiumId: String // FK: "stadium_mlb_fenway_park"
let logoURL: URL?
let primaryColor: String?
let secondaryColor: String?
init(
id: UUID,
id: String,
name: String,
abbreviation: String,
sport: Sport,
city: String,
stadiumId: UUID,
stadiumId: String,
logoURL: URL? = nil,
primaryColor: String? = nil,
secondaryColor: String? = nil

View File

@@ -174,7 +174,7 @@ struct ItineraryDay: Identifiable, Hashable {
var isRestDay: Bool { stops.first?.isRestDay ?? false }
var hasTravelSegment: Bool { !travelSegments.isEmpty }
var gameIds: [UUID] { stops.flatMap { $0.games } }
var gameIds: [String] { stops.flatMap { $0.games } }
var hasGames: Bool { !gameIds.isEmpty }
var primaryCity: String? { stops.first?.city }
var totalDrivingHours: Double { travelSegments.reduce(0) { $0 + $1.durationHours } }

View File

@@ -215,7 +215,7 @@ struct TripPreferences: Codable, Hashable {
var startLocation: LocationInput?
var endLocation: LocationInput?
var sports: Set<Sport>
var mustSeeGameIds: Set<UUID>
var mustSeeGameIds: Set<String>
var travelMode: TravelMode
var startDate: Date
var endDate: Date
@@ -235,7 +235,7 @@ struct TripPreferences: Codable, Hashable {
var selectedRegions: Set<Region>
/// Team to follow (for Follow Team mode)
var followTeamId: UUID?
var followTeamId: String?
/// Whether to start/end from a home location (vs fly-in/fly-out)
var useHomeLocation: Bool
@@ -248,7 +248,7 @@ struct TripPreferences: Codable, Hashable {
startLocation: LocationInput? = nil,
endLocation: LocationInput? = nil,
sports: Set<Sport> = [],
mustSeeGameIds: Set<UUID> = [],
mustSeeGameIds: Set<String> = [],
travelMode: TravelMode = .drive,
startDate: Date = Date(),
endDate: Date = Date().addingTimeInterval(86400 * 7),
@@ -264,7 +264,7 @@ struct TripPreferences: Codable, Hashable {
maxDrivingHoursPerDriver: Double? = nil,
allowRepeatCities: Bool = true,
selectedRegions: Set<Region> = [.east, .central, .west],
followTeamId: UUID? = nil,
followTeamId: String? = nil,
useHomeLocation: Bool = true,
gameFirstTripDuration: Int = 7
) {

View File

@@ -14,8 +14,8 @@ struct TripStop: Identifiable, Codable, Hashable {
let coordinate: CLLocationCoordinate2D?
let arrivalDate: Date
let departureDate: Date
let games: [UUID]
let stadium: UUID?
let games: [String]
let stadium: String?
let lodging: LodgingSuggestion?
let activities: [ActivitySuggestion]
let isRestDay: Bool
@@ -29,8 +29,8 @@ struct TripStop: Identifiable, Codable, Hashable {
coordinate: CLLocationCoordinate2D? = nil,
arrivalDate: Date,
departureDate: Date,
games: [UUID] = [],
stadium: UUID? = nil,
games: [String] = [],
stadium: String? = nil,
lodging: LodgingSuggestion? = nil,
activities: [ActivitySuggestion] = [],
isRestDay: Bool = false,