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

@@ -272,7 +272,7 @@ final class ScenarioCPlanner: ScenarioPlanner {
/// Finds all stadiums in a given city (case-insensitive match).
private func findStadiumsInCity(
cityName: String,
stadiums: [UUID: Stadium]
stadiums: [String: Stadium]
) -> [Stadium] {
let normalizedCity = cityName.lowercased().trimmingCharacters(in: .whitespaces)
return stadiums.values.filter { stadium in
@@ -296,14 +296,14 @@ final class ScenarioCPlanner: ScenarioPlanner {
private func findDirectionalStadiums(
from start: CLLocationCoordinate2D,
to end: CLLocationCoordinate2D,
stadiums: [UUID: Stadium]
) -> Set<UUID> {
stadiums: [String: Stadium]
) -> Set<String> {
let directDistance = distanceBetween(start, end)
// Allow detours up to 50% longer than direct distance
let maxDetourDistance = directDistance * 1.5
var directionalIds: Set<UUID> = []
var directionalIds: Set<String> = []
for (id, stadium) in stadiums {
let stadiumCoord = stadium.coordinate
@@ -349,8 +349,8 @@ final class ScenarioCPlanner: ScenarioPlanner {
/// Create a date range from start_game.date to end_game.date
///
private func generateDateRanges(
startStadiumIds: Set<UUID>,
endStadiumIds: Set<UUID>,
startStadiumIds: Set<String>,
endStadiumIds: Set<String>,
allGames: [Game],
request: PlanningRequest
) -> [DateInterval] {
@@ -417,7 +417,7 @@ final class ScenarioCPlanner: ScenarioPlanner {
/// Creates separate stops when visiting the same city with other cities in between.
private func buildStops(
from games: [Game],
stadiums: [UUID: Stadium]
stadiums: [String: Stadium]
) -> [ItineraryStop] {
guard !games.isEmpty else { return [] }
@@ -426,7 +426,7 @@ final class ScenarioCPlanner: ScenarioPlanner {
// Group consecutive games at the same stadium
var stops: [ItineraryStop] = []
var currentStadiumId: UUID? = nil
var currentStadiumId: String? = nil
var currentGames: [Game] = []
for game in sortedGames {
@@ -458,8 +458,8 @@ final class ScenarioCPlanner: 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 }
@@ -496,7 +496,7 @@ final class ScenarioCPlanner: ScenarioPlanner {
start: LocationInput,
end: LocationInput,
games: [Game],
stadiums: [UUID: Stadium]
stadiums: [String: Stadium]
) -> [ItineraryStop] {
var stops: [ItineraryStop] = []