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

@@ -28,7 +28,7 @@ final class PDFGenerator {
func generatePDF(
for trip: Trip,
games: [UUID: RichGame],
games: [String: RichGame],
assets: PDFAssetPrefetcher.PrefetchedAssets? = nil
) async throws -> Data {
let pdfRenderer = UIGraphicsPDFRenderer(
@@ -244,7 +244,7 @@ final class PDFGenerator {
private func drawItineraryPages(
context: UIGraphicsPDFRendererContext,
trip: Trip,
games: [UUID: RichGame],
games: [String: RichGame],
assets: PDFAssetPrefetcher.PrefetchedAssets?
) {
var pageNumber = 3
@@ -283,7 +283,7 @@ final class PDFGenerator {
drawFooter(context: context, pageNumber: pageNumber)
}
private func estimateDayHeight(day: ItineraryDay, games: [UUID: RichGame]) -> CGFloat {
private func estimateDayHeight(day: ItineraryDay, games: [String: RichGame]) -> CGFloat {
var height: CGFloat = 60 // Day header + city
// Games
@@ -305,7 +305,7 @@ final class PDFGenerator {
private func drawDay(
context: UIGraphicsPDFRendererContext,
day: ItineraryDay,
games: [UUID: RichGame],
games: [String: RichGame],
assets: PDFAssetPrefetcher.PrefetchedAssets?,
y: CGFloat
) -> CGFloat {
@@ -520,7 +520,7 @@ final class PDFGenerator {
private func drawCitySpotlightPages(
context: UIGraphicsPDFRendererContext,
trip: Trip,
games: [UUID: RichGame],
games: [String: RichGame],
assets: PDFAssetPrefetcher.PrefetchedAssets?
) {
guard let cityPOIs = assets?.cityPOIs, !cityPOIs.isEmpty else { return }
@@ -661,7 +661,7 @@ final class PDFGenerator {
private func drawSummaryPage(
context: UIGraphicsPDFRendererContext,
trip: Trip,
games: [UUID: RichGame]
games: [String: RichGame]
) {
var y: CGFloat = margin
@@ -896,7 +896,7 @@ final class ExportService {
/// Export trip to PDF with full prefetched assets
func exportToPDF(
trip: Trip,
games: [UUID: RichGame],
games: [String: RichGame],
progressCallback: ((PDFAssetPrefetcher.PrefetchProgress) async -> Void)? = nil
) async throws -> URL {
// Prefetch all assets
@@ -918,7 +918,7 @@ final class ExportService {
}
/// Quick export without prefetching (basic PDF)
func exportToPDFBasic(trip: Trip, games: [UUID: RichGame]) async throws -> URL {
func exportToPDFBasic(trip: Trip, games: [String: RichGame]) async throws -> URL {
let data = try await pdfGenerator.generatePDF(for: trip, games: games, assets: nil)
let fileName = "\(trip.name.replacingOccurrences(of: " ", with: "_"))_\(Date().timeIntervalSince1970).pdf"