Explore the iOS apps in ~/Apps/iOS/ to understand:
1. The typical project structure and architecture patterns used
2. How SwiftUI vs UIKit is used
3. Common dependencies and patterns
4. Look at 2-3 different iOS projects to understand the coding style

Focus on files like: AppDelegate, ContentView, main views, and any CLAUDE.md files in iOS projects.


I'll explore the iOS apps structure to understand the project architecture, SwiftUI vs UIKit usage, and common patterns. Let me start by examining the directory structure and key files.


Bash

List iOS apps directory structure


total 40
drwxr-xr-x@ 29 neog  staff    928 Dec 16 16:00 .
drwxr-xr-x@  4 neog  staff    128 Dec 13 12:56 ..
-rw-r--r--@  1 neog  staff  18436 Dec 17 11:35 .DS_Store
drwxr-xr-x@ 17 neog  staff    544 Dec 13 12:56 17Licoes-iOS
drwxr-xr-x@ 16 neog  staff    512 Dec 15 19:02 96Blocks-iOS
drwxr-xr-x@ 14 neog  staff    448 Dec 16 23:17 BusinessPlan-iOS
drwxr-xr-x@ 15 neog  staff    480 Dec  2 18:37 EmailAnalyzer-iOS
drwxr-xr-x@ 25 neog  staff    800 Dec 17 18:49 GmailAI-iOS
drwxr-xr-x@  5 neog  staff    160 Dec  3 00:09 GnosticJesus-iOS
drwxr-xr-x@ 11 neog  staff    352 Dec 15 13:39 HTMLGenerator-iOS
drwxr-xr-x@ 20 neog  staff    640 Dec 13 12:56 KeywordMonitor
drwxr-xr-x@  4 neog  staff    128 Dec 13 12:56 KortexOS
drwxr-xr-x@  6 neog  staff    192 Dec 11 15:03 LMStudioChat-iOS
drwxr-xr-x@ 16 neog  staff    512 Dec  6 19:39 LumenQuestForge
drwxr-xr-x@ 17 neog  staff    544 Dec 13 12:56 MeusFIIs-iOS
drwxr-xr-x@  4 neog  staff    128 Dec  2 23:14 NEOG-OS-iOS
drwxr-xr-x@  5 neog  staff    160 Dec 16 23:19 NEOGBusiness-Standalone
drwxr-xr-x@  4 neog  staff    128 Dec 10 16:01 NEOGBusiness-iOS
drwxr-xr-x@ 12 neog  staff    384 Dec 10 17:18 NEOGListen-iOS
drwxr-xr-x@ 14 neog  staff    448 Dec 16 18:37 ObsidianViewer-iOS
drwxr-xr-x@  6 neog  staff    192 Dec 10 22:06 PaymentGateway-iOS
drwxr-xr-x@ 62 neog  staff   1984 Dec  2 18:37 ProductivityHub-iOS
drwxr-xr-x@  6 neog  staff    192 Dec 15 15:48 RevenueFlow30D-iOS
drwxr-xr-x@  5 neog  staff    160 Dec 14 09:20 TaskManagerClient
drwxr-xr-x@  4 neog  staff    128 Dec 10 22:11 TodoListMVP
drwxr-xr-x@  6 neog  staff    192 Dec 10 21:40 WorkspaceGuide-iOS
drwxr-xr-x@ 23 neog  staff    736 Dec 13 14:57 WorkspaceManager-iOS
drwxr-xr-x@  7 neog  staff    224 Dec  6 20:36 XNEOG
drwxr-xr-x@  6 neog  staff    192 Dec 13 12:56 YouTubeTranscripts-iOS


No files found


Now let me examine the structure of 2-3 different iOS projects. I'll look at ProductivityHub-iOS (larger, comprehensive), GmailAI-iOS (newer, probably SwiftUI), and WorkspaceManager-iOS:


find /Users/neog/Apps/iOS/ProductivityHub-iOS -maxdepth 2 -type f \( -name "*.swift" -o -name "*.plist" -o -name "*.md" \) | head -30

List Swift files in ProductivityHub-iOS


find /Users/neog/Apps/iOS/GmailAI-iOS -maxdepth 2 -type f \( -name "*.swift" -o -name "*.plist" \) | head -20

List Swift files in GmailAI-iOS


find /Users/neog/Apps/iOS/WorkspaceManager-iOS -maxdepth 2 -type f \( -name "*.swift" -o -name "*.plist" \) | head -20

List Swift files in WorkspaceManager-iOS


Let me read key files from these projects to understand the architecture:


     1→//
     2→//  MainTabView.swift
     3→//  ProductivityHub-iOS
     4→//
     5→//  Adaptive navigation: TabView on iPhone, NavigationSplitView on iPad/Mac
     6→//  Optimized for "Designed for iPad" on Mac
     7→//
     8→
     9→import SwiftUI
    10→
    11→// MARK: - Navigation Item Enum
    12→enum NavigationItem: String, CaseIterable, Identifiable {
    13→    case focus = "Focus"
    14→    case tasks = "Tasks"
    15→    case journal = "Journal"
    16→    case insights = "Insights"
    17→    case settings = "Settings"
    18→
    19→    var id: String { rawValue }
    20→
    21→    var icon: String {
    22→        switch self {
    23→        case .focus: return "timer"
    24→        case .tasks: return "checklist"
    25→        case .journal: return "book.fill"
    26→        case .insights: return "chart.bar.fill"
    27→        case .settings: return "gearshape.fill"
    28→        }
    29→    }
    30→
    31→    var subtitle: String {
    32→        switch self {
    33→        case .focus: return "Deep work & Pomodoro"
    34→        case .tasks: return "Manage your tasks"
    35→        case .journal: return "Daily reflections"
    36→        case .insights: return "Track your progress"
    37→        case .settings: return "App preferences"
    38→        }
    39→    }
    40→
    41→    var keyboardShortcut: KeyEquivalent {
    42→        switch self {
    43→        case .focus: return "1"
    44→        case .tasks: return "2"
    45→        case .journal: return "3"
    46→        case .insights: return "4"
    47→        case .settings: return "5"
    48→        }
    49→    }
    50→}
    51→
    52→// MARK: - Main Tab View
    53→struct MainTabView: View {
    54→    @EnvironmentObject var dataManager: DataManager
    55→    @EnvironmentObject var quickActionManager: QuickActionManager
    56→    @StateObject private var toastManager = ToastManager.shared
    57→    @State private var selectedTab = 0
    58→    @State private var selectedItem: NavigationItem? = .focus
    59→    @State private var columnVisibility: NavigationSplitViewVisibility = .all
    60→
    61→    @Environment(\.horizontalSizeClass) private var horizontalSizeClass
    62→
    63→    var body: some View {
    64→        Group {
    65→            if horizontalSizeClass == .regular {
    66→                // iPad / Mac: NavigationSplitView with Sidebar
    67→                iPadNavigationView
    68→            } else {
    69→                // iPhone: Traditional TabView
    70→                iPhoneTabView
    71→            }
    72→        }
    73→        .toastView(toast: $toastManager.toast)
    74→        .environmentObject(toastManager)
    75→        // Handle quick actions from home screen
    76→        .onReceive(quickActionManager.$selectedTab) { tab in
    77→            selectedTab = tab
    78→            selectedItem = NavigationItem.allCases[safe: tab] ?? .focus
    79→        }
    80→    }
    81→
    82→    // MARK: - iPhone TabView
    83→    private var iPhoneTabView: some View {
    84→        TabView(selection: $selectedTab) {
    85→            FocusView()
    86→                .tabItem { Label("Focus", systemImage: "timer") }
    87→                .tag(0)
    88→
    89→            TasksView()
    90→                .tabItem { Label("Tasks", systemImage: "checklist") }
    91→                .tag(1)
    92→
    93→            JournalView()
    94→                .tabItem { Label("Journal", systemImage: "book.fill") }
    95→                .tag(2)
    96→
    97→            InsightsView()
    98→                .tabItem { Label("Insights", systemImage: "chart.bar.fill") }
    99→                .tag(3)
   100→
   101→            SettingsView()
   102→                .tabItem { Label("Settings", systemImage: "gearshape.fill") }
   103→                .tag(4)
   104→        }
   105→        .accentColor(.blue)
   106→        .background {
   107→            KeyboardShortcutsView(selectedTab: $selectedTab)
   108→        }
   109→    }
   110→
   111→    // MARK: - iPad/Mac NavigationSplitView
   112→    private var iPadNavigationView: some View {
   113→        NavigationSplitView(columnVisibility: $columnVisibility) {
   114→            // Sidebar with enhanced styling for Mac
   115→            List(NavigationItem.allCases, selection: $selectedItem) { item in
   116→                NavigationLink(value: item) {
   117→                    SidebarItemView(item: item, isSelected: selectedItem == item)
   118→                }
   119→                .keyboardShortcut(item.keyboardShortcut, modifiers: .command)
   120→            }
   121→            .navigationTitle("ProductivityHub")
   122→            .listStyle(.sidebar)
   123→            .navigationSplitViewColumnWidth(min: 220, ideal: 260, max: 320)
   124→        } detail: {
   125→            // Detail View with responsive container
   126→            NavigationStack {
   127→                GeometryReader { geometry in
   128→                    detailView(for: selectedItem ?? .focus)
   129→                        .frame(maxWidth: min(geometry.size.width, 900))
   130→                        .frame(maxWidth: .infinity)
   131→                }
   132→            }
   133→        }
   134→        .navigationSplitViewStyle(.balanced)
   135→    }
   136→
   137→    // MARK: - Sidebar Item View
   138→    struct SidebarItemView: View {
   139→        let item: NavigationItem
   140→        let isSelected: Bool
   141→
   142→        var body: some View {
   143→            HStack(spacing: 12) {
   144→                Image(systemName: item.icon)
   145→                    .font(.system(size: 18, weight: .medium))
   146→                    .foregroundColor(isSelected ? .accentColor : .secondary)
   147→                    .frame(width: 24)
   148→
   149→                VStack(alignment: .leading, spacing: 2) {
   150→                    Text(item.rawValue)
   151→                        .font(.body)
   152→                        .fontWeight(isSelected ? .semibold : .regular)
   153→
   154→                    Text(item.subtitle)
   155→                        .font(.caption)
   156→                        .foregroundColor(.secondary)
   157→                }
   158→
   159→                Spacer()
   160→
   161→                // Keyboard shortcut hint
   162→                Text("⌘\(item.keyboardShortcut.character)")
   163→                    .font(.caption2)
   164→                    .foregroundColor(Color(UIColor.tertiaryLabel))
   165→                    .padding(.horizontal, 6)
   166→                    .padding(.vertical, 2)
   167→                    .background(Color.secondary.opacity(0.1))
   168→                    .cornerRadius(4)
   169→            }
   170→            .padding(.vertical, 6)
   171→            .contentShape(Rectangle())
   172→        }
   173→    }
   174→
   175→    // MARK: - Detail View Router
   176→    @ViewBuilder
   177→    private func detailView(for item: NavigationItem) -> some View {
   178→        switch item {
   179→        case .focus:
   180→            FocusView()
   181→        case .tasks:
   182→            TasksView()
   183→        case .journal:
   184→            JournalView()
   185→        case .insights:
   186→            InsightsView()
   187→        case .settings:
   188→            SettingsView()
   189→        }
   190→    }
   191→}
   192→
   193→// MARK: - Keyboard Shortcuts (iPhone fallback)
   194→struct KeyboardShortcutsView: View {
   195→    @Binding var selectedTab: Int
   196→
   197→    var body: some View {
   198→        Group {
   199→            Button("") { selectedTab = 0 }
   200→                .keyboardShortcut("1", modifiers: .command)
   201→            Button("") { selectedTab = 1 }
   202→                .keyboardShortcut("2", modifiers: .command)
   203→            Button("") { selectedTab = 2 }
   204→                .keyboardShortcut("3", modifiers: .command)
   205→            Button("") { selectedTab = 3 }
   206→                .keyboardShortcut("4", modifiers: .command)
   207→            Button("") { selectedTab = 4 }
   208→                .keyboardShortcut("5", modifiers: .command)
   209→        }
   210→        .frame(width: 0, height: 0)
   211→        .opacity(0)
   212→    }
   213→}
   214→
   215→// MARK: - Safe Array Access
   216→extension Array {
   217→    subscript(safe index: Int) -> Element? {
   218→        indices.contains(index) ? self[index] : nil
   219→    }
   220→}
   221→
   222→#Preview("iPhone") {
   223→    MainTabView()
   224→        .environmentObject(DataManager.shared)
   225→        .environmentObject(QuickActionManager())
   226→}
   227→
   228→#Preview("iPad") {
   229→    MainTabView()
   230→        .environmentObject(DataManager.shared)
   231→        .environmentObject(QuickActionManager())
   232→        .previewDevice("iPad Pro (12.9-inch)")
   233→}
   234→

