// JQCApp.swift // ------------ // App entry point. Phase C adds BGTaskScheduler for background sync. import SwiftUI import SwiftData import BackgroundTasks @main struct JanitorialQCApp: App { @StateObject private var auth = AuthManager.shared @StateObject private var sync = SyncManager.shared init() { registerBackgroundTasks() } var body: some Scene { WindowGroup { ContentView() .environmentObject(auth) .environmentObject(sync) } .modelContainer(for: [ // Phase A LocalFacility.self, LocalArea.self, LocalTemplate.self, // Phase B LocalInspection.self, LocalIssue.self, PendingPhoto.self, SyncQueueEntry.self, ], isUndoEnabled: false) { result in switch result { case .success(let container): Task { @MainActor in SyncManager.shared.modelContext = container.mainContext await AuthManager.shared.restoreSession() SyncManager.shared.startMonitoring() if SyncManager.shared.isOnline { await SyncManager.shared.triggerSync() } } case .failure(let error): fatalError("SwiftData container failed: \(error)") } } } // ── Background Tasks ────────────────────────────────────────────────── /// Register the background sync task with the OS. /// The identifier must match BGTaskSchedulerPermittedIdentifiers in Info.plist. private func registerBackgroundTasks() { BGTaskScheduler.shared.register( forTaskWithIdentifier: "com.jqc.sync", using: nil ) { task in guard let processingTask = task as? BGProcessingTask else { task.setTaskCompleted(success: false) return } handleBackgroundSync(task: processingTask) } } private func handleBackgroundSync(task: BGProcessingTask) { // Schedule the next background run immediately scheduleBackgroundSync() let syncTask = Task { await SyncManager.shared.triggerSync() } // If the OS needs to cancel early, cancel our work task.expirationHandler = { syncTask.cancel() } Task { await syncTask.value task.setTaskCompleted(success: !syncTask.isCancelled) } } } /// Schedule a background processing task. /// Call this from sceneDidEnterBackground or after each foreground sync. func scheduleBackgroundSync() { let request = BGProcessingTaskRequest(identifier: "com.jqc.sync") request.requiresNetworkConnectivity = true request.requiresExternalPower = false try? BGTaskScheduler.shared.submit(request) }