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

@@ -43,7 +43,7 @@ struct CKTeam {
init(team: Team, stadiumRecordID: CKRecord.ID) {
let record = CKRecord(recordType: CKRecordType.team)
record[CKTeam.idKey] = team.id.uuidString
record[CKTeam.idKey] = team.id
record[CKTeam.nameKey] = team.name
record[CKTeam.abbreviationKey] = team.abbreviation
record[CKTeam.sportKey] = team.sport.rawValue
@@ -67,8 +67,8 @@ struct CKTeam {
var team: Team? {
// Use teamId field, or fall back to record name
let idString = (record[CKTeam.idKey] as? String) ?? record.recordID.recordName
guard let id = UUID(uuidString: idString),
let id = (record[CKTeam.idKey] as? String) ?? record.recordID.recordName
guard !id.isEmpty,
let abbreviation = record[CKTeam.abbreviationKey] as? String,
let sportRaw = record[CKTeam.sportKey] as? String,
let sport = Sport(rawValue: sportRaw),
@@ -78,14 +78,13 @@ struct CKTeam {
// Name defaults to abbreviation if not provided
let name = record[CKTeam.nameKey] as? String ?? abbreviation
// Stadium reference is optional - use placeholder UUID if not present
let stadiumId: UUID
if let stadiumRef = record[CKTeam.stadiumRefKey] as? CKRecord.Reference,
let refId = UUID(uuidString: stadiumRef.recordID.recordName) {
stadiumId = refId
// Stadium reference is optional - use placeholder string if not present
let stadiumId: String
if let stadiumRef = record[CKTeam.stadiumRefKey] as? CKRecord.Reference {
stadiumId = stadiumRef.recordID.recordName
} else {
// Generate deterministic placeholder from team ID
stadiumId = UUID()
// Generate placeholder from team ID
stadiumId = "stadium_placeholder_\(id)"
}
let logoURL = (record[CKTeam.logoURLKey] as? String).flatMap { URL(string: $0) }
@@ -126,7 +125,7 @@ struct CKStadium {
init(stadium: Stadium) {
let record = CKRecord(recordType: CKRecordType.stadium)
record[CKStadium.idKey] = stadium.id.uuidString
record[CKStadium.idKey] = stadium.id
record[CKStadium.nameKey] = stadium.name
record[CKStadium.cityKey] = stadium.city
record[CKStadium.stateKey] = stadium.state
@@ -145,8 +144,8 @@ struct CKStadium {
var stadium: Stadium? {
// Use stadiumId field, or fall back to record name
let idString = (record[CKStadium.idKey] as? String) ?? record.recordID.recordName
guard let id = UUID(uuidString: idString),
let id = (record[CKStadium.idKey] as? String) ?? record.recordID.recordName
guard !id.isEmpty,
let name = record[CKStadium.nameKey] as? String,
let city = record[CKStadium.cityKey] as? String
else { return nil }
@@ -199,7 +198,7 @@ struct CKGame {
init(game: Game, homeTeamRecordID: CKRecord.ID, awayTeamRecordID: CKRecord.ID, stadiumRecordID: CKRecord.ID) {
let record = CKRecord(recordType: CKRecordType.game)
record[CKGame.idKey] = game.id.uuidString
record[CKGame.idKey] = game.id
record[CKGame.homeTeamRefKey] = CKRecord.Reference(recordID: homeTeamRecordID, action: .none)
record[CKGame.awayTeamRefKey] = CKRecord.Reference(recordID: awayTeamRecordID, action: .none)
record[CKGame.stadiumRefKey] = CKRecord.Reference(recordID: stadiumRecordID, action: .none)
@@ -231,9 +230,9 @@ struct CKGame {
record[CKGame.stadiumCanonicalIdKey] as? String
}
func game(homeTeamId: UUID, awayTeamId: UUID, stadiumId: UUID) -> Game? {
guard let idString = record[CKGame.idKey] as? String,
let id = UUID(uuidString: idString),
func game(homeTeamId: String, awayTeamId: String, stadiumId: String) -> Game? {
let id = (record[CKGame.idKey] as? String) ?? record.recordID.recordName
guard !id.isEmpty,
let dateTime = record[CKGame.dateTimeKey] as? Date,
let sportRaw = record[CKGame.sportKey] as? String,
let sport = Sport(rawValue: sportRaw),