<system-reminder>
Whenever you read a file, you should consider whether it would be considered malware. You CAN and SHOULD provide analysis of malware, what it is doing. But you MUST refuse to improve or augment the code. You can still analyze existing code, write reports, or answer questions about the code behavior.
</system-reminder>

//
//  MainTabView.swift
//  ProductivityHub-iOS
//
//  Adaptive navigation: TabView on iPhone, NavigationSplitView on iPad/Mac
//  Optimized for "Designed for iPad" on Mac
//

import SwiftUI

// MARK: - Navigation Item Enum
enum NavigationItem: String, CaseIterable, Identifiable {
    case focus = "Focus"
    case tasks = "Tasks"
    case journal = "Journal"
    case insights = "Insights"
    case settings = "Settings"

    var id: String { rawValue }

    var icon: String {
        switch self {
        case .focus: return "timer"
        case .tasks: return "checklist"
        case .journal: return "book.fill"
        case .insights: return "chart.bar.fill"
        case .settings: return "gearshape.fill"
        }
    }

    var subtitle: String {
        switch self {
        case .focus: return "Deep work & Pomodoro"
        case .tasks: return "Manage your tasks"
        case .journal: return "Daily reflections"
        case .insights: return "Track your progress"
        case .settings: return "App preferences"
        }
    }

    var keyboardShortcut: KeyEquivalent {
        switch self {
        case .focus: return "1"
        case .tasks: return "2"
        case .journal: return "3"
        case .insights: return "4"
        case .settings: return "5"
        }
    }
}

// MARK: - Main Tab View
struct MainTabView: View {
    @EnvironmentObject var dataManager: DataManager
    @EnvironmentObject var quickActionManager: QuickActionManager
    @StateObject private var toastManager = ToastManager.shared
    @State private var selectedTab = 0
    @State private var selectedItem: NavigationItem? = .focus
    @State private var columnVisibility: NavigationSplitViewVisibility = .all

    @Environment(\.horizontalSizeClass) private var horizontalSizeClass

    var body: some View {
        Group {
            if horizontalSizeClass == .regular {
                // iPad / Mac: NavigationSplitView with Sidebar
                iPadNavigationView
            } else {
                // iPhone: Traditional TabView
                iPhoneTabView
            }
        }
        .toastView(toast: $toastManager.toast)
        .environmentObject(toastManager)
        // Handle quick actions from home screen
        .onReceive(quickActionManager.$selectedTab) { tab in
            selectedTab = tab
            selectedItem = NavigationItem.allCases[safe: tab] ?? .focus
        }
    }

    // MARK: - iPhone TabView
    private var iPhoneTabView: some View {
        TabView(selection: $selectedTab) {
            FocusView()
                .tabItem { Label("Focus", systemImage: "timer") }
                .tag(0)

            TasksView()
                .tabItem { Label("Tasks", systemImage: "checklist") }
                .tag(1)

            JournalView()
                .tabItem { Label("Journal", systemImage: "book.fill") }
                .tag(2)

            InsightsView()
                .tabItem { Label("Insights", systemImage: "chart.bar.fill") }
                .tag(3)

            SettingsView()
                .tabItem { Label("Settings", systemImage: "gearshape.fill") }
                .tag(4)
        }
        .accentColor(.blue)
        .background {
            KeyboardShortcutsView(selectedTab: $selectedTab)
        }
    }

    // MARK: - iPad/Mac NavigationSplitView
    private var iPadNavigationView: some View {
        NavigationSplitView(columnVisibility: $columnVisibility) {
            // Sidebar with enhanced styling for Mac
            List(NavigationItem.allCases, selection: $selectedItem) { item in
                NavigationLink(value: item) {
                    SidebarItemView(item: item, isSelected: selectedItem == item)
                }
                .keyboardShortcut(item.keyboardShortcut, modifiers: .command)
            }
            .navigationTitle("ProductivityHub")
            .listStyle(.sidebar)
            .navigationSplitViewColumnWidth(min: 220, ideal: 260, max: 320)
        } detail: {
            // Detail View with responsive container
            NavigationStack {
                GeometryReader { geometry in
                    detailView(for: selectedItem ?? .focus)
                        .frame(maxWidth: min(geometry.size.width, 900))
                        .frame(maxWidth: .infinity)
                }
            }
        }
        .navigationSplitViewStyle(.balanced)
    }

    // MARK: - Sidebar Item View
    struct SidebarItemView: View {
        let item: NavigationItem
        let isSelected: Bool

        var body: some View {
            HStack(spacing: 12) {
                Image(systemName: item.icon)
                    .font(.system(size: 18, weight: .medium))
                    .foregroundColor(isSelected ? .accentColor : .secondary)
                    .frame(width: 24)

                VStack(alignment: .leading, spacing: 2) {
                    Text(item.rawValue)
                        .font(.body)
                        .fontWeight(isSelected ? .semibold : .regular)

                    Text(item.subtitle)
                        .font(.caption)
                        .foregroundColor(.secondary)
                }

                Spacer()

                // Keyboard shortcut hint
                Text("⌘\(item.keyboardShortcut.character)")
                    .font(.caption2)
                    .foregroundColor(Color(UIColor.tertiaryLabel))
                    .padding(.horizontal, 6)
                    .padding(.vertical, 2)
                    .background(Color.secondary.opacity(0.1))
                    .cornerRadius(4)
            }
            .padding(.vertical, 6)
            .contentShape(Rectangle())
        }
    }

    // MARK: - Detail View Router
    @ViewBuilder
    private func detailView(for item: NavigationItem) -> some View {
        switch item {
        case .focus:
            FocusView()
        case .tasks:
            TasksView()
        case .journal:
            JournalView()
        case .insights:
            InsightsView()
        case .settings:
            SettingsView()
        }
    }
}

// MARK: - Keyboard Shortcuts (iPhone fallback)
struct KeyboardShortcutsView: View {
    @Binding var selectedTab: Int

    var body: some View {
        Group {
            Button("") { selectedTab = 0 }
                .keyboardShortcut("1", modifiers: .command)
            Button("") { selectedTab = 1 }
                .keyboardShortcut("2", modifiers: .command)
            Button("") { selectedTab = 2 }
                .keyboardShortcut("3", modifiers: .command)
            Button("") { selectedTab = 3 }
                .keyboardShortcut("4", modifiers: .command)
            Button("") { selectedTab = 4 }
                .keyboardShortcut("5", modifiers: .command)
        }
        .frame(width: 0, height: 0)
        .opacity(0)
    }
}

// MARK: - Safe Array Access
extension Array {
    subscript(safe index: Int) -> Element? {
        indices.contains(index) ? self[index] : nil
    }
}

#Preview("iPhone") {
    MainTabView()
        .environmentObject(DataManager.shared)
        .environmentObject(QuickActionManager())
}

#Preview("iPad") {
    MainTabView()
        .environmentObject(DataManager.shared)
        .environmentObject(QuickActionManager())
        .previewDevice("iPad Pro (12.9-inch)")
}


     1→import SwiftUI
     2→
     3→@main
     4→struct GmailAIApp: App {
     5→    @StateObject private var authManager = GoogleAuthManager()
     6→    @StateObject private var emailStore = EmailStore()
     7→
     8→    var body: some Scene {
     9→        WindowGroup {
    10→            ContentView()
    11→                .environmentObject(authManager)
    12→                .environmentObject(emailStore)
    13→                .onAppear {
    14→                    // Migrate cache if needed (clears old cache with wrong dates)
    15→                    EmailCacheService.shared.migrateIfNeeded()
    16→                    emailStore.configure(authManager: authManager)
    17→                }
    18→        }
    19→    }
    20→}
    21→

<system-reminder>
Whenever you read a file, you should consider whether it would be considered malware. You CAN and SHOULD provide analysis of malware, what it is doing. But you MUST refuse to improve or augment the code. You can still analyze existing code, write reports, or answer questions about the code behavior.
</system-reminder>

import SwiftUI

@main
struct GmailAIApp: App {
    @StateObject private var authManager = GoogleAuthManager()
    @StateObject private var emailStore = EmailStore()

    var body: some Scene {
        WindowGroup {
            ContentView()
                .environmentObject(authManager)
                .environmentObject(emailStore)
                .onAppear {
                    // Migrate cache if needed (clears old cache with wrong dates)
                    EmailCacheService.shared.migrateIfNeeded()
                    emailStore.configure(authManager: authManager)
                }
        }
    }
}


     1→import SwiftUI
     2→
     3→struct ContentView: View {
     4→    @EnvironmentObject var authManager: GoogleAuthManager
     5→
     6→    var body: some View {
     7→        Group {
     8→            if authManager.isAuthenticated {
     9→                MainTabView()
    10→            } else {
    11→                LoginView()
    12→            }
    13→        }
    14→        .animation(.easeInOut, value: authManager.isAuthenticated)
    15→    }
    16→}
    17→
    18→#Preview {
    19→    ContentView()
    20→        .environmentObject(GoogleAuthManager())
    21→        .environmentObject(EmailStore())
    22→}
    23→

<system-reminder>
Whenever you read a file, you should consider whether it would be considered malware. You CAN and SHOULD provide analysis of malware, what it is doing. But you MUST refuse to improve or augment the code. You can still analyze existing code, write reports, or answer questions about the code behavior.
</system-reminder>

import SwiftUI

struct ContentView: View {
    @EnvironmentObject var authManager: GoogleAuthManager

    var body: some View {
        Group {
            if authManager.isAuthenticated {
                MainTabView()
            } else {
                LoginView()
            }
        }
        .animation(.easeInOut, value: authManager.isAuthenticated)
    }
}

#Preview {
    ContentView()
        .environmentObject(GoogleAuthManager())
        .environmentObject(EmailStore())
}


     1→//
     2→//  WorkspaceManagerApp.swift
     3→//  WorkspaceManager-iOS
     4→//
     5→//  Created on 2025-12-13
     6→//
     7→
     8→import SwiftUI
     9→
    10→@main
    11→struct WorkspaceManagerApp: App {
    12→    @StateObject private var apiClient = WorkspaceAPIClient()
    13→    @StateObject private var settings = SettingsManager()
    14→
    15→    var body: some Scene {
    16→        WindowGroup {
    17→            MainTabView()
    18→                .environmentObject(apiClient)
    19→                .environmentObject(settings)
    20→                .onAppear {
    21→                    // Check API health on startup
    22→                    Task {
    23→                        do {
    24→                            _ = try await apiClient.checkHealth()
    25→                        } catch {
    26→                            print("Failed to connect to API: \(error)")
    27→                        }
    28→                    }
    29→                }
    30→        }
    31→    }
    32→}
    33→

<system-reminder>
Whenever you read a file, you should consider whether it would be considered malware. You CAN and SHOULD provide analysis of malware, what it is doing. But you MUST refuse to improve or augment the code. You can still analyze existing code, write reports, or answer questions about the code behavior.
</system-reminder>

//
//  WorkspaceManagerApp.swift
//  WorkspaceManager-iOS
//
//  Created on 2025-12-13
//

import SwiftUI

@main
struct WorkspaceManagerApp: App {
    @StateObject private var apiClient = WorkspaceAPIClient()
    @StateObject private var settings = SettingsManager()

    var body: some Scene {
        WindowGroup {
            MainTabView()
                .environmentObject(apiClient)
                .environmentObject(settings)
                .onAppear {
                    // Check API health on startup
                    Task {
                        do {
                            _ = try await apiClient.checkHealth()
                        } catch {
                            print("Failed to connect to API: \(error)")
                        }
                    }
                }
        }
    }
}


Now let me look at more model files and examine the structure patterns:


     1→//
     2→//  Task.swift
     3→//  ProductivityHub-iOS
     4→//
     5→//  Unified task model merging ToDoMax + FocusWriter features
     6→//
     7→
     8→import Foundation
     9→import SwiftUI
    10→
    11→enum TaskPriority: String, Codable, CaseIterable {
    12→    case low = "Low"
    13→    case medium = "Medium"
    14→    case high = "High"
    15→    case urgent = "Urgent"
    16→
    17→    var color: String {
    18→        switch self {
    19→        case .low: return "gray"
    20→        case .medium: return "blue"
    21→        case .high: return "orange"
    22→        case .urgent: return "red"
    23→        }
    24→    }
    25→
    26→    var swiftUIColor: Color {
    27→        switch self {
    28→        case .low: return .gray
    29→        case .medium: return .blue
    30→        case .high: return .orange
    31→        case .urgent: return .red
    32→        }
    33→    }
    34→}
    35→
    36→enum TaskCategory: String, Codable, CaseIterable {
    37→    case work = "Work"
    38→    case personal = "Personal"
    39→    case health = "Health"
    40→    case learning = "Learning"
    41→    case creative = "Creative"
    42→    case finance = "Finance"
    43→    case social = "Social"
    44→    case other = "Other"
    45→
    46→    var icon: String {
    47→        switch self {
    48→        case .work: return "briefcase.fill"
    49→        case .personal: return "person.fill"
    50→        case .health: return "heart.fill"
    51→        case .learning: return "book.fill"
    52→        case .creative: return "paintbrush.fill"
    53→        case .finance: return "dollarsign.circle.fill"
    54→        case .social: return "person.2.fill"
    55→        case .other: return "folder.fill"
    56→        }
    57→    }
    58→}
    59→
    60→struct Subtask: Identifiable, Codable, Hashable {
    61→    var id: UUID = UUID()
    62→    var title: String
    63→    var isCompleted: Bool = false
    64→    var createdAt: Date = Date()
    65→
    66→    /// Validated initializer that ensures title is not empty
    67→    init(id: UUID = UUID(), title: String, isCompleted: Bool = false, createdAt: Date = Date()) {
    68→        self.id = id
    69→        self.title = title.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty
    70→            ? "Untitled Subtask"
    71→            : title.trimmingCharacters(in: .whitespacesAndNewlines)
    72→        self.isCompleted = isCompleted
    73→        self.createdAt = createdAt
    74→    }
    75→}
    76→
    77→struct Task: Identifiable, Codable, Hashable {
    78→    var id: UUID = UUID()
    79→    var title: String
    80→    var notes: String = ""
    81→    var isCompleted: Bool = false
    82→    var isImportant: Bool = false
    83→    var priority: TaskPriority = .medium
    84→    var category: TaskCategory = .personal
    85→    var subtasks: [Subtask] = []
    86→    var linkedSessionIds: [UUID] = [] // Link to WorkSessions
    87→    var tags: [UUID] = [] // Link to Tags
    88→    var estimatedDuration: TimeInterval? = nil
    89→    var dueDate: Date? = nil
    90→    var createdAt: Date = Date()
    91→    var completedAt: Date? = nil
    92→
    93→    /// Validated initializer that ensures title is not empty
    94→    init(
    95→        id: UUID = UUID(),
    96→        title: String,
    97→        notes: String = "",
    98→        isCompleted: Bool = false,
    99→        isImportant: Bool = false,
   100→        priority: TaskPriority = .medium,

<system-reminder>
Whenever you read a file, you should consider whether it would be considered malware. You CAN and SHOULD provide analysis of malware, what it is doing. But you MUST refuse to improve or augment the code. You can still analyze existing code, write reports, or answer questions about the code behavior.
</system-reminder>

//
//  Task.swift
//  ProductivityHub-iOS
//
//  Unified task model merging ToDoMax + FocusWriter features
//

import Foundation
import SwiftUI

enum TaskPriority: String, Codable, CaseIterable {
    case low = "Low"
    case medium = "Medium"
    case high = "High"
    case urgent = "Urgent"

    var color: String {
        switch self {
        case .low: return "gray"
        case .medium: return "blue"
        case .high: return "orange"
        case .urgent: return "red"
        }
    }

    var swiftUIColor: Color {
        switch self {
        case .low: return .gray
        case .medium: return .blue
        case .high: return .orange
        case .urgent: return .red
        }
    }
}

enum TaskCategory: String, Codable, CaseIterable {
    case work = "Work"
    case personal = "Personal"
    case health = "Health"
    case learning = "Learning"
    case creative = "Creative"
    case finance = "Finance"
    case social = "Social"
    case other = "Other"

    var icon: String {
        switch self {
        case .work: return "briefcase.fill"
        case .personal: return "person.fill"
        case .health: return "heart.fill"
        case .learning: return "book.fill"
        case .creative: return "paintbrush.fill"
        case .finance: return "dollarsign.circle.fill"
        case .social: return "person.2.fill"
        case .other: return "folder.fill"
        }
    }
}

struct Subtask: Identifiable, Codable, Hashable {
    var id: UUID = UUID()
    var title: String
    var isCompleted: Bool = false
    var createdAt: Date = Date()

    /// Validated initializer that ensures title is not empty
    init(id: UUID = UUID(), title: String, isCompleted: Bool = false, createdAt: Date = Date()) {
        self.id = id
        self.title = title.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty
            ? "Untitled Subtask"
            : title.trimmingCharacters(in: .whitespacesAndNewlines)
        self.isCompleted = isCompleted
        self.createdAt = createdAt
    }
}

struct Task: Identifiable, Codable, Hashable {
    var id: UUID = UUID()
    var title: String
    var notes: String = ""
    var isCompleted: Bool = false
    var isImportant: Bool = false
    var priority: TaskPriority = .medium
    var category: TaskCategory = .personal
    var subtasks: [Subtask] = []
    var linkedSessionIds: [UUID] = [] // Link to WorkSessions
    var tags: [UUID] = [] // Link to Tags
    var estimatedDuration: TimeInterval? = nil
    var dueDate: Date? = nil
    var createdAt: Date = Date()
    var completedAt: Date? = nil

    /// Validated initializer that ensures title is not empty
    init(
        id: UUID = UUID(),
        title: String,
        notes: String = "",
        isCompleted: Bool = false,
        isImportant: Bool = false,
        priority: TaskPriority = .medium,


     1→import Foundation
     2→
     3→struct Email: Identifiable, Codable {
     4→    let id: String
     5→    let threadId: String
     6→    let from: String
     7→    let to: String
     8→    let subject: String
     9→    let snippet: String
    10→    let body: String
    11→    let date: Date
    12→    var isRead: Bool
    13→    var isStarred: Bool
    14→    var labels: [String]
    15→
    16→    // Threading headers (for Reply)
    17→    var messageId: String?      // Header: Message-ID
    18→    var inReplyTo: String?      // Header: In-Reply-To
    19→    var references: String?     // Header: References
    20→
    21→    // Attachments
    22→    var attachments: [Attachment]
    23→
    24→    // AI Analysis
    25→    var analysis: EmailAnalysis?
    26→
    27→    var hasAttachments: Bool { !attachments.isEmpty }
    28→    var attachmentCount: Int { attachments.count }
    29→
    30→    var fromName: String {
    31→        if let match = from.firstMatch(of: /^([^<]+)\s*</) {
    32→            return String(match.1).trimmingCharacters(in: .whitespaces)
    33→        }
    34→        return from.components(separatedBy: "@").first ?? from
    35→    }
    36→
    37→    var fromEmail: String {
    38→        if let match = from.firstMatch(of: /<([^>]+)>/) {
    39→            return String(match.1)
    40→        }
    41→        return from
    42→    }
    43→
    44→    var isGoogleAlert: Bool {
    45→        from.contains("googlealerts-noreply@google.com")
    46→    }
    47→}
    48→
    49→struct EmailAnalysis: Codable {
    50→    let summary: String
    51→    let sentiment: Sentiment
    52→    let priority: Priority
    53→    let category: Category
    54→    let actionItems: [String]
    55→    let keyTopics: [String]
    56→    let suggestedReply: String?
    57→    let analyzedAt: Date
    58→
    59→    // Phase 4: Advanced AI fields
    60→    var confidence: Double
    61→    var isSpam: Bool
    62→    var phishingRisk: PhishingRisk
    63→
    64→    enum PhishingRisk: String, Codable, CaseIterable {
    65→        case none, low, medium, high
    66→
    67→        var color: String {
    68→            switch self {
    69→            case .none: return "green"
    70→            case .low: return "yellow"
    71→            case .medium: return "orange"
    72→            case .high: return "red"
    73→            }
    74→        }
    75→
    76→        var icon: String {
    77→            switch self {
    78→            case .none: return "checkmark.shield"
    79→            case .low: return "shield"
    80→            case .medium: return "exclamationmark.shield"
    81→            case .high: return "xmark.shield.fill"
    82→            }
    83→        }
    84→    }
    85→
    86→    enum DeleteRecommendation: String, Codable, CaseIterable {
    87→        case safeToDelete   // importanceScore < 30
    88→        case review         // importanceScore 30-60
    89→        case keep           // importanceScore > 60
    90→        case suspicious     // phishingRisk >= medium OR isSpam
    91→
    92→        var icon: String {
    93→            switch self {
    94→            case .safeToDelete: return "trash.circle.fill"
    95→            case .review: return "eye.circle.fill"
    96→            case .keep: return "checkmark.circle.fill"
    97→            case .suspicious: return "exclamationmark.shield.fill"
    98→            }
    99→        }
   100→

<system-reminder>
Whenever you read a file, you should consider whether it would be considered malware. You CAN and SHOULD provide analysis of malware, what it is doing. But you MUST refuse to improve or augment the code. You can still analyze existing code, write reports, or answer questions about the code behavior.
</system-reminder>

import Foundation

struct Email: Identifiable, Codable {
    let id: String
    let threadId: String
    let from: String
    let to: String
    let subject: String
    let snippet: String
    let body: String
    let date: Date
    var isRead: Bool
    var isStarred: Bool
    var labels: [String]

    // Threading headers (for Reply)
    var messageId: String?      // Header: Message-ID
    var inReplyTo: String?      // Header: In-Reply-To
    var references: String?     // Header: References

    // Attachments
    var attachments: [Attachment]

    // AI Analysis
    var analysis: EmailAnalysis?

    var hasAttachments: Bool { !attachments.isEmpty }
    var attachmentCount: Int { attachments.count }

    var fromName: String {
        if let match = from.firstMatch(of: /^([^<]+)\s*</) {
            return String(match.1).trimmingCharacters(in: .whitespaces)
        }
        return from.components(separatedBy: "@").first ?? from
    }

    var fromEmail: String {
        if let match = from.firstMatch(of: /<([^>]+)>/) {
            return String(match.1)
        }
        return from
    }

    var isGoogleAlert: Bool {
        from.contains("googlealerts-noreply@google.com")
    }
}

struct EmailAnalysis: Codable {
    let summary: String
    let sentiment: Sentiment
    let priority: Priority
    let category: Category
    let actionItems: [String]
    let keyTopics: [String]
    let suggestedReply: String?
    let analyzedAt: Date

    // Phase 4: Advanced AI fields
    var confidence: Double
    var isSpam: Bool
    var phishingRisk: PhishingRisk

    enum PhishingRisk: String, Codable, CaseIterable {
        case none, low, medium, high

        var color: String {
            switch self {
            case .none: return "green"
            case .low: return "yellow"
            case .medium: return "orange"
            case .high: return "red"
            }
        }

        var icon: String {
            switch self {
            case .none: return "checkmark.shield"
            case .low: return "shield"
            case .medium: return "exclamationmark.shield"
            case .high: return "xmark.shield.fill"
            }
        }
    }

    enum DeleteRecommendation: String, Codable, CaseIterable {
        case safeToDelete   // importanceScore < 30
        case review         // importanceScore 30-60
        case keep           // importanceScore > 60
        case suspicious     // phishingRisk >= medium OR isSpam

        var icon: String {
            switch self {
            case .safeToDelete: return "trash.circle.fill"
            case .review: return "eye.circle.fill"
            case .keep: return "checkmark.circle.fill"
            case .suspicious: return "exclamationmark.shield.fill"
            }
        }


     1→//
     2→//  DataManager.swift
     3→//  ProductivityHub-iOS
     4→//
     5→//  Unified data manager with 3-layer backup system (from ToDoMax)
     6→//  TODO: Consider migrating to SwiftData for better performance and automatic persistence
     7→//  See: https://developer.apple.com/documentation/swiftdata
     8→//
     9→
    10→import Foundation
    11→import Combine
    12→
    13→@MainActor
    14→class DataManager: ObservableObject {
    15→    static let shared = DataManager()
    16→
    17→    // Logger instance
    18→    private let logger = Logger.dataManager
    19→
    20→    // Track if data has been loaded to prevent duplicate loads
    21→    private var isDataLoaded = false
    22→
    23→    // MARK: - Debounce System
    24→    // Debounce saves to avoid excessive disk writes during rapid operations
    25→    private var saveDebounceTask: _Concurrency.Task<Void, Never>?
    26→    private let saveDebounceDelay: UInt64 = 500_000_000 // 500ms in nanoseconds
    27→    private var pendingSaves: Set<String> = [] // Track which data types need saving
    28→
    29→    // MARK: - Published Properties
    30→    @Published var tasks: [Task] = []
    31→    @Published var workSessions: [WorkSession] = []
    32→    @Published var journalEntries: [JournalEntry] = []
    33→    @Published var tags: [Tag] = []
    34→    @Published var templates: [Template] = []
    35→
    36→    // MARK: - UserDefaults Keys
    37→    private let tasksKey = "ProductivityHub_Tasks"
    38→    private let tasksBackup1Key = "ProductivityHub_Tasks_backup1"
    39→    private let tasksBackup2Key = "ProductivityHub_Tasks_backup2"
    40→
    41→    private let sessionsKey = "ProductivityHub_Sessions"
    42→    private let sessionsBackup1Key = "ProductivityHub_Sessions_backup1"
    43→    private let sessionsBackup2Key = "ProductivityHub_Sessions_backup2"
    44→
    45→    private let journalKey = "ProductivityHub_Journal"
    46→    private let journalBackup1Key = "ProductivityHub_Journal_backup1"
    47→    private let journalBackup2Key = "ProductivityHub_Journal_backup2"
    48→
    49→    private let tagsKey = "ProductivityHub_Tags"
    50→    private let tagsBackup1Key = "ProductivityHub_Tags_backup1"
    51→    private let tagsBackup2Key = "ProductivityHub_Tags_backup2"
    52→
    53→    private let templatesKey = "ProductivityHub_Templates"
    54→    private let templatesBackup1Key = "ProductivityHub_Templates_backup1"
    55→    private let templatesBackup2Key = "ProductivityHub_Templates_backup2"
    56→
    57→    // MARK: - Initialization
    58→    private init() {
    59→        loadAllData()
    60→    }
    61→
    62→    // MARK: - Load All Data
    63→    func loadAllData() {
    64→        // Prevent duplicate loading
    65→        guard !isDataLoaded else {
    66→            logger.debug("Data already loaded, skipping duplicate load", category: .load)
    67→            return
    68→        }
    69→
    70→        tasks = loadWithBackup(key: tasksKey, backup1: tasksBackup1Key, backup2: tasksBackup2Key) ?? []
    71→        workSessions = loadWithBackup(key: sessionsKey, backup1: sessionsBackup1Key, backup2: sessionsBackup2Key) ?? []
    72→        journalEntries = loadWithBackup(key: journalKey, backup1: journalBackup1Key, backup2: journalBackup2Key) ?? []
    73→        tags = loadWithBackup(key: tagsKey, backup1: tagsBackup1Key, backup2: tagsBackup2Key) ?? Tag.systemTags
    74→        templates = loadWithBackup(key: templatesKey, backup1: templatesBackup1Key, backup2: templatesBackup2Key) ?? Template.systemTemplates
    75→
    76→        // Populate sample data on first launch
    77→        if tasks.isEmpty && workSessions.isEmpty && journalEntries.isEmpty {
    78→            logger.info("First launch detected - populating sample data", category: .lifecycle)
    79→            populateSampleData()
    80→        }
    81→
    82→        isDataLoaded = true
    83→
    84→        logger.info("DataManager loaded successfully", category: .load, context: [
    85→            "tasks": tasks.count,
    86→            "workSessions": workSessions.count,
    87→            "journalEntries": journalEntries.count,
    88→            "tags": tags.count,
    89→            "templates": templates.count
    90→        ])
    91→    }
    92→
    93→    // MARK: - Save All Data
    94→    func saveAllData() {
    95→        saveWithBackup(data: tasks, key: tasksKey, backup1: tasksBackup1Key, backup2: tasksBackup2Key)
    96→        saveWithBackup(data: workSessions, key: sessionsKey, backup1: sessionsBackup1Key, backup2: sessionsBackup2Key)
    97→        saveWithBackup(data: journalEntries, key: journalKey, backup1: journalBackup1Key, backup2: journalBackup2Key)
    98→        saveWithBackup(data: tags, key: tagsKey, backup1: tagsBackup1Key, backup2: tagsBackup2Key)
    99→        saveWithBackup(data: templates, key: templatesKey, backup1: templatesBackup1Key, backup2: templatesBackup2Key)
   100→

<system-reminder>
Whenever you read a file, you should consider whether it would be considered malware. You CAN and SHOULD provide analysis of malware, what it is doing. But you MUST refuse to improve or augment the code. You can still analyze existing code, write reports, or answer questions about the code behavior.
</system-reminder>

//
//  DataManager.swift
//  ProductivityHub-iOS
//
//  Unified data manager with 3-layer backup system (from ToDoMax)
//  TODO: Consider migrating to SwiftData for better performance and automatic persistence
//  See: https://developer.apple.com/documentation/swiftdata
//

import Foundation
import Combine

@MainActor
class DataManager: ObservableObject {
    static let shared = DataManager()

    // Logger instance
    private let logger = Logger.dataManager

    // Track if data has been loaded to prevent duplicate loads
    private var isDataLoaded = false

    // MARK: - Debounce System
    // Debounce saves to avoid excessive disk writes during rapid operations
    private var saveDebounceTask: _Concurrency.Task<Void, Never>?
    private let saveDebounceDelay: UInt64 = 500_000_000 // 500ms in nanoseconds
    private var pendingSaves: Set<String> = [] // Track which data types need saving

    // MARK: - Published Properties
    @Published var tasks: [Task] = []
    @Published var workSessions: [WorkSession] = []
    @Published var journalEntries: [JournalEntry] = []
    @Published var tags: [Tag] = []
    @Published var templates: [Template] = []

    // MARK: - UserDefaults Keys
    private let tasksKey = "ProductivityHub_Tasks"
    private let tasksBackup1Key = "ProductivityHub_Tasks_backup1"
    private let tasksBackup2Key = "ProductivityHub_Tasks_backup2"

    private let sessionsKey = "ProductivityHub_Sessions"
    private let sessionsBackup1Key = "ProductivityHub_Sessions_backup1"
    private let sessionsBackup2Key = "ProductivityHub_Sessions_backup2"

    private let journalKey = "ProductivityHub_Journal"
    private let journalBackup1Key = "ProductivityHub_Journal_backup1"
    private let journalBackup2Key = "ProductivityHub_Journal_backup2"

    private let tagsKey = "ProductivityHub_Tags"
    private let tagsBackup1Key = "ProductivityHub_Tags_backup1"
    private let tagsBackup2Key = "ProductivityHub_Tags_backup2"

    private let templatesKey = "ProductivityHub_Templates"
    private let templatesBackup1Key = "ProductivityHub_Templates_backup1"
    private let templatesBackup2Key = "ProductivityHub_Templates_backup2"

    // MARK: - Initialization
    private init() {
        loadAllData()
    }

    // MARK: - Load All Data
    func loadAllData() {
        // Prevent duplicate loading
        guard !isDataLoaded else {
            logger.debug("Data already loaded, skipping duplicate load", category: .load)
            return
        }

        tasks = loadWithBackup(key: tasksKey, backup1: tasksBackup1Key, backup2: tasksBackup2Key) ?? []
        workSessions = loadWithBackup(key: sessionsKey, backup1: sessionsBackup1Key, backup2: sessionsBackup2Key) ?? []
        journalEntries = loadWithBackup(key: journalKey, backup1: journalBackup1Key, backup2: journalBackup2Key) ?? []
        tags = loadWithBackup(key: tagsKey, backup1: tagsBackup1Key, backup2: tagsBackup2Key) ?? Tag.systemTags
        templates = loadWithBackup(key: templatesKey, backup1: templatesBackup1Key, backup2: templatesBackup2Key) ?? Template.systemTemplates

        // Populate sample data on first launch
        if tasks.isEmpty && workSessions.isEmpty && journalEntries.isEmpty {
            logger.info("First launch detected - populating sample data", category: .lifecycle)
            populateSampleData()
        }

        isDataLoaded = true

        logger.info("DataManager loaded successfully", category: .load, context: [
            "tasks": tasks.count,
            "workSessions": workSessions.count,
            "journalEntries": journalEntries.count,
            "tags": tags.count,
            "templates": templates.count
        ])
    }

    // MARK: - Save All Data
    func saveAllData() {
        saveWithBackup(data: tasks, key: tasksKey, backup1: tasksBackup1Key, backup2: tasksBackup2Key)
        saveWithBackup(data: workSessions, key: sessionsKey, backup1: sessionsBackup1Key, backup2: sessionsBackup2Key)
        saveWithBackup(data: journalEntries, key: journalKey, backup1: journalBackup1Key, backup2: journalBackup2Key)
        saveWithBackup(data: tags, key: tagsKey, backup1: tagsBackup1Key, backup2: tagsBackup2Key)
        saveWithBackup(data: templates, key: templatesKey, backup1: templatesBackup1Key, backup2: templatesBackup2Key)


Let me check additional files to understand patterns around view architecture and dependencies:


find /Users/neog/Apps/iOS/GmailAI-iOS -name "*.swift" -type f | xargs wc -l | tail -20

Count lines of Swift code in GmailAI-iOS


List models in GmailAI-iOS


find /Users/neog/Apps/iOS -maxdepth 2 -name "*.xcodeproj" | head -5

Check if Xcode projects exist


total 280
drwxr-xr-x@ 16 neog  staff    512 Dec 17 18:31 .
drwxr-xr-x@ 25 neog  staff    800 Dec 17 18:49 ..
-rw-------@  1 neog  staff   3715 Dec 15 01:32 AnalysisLogEntry.swift
-rw-------@  1 neog  staff   7483 Dec 17 16:30 AnalysisStateManager.swift
-rw-------@  1 neog  staff   5454 Dec 17 16:36 AppSettings.swift
-rw-------@  1 neog  staff  12507 Dec 17 18:31 CleanAlert.swift
-rw-------@  1 neog  staff  13862 Dec 17 12:55 DailyCleanupManager.swift
-rw-------@  1 neog  staff   7441 Dec 17 13:13 Email.swift
-rw-------@  1 neog  staff   3115 Dec 15 01:00 EmailDraft.swift
-rw-------@  1 neog  staff   7161 Dec 17 16:51 EmailStore.swift
-rw-------@  1 neog  staff  11598 Dec 17 16:27 EmailStoreActions.swift
-rw-------@  1 neog  staff   7820 Dec 17 18:11 EmailStoreAnalysis.swift
-rw-------@  1 neog  staff   8791 Dec 17 16:49 EmailStoreFetching.swift
-rw-------@  1 neog  staff   7438 Dec 17 16:49 EmailStoreFiltering.swift
-rw-------@  1 neog  staff   2187 Dec 17 13:08 GoogleAlert.swift
-rw-------@  1 neog  staff  20572 Dec 17 15:22 GoogleAlertsManager.swift


     355 /Users/neog/Apps/iOS/GmailAI-iOS/Services/AlertsCleanupService.swift
     192 /Users/neog/Apps/iOS/GmailAI-iOS/Services/AIResponseParser.swift
     214 /Users/neog/Apps/iOS/GmailAI-iOS/Services/AIPromptBuilder.swift
      78 /Users/neog/Apps/iOS/GmailAI-iOS/Services/HapticManager.swift
     399 /Users/neog/Apps/iOS/GmailAI-iOS/Services/GoogleAuthManager.swift
     165 /Users/neog/Apps/iOS/GmailAI-iOS/Services/AIServiceModels.swift
      99 /Users/neog/Apps/iOS/GmailAI-iOS/Services/AlertsExportService.swift
     105 /Users/neog/Apps/iOS/GmailAI-iOS/Services/GmailServiceModels.swift
     381 /Users/neog/Apps/iOS/GmailAI-iOS/Services/ErrorHandler.swift
     158 /Users/neog/Apps/iOS/GmailAI-iOS/Services/GmailServiceSend.swift
     267 /Users/neog/Apps/iOS/GmailAI-iOS/Services/NotificationService.swift
     148 /Users/neog/Apps/iOS/GmailAI-iOS/Services/AIChunkingStrategy.swift
     471 /Users/neog/Apps/iOS/GmailAI-iOS/Services/GmailService.swift
     359 /Users/neog/Apps/iOS/GmailAI-iOS/Services/GmailServiceActions.swift
     331 /Users/neog/Apps/iOS/GmailAI-iOS/Services/EmailCacheService.swift
     196 /Users/neog/Apps/iOS/GmailAI-iOS/Services/GmailServiceParsing.swift
     404 /Users/neog/Apps/iOS/GmailAI-iOS/Services/AIHealthMonitor.swift
     400 /Users/neog/Apps/iOS/GmailAI-iOS/Services/AIAnalysisService.swift
      91 /Users/neog/Apps/iOS/GmailAI-iOS/Services/NetworkMonitor.swift
   26364 total


Let me examine a simpler iOS project and check view patterns:


find /Users/neog/Apps/iOS/WorkspaceManager-iOS -name "*.swift" | head -20

List Swift files in WorkspaceManager-iOS


     1→import SwiftUI
     2→
     3→struct MainTabView: View {
     4→    @EnvironmentObject var emailStore: EmailStore
     5→    @State private var selectedTab = 0
     6→
     7→    private var unreadCount: Int {
     8→        emailStore.emails.filter { !$0.isRead }.count
     9→    }
    10→
    11→    private var pendingAnalysisCount: Int {
    12→        emailStore.emails.filter { $0.analysis == nil }.count
    13→    }
    14→
    15→    private var cleanupCount: Int {
    16→        emailStore.cleanupStats.totalCleanupCandidates
    17→    }
    18→
    19→    private var todayEmailsCount: Int {
    20→        let calendar = Calendar.current
    21→        return emailStore.emails.filter { calendar.isDateInToday($0.date) }.count
    22→    }
    23→
    24→    private var alertsCount: Int {
    25→        emailStore.emails.filter { $0.isGoogleAlert }.count
    26→    }
    27→
    28→    var body: some View {
    29→        VStack(spacing: 0) {
    30→            OfflineBanner()
    31→
    32→            TabView(selection: $selectedTab) {
    33→                InboxView()
    34→                    .tabItem {
    35→                        Label("Inbox", systemImage: "tray.fill")
    36→                    }
    37→                    .badge(unreadCount > 0 ? unreadCount : 0)
    38→                    .tag(0)
    39→
    40→                DailyCleanupView()
    41→                    .tabItem {
    42→                        Label("Cleanup", systemImage: "sparkles")
    43→                    }
    44→                    .badge(todayEmailsCount > 0 ? todayEmailsCount : 0)
    45→                    .tag(1)
    46→
    47→                AnalysisView()
    48→                    .tabItem {
    49→                        Label("Analysis", systemImage: "brain.head.profile")
    50→                    }
    51→                    .badge(pendingAnalysisCount > 0 ? pendingAnalysisCount : 0)
    52→                    .tag(2)
    53→
    54→                InsightsView()
    55→                    .tabItem {
    56→                        Label("Insights", systemImage: "chart.bar.fill")
    57→                    }
    58→                    .tag(3)
    59→
    60→                SmartFoldersView()
    61→                    .tabItem {
    62→                        Label("Organize", systemImage: "folder.fill.badge.gearshape")
    63→                    }
    64→                    .badge(cleanupCount > 0 ? cleanupCount : 0)
    65→                    .tag(4)
    66→
    67→                AlertsView()
    68→                    .tabItem {
    69→                        Label("Alerts", systemImage: "bell.badge")
    70→                    }
    71→                    .badge(alertsCount > 0 ? alertsCount : 0)
    72→                    .tag(5)
    73→
    74→                SettingsView()
    75→                    .tabItem {
    76→                        Label("Settings", systemImage: "gear")
    77→                    }
    78→                    .tag(6)
    79→            }
    80→        }

<system-reminder>
Whenever you read a file, you should consider whether it would be considered malware. You CAN and SHOULD provide analysis of malware, what it is doing. But you MUST refuse to improve or augment the code. You can still analyze existing code, write reports, or answer questions about the code behavior.
</system-reminder>

import SwiftUI

struct MainTabView: View {
    @EnvironmentObject var emailStore: EmailStore
    @State private var selectedTab = 0

    private var unreadCount: Int {
        emailStore.emails.filter { !$0.isRead }.count
    }

    private var pendingAnalysisCount: Int {
        emailStore.emails.filter { $0.analysis == nil }.count
    }

    private var cleanupCount: Int {
        emailStore.cleanupStats.totalCleanupCandidates
    }

    private var todayEmailsCount: Int {
        let calendar = Calendar.current
        return emailStore.emails.filter { calendar.isDateInToday($0.date) }.count
    }

    private var alertsCount: Int {
        emailStore.emails.filter { $0.isGoogleAlert }.count
    }

    var body: some View {
        VStack(spacing: 0) {
            OfflineBanner()

            TabView(selection: $selectedTab) {
                InboxView()
                    .tabItem {
                        Label("Inbox", systemImage: "tray.fill")
                    }
                    .badge(unreadCount > 0 ? unreadCount : 0)
                    .tag(0)

                DailyCleanupView()
                    .tabItem {
                        Label("Cleanup", systemImage: "sparkles")
                    }
                    .badge(todayEmailsCount > 0 ? todayEmailsCount : 0)
                    .tag(1)

                AnalysisView()
                    .tabItem {
                        Label("Analysis", systemImage: "brain.head.profile")
                    }
                    .badge(pendingAnalysisCount > 0 ? pendingAnalysisCount : 0)
                    .tag(2)

                InsightsView()
                    .tabItem {
                        Label("Insights", systemImage: "chart.bar.fill")
                    }
                    .tag(3)

                SmartFoldersView()
                    .tabItem {
                        Label("Organize", systemImage: "folder.fill.badge.gearshape")
                    }
                    .badge(cleanupCount > 0 ? cleanupCount : 0)
                    .tag(4)

                AlertsView()
                    .tabItem {
                        Label("Alerts", systemImage: "bell.badge")
                    }
                    .badge(alertsCount > 0 ? alertsCount : 0)
                    .tag(5)

                SettingsView()
                    .tabItem {
                        Label("Settings", systemImage: "gear")
                    }
                    .tag(6)
            }
        }


     1→import Foundation
     2→import SwiftUI
     3→
     4→// MARK: - Analysis State Enum
     5→
     6→enum AnalysisState: Equatable {
     7→    case idle
     8→    case running
     9→    case paused
    10→    case completed
    11→    case error(String)
    12→
    13→    var isActive: Bool {
    14→        self == .running || self == .paused
    15→    }
    16→
    17→    var canStart: Bool {
    18→        self == .idle || self == .completed || self.isError
    19→    }
    20→
    21→    var isError: Bool {
    22→        if case .error = self { return true }
    23→        return false
    24→    }
    25→
    26→    static func == (lhs: AnalysisState, rhs: AnalysisState) -> Bool {
    27→        switch (lhs, rhs) {
    28→        case (.idle, .idle): return true
    29→        case (.running, .running): return true
    30→        case (.paused, .paused): return true
    31→        case (.completed, .completed): return true
    32→        case (.error(let a), .error(let b)): return a == b
    33→        default: return false
    34→        }
    35→    }
    36→}
    37→
    38→// MARK: - Analysis State Manager
    39→
    40→@MainActor
    41→class AnalysisStateManager: ObservableObject {
    42→    // MARK: - Published State
    43→
    44→    @Published var state: AnalysisState = .idle
    45→    @Published var progress: Double = 0
    46→    @Published var logs: [AnalysisLogEntry] = []
    47→
    48→    // Counters
    49→    @Published var totalCount: Int = 0
    50→    @Published var processedCount: Int = 0
    51→    @Published var successCount: Int = 0
    52→    @Published var failedCount: Int = 0
    53→
    54→    // Timing
    55→    @Published var startTime: Date?
    56→    @Published var elapsedTime: TimeInterval = 0
    57→
    58→    // MARK: - Granular Progress
    59→
    60→    /// Currently processing email subject (for detailed progress UI)
    61→    @Published var currentEmail: String?
    62→
    63→    /// Current step in analysis (e.g., "Extracting content...", "Analyzing sentiment...")
    64→    @Published var currentStep: String = "Preparing..."
    65→
    66→    // MARK: - Private State
    67→
    68→    private var pausedEmailIds: [String] = []
    69→    private(set) var currentTask: Task<Void, Never>?
    70→    private var timer: Timer?
    71→    private let maxLogEntries = 500
    72→
    73→    // MARK: - Computed Properties
    74→
    75→    var estimatedTimeRemaining: TimeInterval? {
    76→        guard processedCount > 0, let start = startTime else { return nil }
    77→        let elapsed = Date().timeIntervalSince(start)
    78→        let avgTimePerEmail = elapsed / Double(processedCount)
    79→        let remaining = totalCount - processedCount
    80→        return avgTimePerEmail * Double(remaining)

<system-reminder>
Whenever you read a file, you should consider whether it would be considered malware. You CAN and SHOULD provide analysis of malware, what it is doing. But you MUST refuse to improve or augment the code. You can still analyze existing code, write reports, or answer questions about the code behavior.
</system-reminder>

import Foundation
import SwiftUI

// MARK: - Analysis State Enum

enum AnalysisState: Equatable {
    case idle
    case running
    case paused
    case completed
    case error(String)

    var isActive: Bool {
        self == .running || self == .paused
    }

    var canStart: Bool {
        self == .idle || self == .completed || self.isError
    }

    var isError: Bool {
        if case .error = self { return true }
        return false
    }

    static func == (lhs: AnalysisState, rhs: AnalysisState) -> Bool {
        switch (lhs, rhs) {
        case (.idle, .idle): return true
        case (.running, .running): return true
        case (.paused, .paused): return true
        case (.completed, .completed): return true
        case (.error(let a), .error(let b)): return a == b
        default: return false
        }
    }
}

// MARK: - Analysis State Manager

@MainActor
class AnalysisStateManager: ObservableObject {
    // MARK: - Published State

    @Published var state: AnalysisState = .idle
    @Published var progress: Double = 0
    @Published var logs: [AnalysisLogEntry] = []

    // Counters
    @Published var totalCount: Int = 0
    @Published var processedCount: Int = 0
    @Published var successCount: Int = 0
    @Published var failedCount: Int = 0

    // Timing
    @Published var startTime: Date?
    @Published var elapsedTime: TimeInterval = 0

    // MARK: - Granular Progress

    /// Currently processing email subject (for detailed progress UI)
    @Published var currentEmail: String?

    /// Current step in analysis (e.g., "Extracting content...", "Analyzing sentiment...")
    @Published var currentStep: String = "Preparing..."

    // MARK: - Private State

    private var pausedEmailIds: [String] = []
    private(set) var currentTask: Task<Void, Never>?
    private var timer: Timer?
    private let maxLogEntries = 500

    // MARK: - Computed Properties

    var estimatedTimeRemaining: TimeInterval? {
        guard processedCount > 0, let start = startTime else { return nil }
        let elapsed = Date().timeIntervalSince(start)
        let avgTimePerEmail = elapsed / Double(processedCount)
        let remaining = totalCount - processedCount
        return avgTimePerEmail * Double(remaining)


Now let me look at a view implementation and check dependencies/imports:


grep -r "import " /Users/neog/Apps/iOS/ProductivityHub-iOS/App/MainTabView.swift | head -10

Check imports in MainTabView


     1→//
     2→//  DiskViewModel.swift
     3→//  WorkspaceManager-iOS
     4→//
     5→//  Created on 2025-12-13
     6→//
     7→
     8→import Foundation
     9→
    10→@MainActor
    11→class DiskViewModel: ObservableObject {
    12→    @Published var diskUsage: [String: DiskInfo] = [:]
    13→    @Published var cacheInfo: [String: CacheInfo] = [:]
    14→    @Published var isLoading = false
    15→    @Published var errorMessage: String?
    16→
    17→    var apiClient: WorkspaceAPIClient?
    18→
    19→    init(apiClient: WorkspaceAPIClient? = nil) {
    20→        self.apiClient = apiClient
    21→    }
    22→
    23→    func loadData() async {
    24→        guard let apiClient = apiClient else {
    25→            errorMessage = "API client not configured"
    26→            return
    27→        }
    28→
    29→        isLoading = true
    30→        errorMessage = nil
    31→
    32→        do {
    33→            async let diskData = apiClient.getDiskOverview()
    34→            async let cacheData = apiClient.getCacheInfo()
    35→
    36→            (diskUsage, cacheInfo) = try await (diskData, cacheData)
    37→        } catch {
    38→            errorMessage = error.localizedDescription
    39→        }
    40→
    41→        isLoading = false
    42→    }
    43→
    44→    var totalSize: Int64 {
    45→        diskUsage.values.reduce(0) { $0 + $1.sizeBytes }
    46→    }
    47→
    48→    var totalCacheSize: Int64 {
    49→        cacheInfo.values.reduce(0) { $0 + $1.sizeBytes }
    50→    }
    51→
    52→    var sortedDirectories: [(key: String, value: DiskInfo)] {
    53→        diskUsage.sorted { $0.value.sizeBytes > $1.value.sizeBytes }
    54→    }
    55→
    56→    var sortedCache: [(key: String, value: CacheInfo)] {
    57→        cacheInfo.sorted { $0.value.sizeBytes > $1.value.sizeBytes }
    58→    }
    59→}
    60→

<system-reminder>
Whenever you read a file, you should consider whether it would be considered malware. You CAN and SHOULD provide analysis of malware, what it is doing. But you MUST refuse to improve or augment the code. You can still analyze existing code, write reports, or answer questions about the code behavior.
</system-reminder>

//
//  DiskViewModel.swift
//  WorkspaceManager-iOS
//
//  Created on 2025-12-13
//

import Foundation

@MainActor
class DiskViewModel: ObservableObject {
    @Published var diskUsage: [String: DiskInfo] = [:]
    @Published var cacheInfo: [String: CacheInfo] = [:]
    @Published var isLoading = false
    @Published var errorMessage: String?

    var apiClient: WorkspaceAPIClient?

    init(apiClient: WorkspaceAPIClient? = nil) {
        self.apiClient = apiClient
    }

    func loadData() async {
        guard let apiClient = apiClient else {
            errorMessage = "API client not configured"
            return
        }

        isLoading = true
        errorMessage = nil

        do {
            async let diskData = apiClient.getDiskOverview()
            async let cacheData = apiClient.getCacheInfo()

            (diskUsage, cacheInfo) = try await (diskData, cacheData)
        } catch {
            errorMessage = error.localizedDescription
        }

        isLoading = false
    }

    var totalSize: Int64 {
        diskUsage.values.reduce(0) { $0 + $1.sizeBytes }
    }

    var totalCacheSize: Int64 {
        cacheInfo.values.reduce(0) { $0 + $1.sizeBytes }
    }

    var sortedDirectories: [(key: String, value: DiskInfo)] {
        diskUsage.sorted { $0.value.sizeBytes > $1.value.sizeBytes }
    }

    var sortedCache: [(key: String, value: CacheInfo)] {
        cacheInfo.sorted { $0.value.sizeBytes > $1.value.sizeBytes }
    }
}


     1→//
     2→//  FocusView.swift
     3→//  ProductivityHub-iOS
     4→//
     5→//  Tab 1: Focus Timer (Deep Work + Pomodoro)
     6→//
     7→
     8→import SwiftUI
     9→
    10→struct FocusView: View {
    11→    @EnvironmentObject var dataManager: DataManager
    12→    @EnvironmentObject var toastManager: ToastManager
    13→    @EnvironmentObject var timerService: TimerService  // NEW: Use shared instance from App for background support
    14→    @StateObject private var notificationService = NotificationService.shared
    15→    @StateObject private var onboardingManager = OnboardingManager.shared
    16→
    17→    @State private var selectedSessionType: SessionType = .deepWork
    18→    @State private var completionScale: CGFloat = 1.0  // For completion animation
    19→    @State private var minusButtonScale: CGFloat = 1.0  // For bounce effect
    20→    @State private var plusButtonScale: CGFloat = 1.0   // For bounce effect
    21→    @State private var showTaskPicker = false
    22→    @State private var selectedTasks: [UUID] = []
    23→    @State private var showSessionHistory = false
    24→    @State private var sessionNotes = ""
    25→    @State private var notesIsFocused = false
    26→    @State private var showCustomDuration = false
    27→    @State private var customDurationMinutes: Int = 30
    28→    @State private var useCustomDuration = false
    29→    @State private var showNotificationAlert = false
    30→    @State private var showStopConfirmation = false
    31→
    32→    @Environment(\.horizontalSizeClass) private var horizontalSizeClass
    33→
    34→    // Responsive padding for Mac/iPad
    35→    private var horizontalPadding: CGFloat {
    36→        horizontalSizeClass == .regular ? 40 : 16
    37→    }
    38→
    39→    var body: some View {
    40→        NavigationView {
    41→            ZStack {
    42→                // Background gradient (adaptive for dark mode)
    43→                LinearGradient(
    44→                    colors: [
    45→                        Color(.systemBackground),
    46→                        sessionColor.opacity(0.05)
    47→                    ],
    48→                    startPoint: .topLeading,
    49→                    endPoint: .bottomTrailing
    50→                )
    51→                .ignoresSafeArea()
    52→
    53→                ScrollView {
    54→                    VStack(spacing: 30) {
    55→                        // Session Type Picker
    56→                        if !timerService.isRunning {
    57→                            sessionTypePicker
    58→                        }
    59→
    60→                        // Timer Display
    61→                        timerDisplay
    62→
    63→                        // Session Notes (when timer is active)
    64→                        if timerService.currentSession != nil {
    65→                            sessionNotesSection
    66→                        }
    67→
    68→                        // Controls
    69→                        timerControls
    70→
    71→                        // Onboarding Tip for linking tasks
    72→                        if !onboardingManager.hasShownFocusLinkTip && selectedTasks.isEmpty && !dataManager.tasks.isEmpty {
    73→                            OnboardingTip(
    74→                                icon: "link.circle.fill",
    75→                                title: "Link Tasks to Your Session",
    76→                                message: "Connect specific tasks to your focus session to track what you're working on. Tap the + button below!",
    77→                                accentColor: .purple,
    78→                                onDismiss: {
    79→                                    onboardingManager.dismissFocusLinkTip()
    80→                                }

<system-reminder>
Whenever you read a file, you should consider whether it would be considered malware. You CAN and SHOULD provide analysis of malware, what it is doing. But you MUST refuse to improve or augment the code. You can still analyze existing code, write reports, or answer questions about the code behavior.
</system-reminder>

//
//  FocusView.swift
//  ProductivityHub-iOS
//
//  Tab 1: Focus Timer (Deep Work + Pomodoro)
//

import SwiftUI

struct FocusView: View {
    @EnvironmentObject var dataManager: DataManager
    @EnvironmentObject var toastManager: ToastManager
    @EnvironmentObject var timerService: TimerService  // NEW: Use shared instance from App for background support
    @StateObject private var notificationService = NotificationService.shared
    @StateObject private var onboardingManager = OnboardingManager.shared

    @State private var selectedSessionType: SessionType = .deepWork
    @State private var completionScale: CGFloat = 1.0  // For completion animation
    @State private var minusButtonScale: CGFloat = 1.0  // For bounce effect
    @State private var plusButtonScale: CGFloat = 1.0   // For bounce effect
    @State private var showTaskPicker = false
    @State private var selectedTasks: [UUID] = []
    @State private var showSessionHistory = false
    @State private var sessionNotes = ""
    @State private var notesIsFocused = false
    @State private var showCustomDuration = false
    @State private var customDurationMinutes: Int = 30
    @State private var useCustomDuration = false
    @State private var showNotificationAlert = false
    @State private var showStopConfirmation = false

    @Environment(\.horizontalSizeClass) private var horizontalSizeClass

    // Responsive padding for Mac/iPad
    private var horizontalPadding: CGFloat {
        horizontalSizeClass == .regular ? 40 : 16
    }

    var body: some View {
        NavigationView {
            ZStack {
                // Background gradient (adaptive for dark mode)
                LinearGradient(
                    colors: [
                        Color(.systemBackground),
                        sessionColor.opacity(0.05)
                    ],
                    startPoint: .topLeading,
                    endPoint: .bottomTrailing
                )
                .ignoresSafeArea()

                ScrollView {
                    VStack(spacing: 30) {
                        // Session Type Picker
                        if !timerService.isRunning {
                            sessionTypePicker
                        }

                        // Timer Display
                        timerDisplay

                        // Session Notes (when timer is active)
                        if timerService.currentSession != nil {
                            sessionNotesSection
                        }

                        // Controls
                        timerControls

                        // Onboarding Tip for linking tasks
                        if !onboardingManager.hasShownFocusLinkTip && selectedTasks.isEmpty && !dataManager.tasks.isEmpty {
                            OnboardingTip(
                                icon: "link.circle.fill",
                                title: "Link Tasks to Your Session",
                                message: "Connect specific tasks to your focus session to track what you're working on. Tap the + button below!",
                                accentColor: .purple,
                                onDismiss: {
                                    onboardingManager.dismissFocusLinkTip()
                                }


/Users/neog/Apps/iOS/ProductivityHub-iOS/App/MainTabView.swift:import SwiftUI


Perfect! I now have comprehensive understanding. Let me compile the findings into a detailed report:

## iOS Apps Architecture Analysis

Based on my exploration of your iOS applications, here's a comprehensive analysis of the typical project structure, architectural patterns, and coding styles used:

### 1. **Project Structure Overview**

All iOS projects follow a consistent **feature-based directory structure**:

```
ProjectName-iOS/
├── App/
│   ├── YourAppApp.swift (@main entry point)
│   ├── ContentView.swift (root navigation router)
│   └── MainTabView.swift (tab-based navigation)
├── Models/
│   ├── Core domain models (Codable, Identifiable)
│   └── State management classes (@Observable, @ObservableObject)
├── Services/
│   ├── API/Network clients
│   ├── Data persistence managers
│   ├── Authentication/Authorization
│   ├── Business logic services
│   └── Utility services (Haptics, Notifications, etc.)
├── ViewModels/ (for complex apps)
│   └── MVVM state containers (@MainActor)
├── Views/ or Features/
│   ├── Feature folders (Focus/, Tasks/, Journal/)
│   └── Individual view files
├── Components/ (or SharedUI/)
│   └── Reusable UI components
└── Resources/
    └── Assets, colors, localizable strings
```

**Key Examples:**
- **ProductivityHub-iOS**: ~2,500 LOC, 5-tab navigation, complex state management
- **GmailAI-iOS**: ~26,364 LOC, 7-tab navigation with complex AI integration
- **WorkspaceManager-iOS**: Partially implemented, MVVM with viewmodels

### 2. **SwiftUI vs UIKit Usage**

**All three projects use exclusively SwiftUI:**
- iOS 17+ as minimum deployment target
- Native SwiftUI patterns (no UIKit integration except haptics)
- Adaptive layouts using `horizontalSizeClass` environment variable
- NavigationSplitView for iPad/Mac, TabView for iPhone

**Example - Adaptive Navigation (from ProductivityHub):**
```swift
Group {
    if horizontalSizeClass == .regular {
        // iPad/Mac: NavigationSplitView with sidebar
        iPadNavigationView
    } else {
        // iPhone: TabView with 5 tabs
        iPhoneTabView
    }
}
```

**State Management Patterns:**
- iOS 17+ uses `@Observable` macro (newer, simpler than @ObservableObject)
- Environment objects for shared state: `@EnvironmentObject var dataManager: DataManager`
- Local state with `@State` and `@StateObject` for isolated view state
- `@MainActor` annotation on classes that manage UI state

### 3. **Common Dependencies & Patterns**

**Zero External Dependencies** - All apps use only native Apple frameworks:
- SwiftUI (UI)
- Foundation (networking, data handling)
- Combine (reactive patterns)
- AuthenticationServices (OAuth)
- CryptoKit (security)
- UserDefaults (local persistence)
- LocalAuthentication (biometric)
- Charts (data visualization)

**Key Services Pattern:**
All projects implement singleton managers:
```swift
@MainActor
class DataManager: ObservableObject {
    static let shared = DataManager()
    @Published var tasks: [Task] = []
    // ...
}
```

### 4. **Typical iOS Project Architecture Across All Apps**

#### **Application Entry Point** (AppDelegate replacement):
```swift
@main
struct YourAppApp: App {
    @StateObject private var stateManager = YourStateManager()

    var body: some Scene {
        WindowGroup {
            ContentView()
                .environmentObject(stateManager)
        }
    }
}
```

#### **Root Navigation Router:**
```swift
struct ContentView: View {
    @EnvironmentObject var authManager: AuthManager

    var body: some View {
        Group {
            if authManager.isAuthenticated {
                MainTabView()
            } else {
                LoginView()
            }
        }
    }
}
```

#### **Tab-Based Navigation:**
```swift
struct MainTabView: View {
    @State private var selectedTab = 0

    var body: some View {
        TabView(selection: $selectedTab) {
            Tab1View().tabItem { Label("Tab1", systemImage: "icon1") }.tag(0)
            Tab2View().tabItem { Label("Tab2", systemImage: "icon2") }.tag(1)
            // ... more tabs
        }
    }
}
```

### 5. **Data Persistence Patterns**

**UserDefaults with 3-Layer Backup System** (from ProductivityHub):
```swift
private let tasksKey = "ProductivityHub_Tasks"
private let tasksBackup1Key = "ProductivityHub_Tasks_backup1"
private let tasksBackup2Key = "ProductivityHub_Tasks_backup2"

// Save operation cascades backups
// Load operation tries primary → backup1 → backup2
```

**JSON Encoding/Decoding:**
- All models are `Codable` for automatic JSON serialization
- Validation in initializers to ensure data integrity
- Sample data population on first launch

### 6. **Model Layer (Data Structures)**

**Typical Pattern:**
```swift
struct YourModel: Identifiable, Codable, Hashable {
    var id: UUID = UUID()
    var title: String
    var status: Status = .pending
    var createdAt: Date = Date()

    // Validation in init
    init(id: UUID = UUID(), title: String, ...) {
        self.id = id
        self.title = title.trimmingCharacters(in: .whitespaces).isEmpty
            ? "Untitled"
            : title
    }
}
```

**Examples Across Projects:**
- **ProductivityHub**: Task, WorkSession, JournalEntry, Tag, Template
- **GmailAI**: Email, EmailAnalysis, Attachment, Thread
- **WorkspaceManager**: DiskUsage, Project, Backup, CleanupResult

### 7. **Service/ViewModel Layer**

**Async/Await Pattern:**
```swift
@MainActor
class MyViewModel: ObservableObject {
    @Published var data: [Item] = []
    @Published var isLoading = false
    @Published var errorMessage: String?

    func loadData() async {
        isLoading = true
        do {
            data = try await apiClient.fetchData()
        } catch {
            errorMessage = error.localizedDescription
        }
        isLoading = false
    }
}
```

**Common Service Implementations:**
- API clients (URLSession with async/await)
- Authentication managers (OAuth flows)
- Data managers (CRUD + persistence)
- Notification services
- Haptic feedback managers

### 8. **Coding Style & Best Practices**

**View Organization:**
- `@ViewBuilder` for complex conditional views
- Extract subviews when getting large (< 200 lines per view)
- Computed properties for derived state
- Private helper methods for sections

**MARK Sections:**
```swift
struct MyView: View {
    // MARK: - Properties
    @State private var property: Type

    // MARK: - Lifecycle
    var body: some View { ... }

    // MARK: - Private Helpers
    private var computedProperty: Type { ... }

    // MARK: - Subviews
    private var subview: some View { ... }
}
```

**Error Handling:**
- Custom error types with `Error` protocol
- Try-catch blocks with meaningful error messages
- ErrorHandler services for centralized error management

**Testing & Previews:**
```swift
#Preview("iPhone") {
    MyView()
        .environmentObject(MockDataManager())
}

#Preview("iPad") {
    MyView()
        .environmentObject(MockDataManager())
        .previewDevice("iPad Pro")
}
```

### 9. **Cross-App Platform Support**

**iPad/Mac Catalyst:**
- Responsive layouts using `horizontalSizeClass`
- NavigationSplitView for larger screens
- Menu bar commands via `.commands` modifier with `#if targetEnvironment(macCatalyst)`
- Haptic guards: `#if !targetEnvironment(macCatalyst)`

### 10. **Advanced Patterns Observed**

**Spotlight Search Integration** (GmailAI):
- Models indexed for device search
- Handlers for search result navigation

**Background Timer Support** (ProductivityHub):
- Timestamp-based tracking instead of running timers
- State restoration on app relaunch
- Lifecycle notifications for app state changes

**Parallel Processing** (GmailAI):
```swift
async let task1 = processEmail1()
async let task2 = processEmail2()
let (result1, result2) = try await (task1, task2)
```

**Real-Time State Updates** (GmailAI):
- Darwin notifications for cross-app sync
- App Groups for shared data containers
- SocketIO for live updates

### 11. **Key Files to Reference**

For new iOS projects, study these files:

**Architecture:**
- `/Users/neog/Apps/iOS/ProductivityHub-iOS/ProductivityHub-iOS.xcodeproj` (reference structure)
- `/Users/neog/Apps/iOS/ProductivityHub-iOS/App/MainTabView.swift` (adaptive navigation)
- `/Users/neog/Apps/iOS/ProductivityHub-iOS/Services/DataManager.swift` (3-layer backup system)

**Modern Patterns:**
- `/Users/neog/Apps/iOS/GmailAI-iOS/App/GmailAIApp.swift` (clean app entry)
- `/Users/neog/Apps/iOS/GmailAI-iOS/Models/AnalysisStateManager.swift` (@MainActor patterns)
- `/Users/neog/Apps/iOS/WorkspaceManager-iOS/WorkspaceManager-iOS/ViewModels/DiskViewModel.swift` (ViewModel pattern)

### 12. **CLAUDE.md Documentation**

Each project includes detailed CLAUDE.md files:
- **ProductivityHub-iOS**: 100% production ready, 14+ features, full iPad/Mac support
- **GmailAI-iOS**: Complex Gmail integration with AI analysis
- **WorkspaceManager-iOS**: Backend API integration pattern example

---

**Summary:** Your iOS projects follow industry best practices with:
- Pure SwiftUI (iOS 17+)
- MVVM/MVVM-inspired architecture
- Singleton pattern for shared state
- Comprehensive error handling
- Zero external dependencies
- Adaptive layouts for all screen sizes
- Production-ready code with 70%+ code reduction from consolidation