Explore the existing iOS apps in ~/Apps/iOS/ to understand the patterns and architecture used. Focus on:

1. Look at TOOL-WorkspaceManager or WorkspaceManager-iOS if it exists - this would be the most similar app
2. Look at any app that connects to a local API server (like the workspace API on port 9004)
3. Understand the common structure: Views, Models, Services, ViewModels
4. Check what networking/API client patterns are used
5. Look for SwiftUI vs UIKit usage

Provide a summary of:
- Project structure pattern
- Networking approach
- UI framework (SwiftUI/UIKit)
- Any reusable components or services


I'll explore the iOS apps in ~/Apps/iOS/ to understand the architecture patterns, focusing on WorkspaceManager-iOS and how apps connect to local API servers.


Bash

List iOS apps directory


total 0
drwxr-xr-x@ 26 neog  staff   832 Dec 30 12:26 .
drwxr-xr-x@  5 neog  staff   160 Dec 29 18:58 ..
drwxr-xr-x@ 18 neog  staff   576 Dec 22 05:21 AI-KeywordMonitor
drwxr-xr-x@ 14 neog  staff   448 Dec 29 18:58 BIZ-BusinessPlan
drwxr-xr-x@  6 neog  staff   192 Dec 15 15:48 BIZ-RevenueFlow30D
drwxr-xr-x@ 18 neog  staff   576 Dec 22 05:21 EDU-17Licoes
drwxr-xr-x@  7 neog  staff   224 Dec 29 18:58 EDU-BibliaEstudo
drwxr-xr-x@  9 neog  staff   288 Dec 29 18:58 EDU-DailyVirtue
drwxr-xr-x@ 14 neog  staff   448 Dec 21 20:52 EMAIL-EmailAnalyzer
drwxr-xr-x@ 23 neog  staff   736 Dec 29 18:58 EMAIL-GmailAI
drwxr-xr-x@ 20 neog  staff   640 Dec 30 01:56 FIN-MeusFIIs
drwxr-xr-x@  7 neog  staff   224 Dec 23 22:52 HEALTH-MassGainer2026
drwxr-xr-x@  7 neog  staff   224 Dec 18 12:53 LOC-AroundMe
drwxr-xr-x@  9 neog  staff   288 Dec 23 05:39 LoanTracker-iOS
drwxr-xr-x@ 11 neog  staff   352 Dec 29 18:58 MEDIA-ObsidianViewer
drwxr-xr-x  12 neog  staff   384 Dec 30 01:41 MEDIA-YouTubeHub
drwxr-xr-x@  7 neog  staff   224 Dec 30 13:03 NetworkMonitor-iOS
drwxr-xr-x@ 17 neog  staff   544 Dec 29 18:58 PROD-96Blocks
drwxr-xr-x@ 61 neog  staff  1952 Dec 21 20:52 PROD-ProductivityHub
drwxr-xr-x@ 12 neog  staff   384 Dec 10 17:18 SOC-NEOGListen
drwxr-xr-x@ 18 neog  staff   576 Dec 21 16:04 TOOL-CleanShield
drwxr-xr-x@  6 neog  staff   192 Dec 10 22:06 TOOL-PaymentGateway
drwxr-xr-x@  5 neog  staff   160 Dec 27 01:34 TOOL-ProxyMonitor
drwxr-xr-x@  5 neog  staff   160 Dec 21 20:52 TOOL-WorkspaceGuide
drwxr-xr-x@ 24 neog  staff   768 Dec 30 00:17 TOOL-WorkspaceManager
drwxr-xr-x@ 13 neog  staff   416 Dec 23 04:29 VectorCRM-iOS


Perfect! I can see TOOL-WorkspaceManager exists. Let me explore the structure of this app and a few others to understand the patterns.


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

List Swift files in WorkspaceManager


Great! Now let me explore the structure more and look at the API client and other apps:


find /Users/neog/Apps/iOS/TOOL-WorkspaceManager -type f -name "*.swift" | wc -l

Count total Swift files


Show directory structure


     1→//
     2→//  WorkspaceAPIClient.swift
     3→//  WorkspaceManager-iOS
     4→//
     5→//  Created on 2025-12-13
     6→//
     7→
     8→import Foundation
     9→
    10→@MainActor
    11→class WorkspaceAPIClient: ObservableObject {
    12→    @Published var isConnected: Bool = false
    13→    @Published var lastError: String?
    14→
    15→    var baseURL: URL
    16→    private let session: URLSession
    17→
    18→    init(baseURL: String = "http://100.75.88.8:9004") {
    19→        self.baseURL = URL(string: baseURL)!
    20→        self.session = URLSession.shared
    21→    }
    22→
    23→    // MARK: - Health Check
    24→    func checkHealth() async throws -> Bool {
    25→        let url = baseURL.appendingPathComponent("/health")
    26→        let (data, response) = try await session.data(from: url)
    27→
    28→        guard let httpResponse = response as? HTTPURLResponse,
    29→              httpResponse.statusCode == 200 else {
    30→            throw APIError.serverError
    31→        }
    32→
    33→        let result = try JSONDecoder().decode(HealthResponse.self, from: data)
    34→        isConnected = result.status == "ok"
    35→        lastError = nil
    36→        return isConnected
    37→    }
    38→
    39→    // MARK: - Disk Operations
    40→    func getDiskOverview() async throws -> [String: DiskInfo] {
    41→        let url = baseURL.appendingPathComponent("/api/disk/overview")
    42→        let (data, _) = try await session.data(from: url)
    43→        let response = try JSONDecoder().decode(DiskUsageResponse.self, from: data)
    44→        lastError = nil
    45→        return response.data
    46→    }
    47→
    48→    func getCacheInfo() async throws -> [String: CacheInfo] {
    49→        let url = baseURL.appendingPathComponent("/api/disk/cache")
    50→        let (data, _) = try await session.data(from: url)
    51→        let response = try JSONDecoder().decode(CacheResponse.self, from: data)
    52→        lastError = nil
    53→        return response.data
    54→    }
    55→
    56→    // MARK: - Cleanup Operations
    57→    func cleanupCache(targets: [String]) async throws -> CleanupResult {
    58→        let url = baseURL.appendingPathComponent("/api/cleanup/cache")
    59→        var request = URLRequest(url: url)
    60→        request.httpMethod = "POST"
    61→        request.setValue("application/json", forHTTPHeaderField: "Content-Type")
    62→
    63→        let body = ["targets": targets]
    64→        request.httpBody = try JSONEncoder().encode(body)
    65→
    66→        let (data, _) = try await session.data(for: request)
    67→        let result = try JSONDecoder().decode(CleanupResult.self, from: data)
    68→        lastError = nil
    69→        return result
    70→    }
    71→
    72→    func runMonthlyCleanup(dryRun: Bool = false) async throws -> CleanupResult {
    73→        let url = baseURL.appendingPathComponent("/api/cleanup/monthly")
    74→        var request = URLRequest(url: url)
    75→        request.httpMethod = "POST"
    76→        request.setValue("application/json", forHTTPHeaderField: "Content-Type")
    77→
    78→        let body = ["dry_run": dryRun]
    79→        request.httpBody = try JSONEncoder().encode(body)
    80→
    81→        let (data, _) = try await session.data(for: request)
    82→        let result = try JSONDecoder().decode(CleanupResult.self, from: data)
    83→        lastError = nil
    84→        return result
    85→    }
    86→
    87→    // MARK: - iCloud Operations
    88→    func getICloudStatus() async throws -> ICloudStatus {
    89→        let url = baseURL.appendingPathComponent("/api/icloud/status")
    90→        let (data, _) = try await session.data(from: url)
    91→        let response = try JSONDecoder().decode(ICloudStatusResponse.self, from: data)
    92→        lastError = nil
    93→        return response.data
    94→    }
    95→
    96→    func getICloudBackups() async throws -> [Backup] {
    97→        let url = baseURL.appendingPathComponent("/api/icloud/backups")
    98→        let (data, _) = try await session.data(from: url)
    99→        let response = try JSONDecoder().decode(BackupsResponse.self, from: data)
   100→        lastError = nil
   101→        return response.data.backups
   102→    }
   103→
   104→    // MARK: - Projects Operations
   105→    func getProjectsOverview() async throws -> ProjectsOverview {
   106→        let url = baseURL.appendingPathComponent("/api/projects/overview")
   107→        let (data, _) = try await session.data(from: url)
   108→        let response = try JSONDecoder().decode(ProjectsResponse.self, from: data)
   109→        lastError = nil
   110→        return response.data
   111→    }
   112→
   113→    // MARK: - Stats
   114→    func getStatsSummary() async throws -> WorkspaceSummary {
   115→        let url = baseURL.appendingPathComponent("/api/stats/summary")
   116→        let (data, _) = try await session.data(from: url)
   117→        let response = try JSONDecoder().decode(SummaryResponse.self, from: data)
   118→        lastError = nil
   119→        return response.data
   120→    }
   121→}
   122→
   123→// MARK: - API Error
   124→enum APIError: LocalizedError {
   125→    case invalidURL
   126→    case serverError
   127→    case decodingError
   128→    case networkUnavailable
   129→
   130→    var errorDescription: String? {
   131→        switch self {
   132→        case .invalidURL: return "URL inválida"
   133→        case .serverError: return "Erro no servidor"
   134→        case .decodingError: return "Erro ao processar dados"
   135→        case .networkUnavailable: return "Sem conexão com o Mac"
   136→        }
   137→    }
   138→}
   139→

<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>

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

import Foundation

@MainActor
class WorkspaceAPIClient: ObservableObject {
    @Published var isConnected: Bool = false
    @Published var lastError: String?

    var baseURL: URL
    private let session: URLSession

    init(baseURL: String = "http://100.75.88.8:9004") {
        self.baseURL = URL(string: baseURL)!
        self.session = URLSession.shared
    }

    // MARK: - Health Check
    func checkHealth() async throws -> Bool {
        let url = baseURL.appendingPathComponent("/health")
        let (data, response) = try await session.data(from: url)

        guard let httpResponse = response as? HTTPURLResponse,
              httpResponse.statusCode == 200 else {
            throw APIError.serverError
        }

        let result = try JSONDecoder().decode(HealthResponse.self, from: data)
        isConnected = result.status == "ok"
        lastError = nil
        return isConnected
    }

    // MARK: - Disk Operations
    func getDiskOverview() async throws -> [String: DiskInfo] {
        let url = baseURL.appendingPathComponent("/api/disk/overview")
        let (data, _) = try await session.data(from: url)
        let response = try JSONDecoder().decode(DiskUsageResponse.self, from: data)
        lastError = nil
        return response.data
    }

    func getCacheInfo() async throws -> [String: CacheInfo] {
        let url = baseURL.appendingPathComponent("/api/disk/cache")
        let (data, _) = try await session.data(from: url)
        let response = try JSONDecoder().decode(CacheResponse.self, from: data)
        lastError = nil
        return response.data
    }

    // MARK: - Cleanup Operations
    func cleanupCache(targets: [String]) async throws -> CleanupResult {
        let url = baseURL.appendingPathComponent("/api/cleanup/cache")
        var request = URLRequest(url: url)
        request.httpMethod = "POST"
        request.setValue("application/json", forHTTPHeaderField: "Content-Type")

        let body = ["targets": targets]
        request.httpBody = try JSONEncoder().encode(body)

        let (data, _) = try await session.data(for: request)
        let result = try JSONDecoder().decode(CleanupResult.self, from: data)
        lastError = nil
        return result
    }

    func runMonthlyCleanup(dryRun: Bool = false) async throws -> CleanupResult {
        let url = baseURL.appendingPathComponent("/api/cleanup/monthly")
        var request = URLRequest(url: url)
        request.httpMethod = "POST"
        request.setValue("application/json", forHTTPHeaderField: "Content-Type")

        let body = ["dry_run": dryRun]
        request.httpBody = try JSONEncoder().encode(body)

        let (data, _) = try await session.data(for: request)
        let result = try JSONDecoder().decode(CleanupResult.self, from: data)
        lastError = nil
        return result
    }

    // MARK: - iCloud Operations
    func getICloudStatus() async throws -> ICloudStatus {
        let url = baseURL.appendingPathComponent("/api/icloud/status")
        let (data, _) = try await session.data(from: url)
        let response = try JSONDecoder().decode(ICloudStatusResponse.self, from: data)
        lastError = nil
        return response.data
    }

    func getICloudBackups() async throws -> [Backup] {
        let url = baseURL.appendingPathComponent("/api/icloud/backups")
        let (data, _) = try await session.data(from: url)
        let response = try JSONDecoder().decode(BackupsResponse.self, from: data)
        lastError = nil
        return response.data.backups
    }

    // MARK: - Projects Operations
    func getProjectsOverview() async throws -> ProjectsOverview {
        let url = baseURL.appendingPathComponent("/api/projects/overview")
        let (data, _) = try await session.data(from: url)
        let response = try JSONDecoder().decode(ProjectsResponse.self, from: data)
        lastError = nil
        return response.data
    }

    // MARK: - Stats
    func getStatsSummary() async throws -> WorkspaceSummary {
        let url = baseURL.appendingPathComponent("/api/stats/summary")
        let (data, _) = try await session.data(from: url)
        let response = try JSONDecoder().decode(SummaryResponse.self, from: data)
        lastError = nil
        return response.data
    }
}

// MARK: - API Error
enum APIError: LocalizedError {
    case invalidURL
    case serverError
    case decodingError
    case networkUnavailable

    var errorDescription: String? {
        switch self {
        case .invalidURL: return "URL inválida"
        case .serverError: return "Erro no servidor"
        case .decodingError: return "Erro ao processar dados"
        case .networkUnavailable: return "Sem conexão com o Mac"
        }
    }
}


     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)")
                        }
                    }
                }
        }
    }
}


total 0
drwxr-xr-x@  9 neog  staff  288 Dec 30 00:18 .
drwxr-xr-x@ 24 neog  staff  768 Dec 30 00:17 ..
drwxr-xr-x@  4 neog  staff  128 Dec 30 00:18 App
drwxr-xr-x@  4 neog  staff  128 Dec 13 14:58 Assets.xcassets
drwxr-xr-x@  6 neog  staff  192 Dec 13 14:07 Components
drwxr-xr-x@  6 neog  staff  192 Dec 13 14:00 Models
drwxr-xr-x@  4 neog  staff  128 Dec 13 14:10 Services
drwxr-xr-x@  6 neog  staff  192 Dec 13 15:07 ViewModels
drwxr-xr-x@  7 neog  staff  224 Dec 13 13:59 Views


Excellent! Now let me look at a couple of other apps to understand the patterns better:


find /Users/neog/Apps/iOS/PROD-ProductivityHub -type f -name "*.swift" | head -15

List Swift files in ProductivityHub


     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→//  DiskUsage.swift
     3→//  WorkspaceManager-iOS
     4→//
     5→//  Created on 2025-12-13
     6→//
     7→
     8→import Foundation
     9→
    10→// MARK: - Disk Usage Response
    11→struct DiskUsageResponse: Codable {
    12→    let status: String
    13→    let timestamp: String
    14→    let data: [String: DiskInfo]
    15→}
    16→
    17→// MARK: - Disk Info
    18→struct DiskInfo: Codable {
    19→    let path: String
    20→    let sizeBytes: Int64
    21→    let sizeHuman: String
    22→    let exists: Bool
    23→
    24→    enum CodingKeys: String, CodingKey {
    25→        case path
    26→        case sizeBytes = "size_bytes"
    27→        case sizeHuman = "size_human"
    28→        case exists
    29→    }
    30→}
    31→
    32→// MARK: - Cache Response
    33→struct CacheResponse: Codable {
    34→    let status: String
    35→    let timestamp: String
    36→    let data: [String: CacheInfo]
    37→}
    38→
    39→// MARK: - Cache Info
    40→struct CacheInfo: Codable {
    41→    let path: String
    42→    let sizeBytes: Int64
    43→    let sizeHuman: String
    44→    let canDelete: Bool
    45→
    46→    enum CodingKeys: String, CodingKey {
    47→        case path
    48→        case sizeBytes = "size_bytes"
    49→        case sizeHuman = "size_human"
    50→        case canDelete = "can_delete"
    51→    }
    52→}
    53→

<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>

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

import Foundation

// MARK: - Disk Usage Response
struct DiskUsageResponse: Codable {
    let status: String
    let timestamp: String
    let data: [String: DiskInfo]
}

// MARK: - Disk Info
struct DiskInfo: Codable {
    let path: String
    let sizeBytes: Int64
    let sizeHuman: String
    let exists: Bool

    enum CodingKeys: String, CodingKey {
        case path
        case sizeBytes = "size_bytes"
        case sizeHuman = "size_human"
        case exists
    }
}

// MARK: - Cache Response
struct CacheResponse: Codable {
    let status: String
    let timestamp: String
    let data: [String: CacheInfo]
}

// MARK: - Cache Info
struct CacheInfo: Codable {
    let path: String
    let sizeBytes: Int64
    let sizeHuman: String
    let canDelete: Bool

    enum CodingKeys: String, CodingKey {
        case path
        case sizeBytes = "size_bytes"
        case sizeHuman = "size_human"
        case canDelete = "can_delete"
    }
}


Let me look at the ProductivityHub structure and check more ViewModels:


find /Users/neog/Apps/iOS/PROD-ProductivityHub -type d | head -20

Show directory structure of ProductivityHub


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

<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 habits = "Habits"
    case journal = "Journal"
    case progress = "Progress"
    case settings = "Settings"

    var id: String { rawValue }

    var icon: String {
        switch self {
        case .focus: return "timer"
        case .tasks: return "checklist"
        case .habits: return "repeat.circle.fill"
        case .journal: return "book.fill"
        case .progress: 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 .habits: return "Track daily habits"
        case .journal: return "Daily reflections"
        case .progress: return "XP, levels & badges"
        case .settings: return "App preferences"
        }
    }

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

// 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)

            HabitsView()
                .tabItem { Label("Habits", systemImage: "repeat.circle.fill") }
                .tag(2)

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

            ProgressHubView()
                .tabItem { Label("Progress", systemImage: "chart.bar.fill") }
                .tag(4)

            SettingsView()
                .tabItem { Label("Settings", systemImage: "gearshape.fill") }
                .tag(5)
        }
        .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 .habits:
            HabitsView()
        case .journal:
            JournalView()
        case .progress:
            ProgressHubView()
        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)
            Button("") { selectedTab = 5 }
                .keyboardShortcut("6", 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→//
     2→//  CleanupViewModel.swift
     3→//  WorkspaceManager-iOS
     4→//
     5→//  Created on 2025-12-13
     6→//
     7→
     8→import Foundation
     9→
    10→@MainActor
    11→class CleanupViewModel: ObservableObject {
    12→    @Published var lastCleanupResult: CleanupResult?
    13→    @Published var isRunning = false
    14→    @Published var errorMessage: String?
    15→
    16→    var apiClient: WorkspaceAPIClient?
    17→
    18→    init(apiClient: WorkspaceAPIClient? = nil) {
    19→        self.apiClient = apiClient
    20→    }
    21→
    22→    func cleanupCache(targets: [String]) async {
    23→        guard let apiClient = apiClient else {
    24→            errorMessage = "API client not configured"
    25→            return
    26→        }
    27→
    28→        isRunning = true
    29→        errorMessage = nil
    30→
    31→        do {
    32→            lastCleanupResult = try await apiClient.cleanupCache(targets: targets)
    33→        } catch {
    34→            errorMessage = error.localizedDescription
    35→        }
    36→
    37→        isRunning = false
    38→    }
    39→
    40→    func runMonthlyCleanup(dryRun: Bool = false) async {
    41→        guard let apiClient = apiClient else {
    42→            errorMessage = "API client not configured"
    43→            return
    44→        }
    45→
    46→        isRunning = true
    47→        errorMessage = nil
    48→
    49→        do {
    50→            lastCleanupResult = try await apiClient.runMonthlyCleanup(dryRun: dryRun)
    51→        } catch {
    52→            errorMessage = error.localizedDescription
    53→        }
    54→
    55→        isRunning = false
    56→    }
    57→
    58→    var totalFreed: String {
    59→        lastCleanupResult?.totalFreedHuman ?? "0 B"
    60→    }
    61→
    62→    var wasSuccessful: Bool {
    63→        lastCleanupResult?.status == "ok"
    64→    }
    65→}
    66→

<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>

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

import Foundation

@MainActor
class CleanupViewModel: ObservableObject {
    @Published var lastCleanupResult: CleanupResult?
    @Published var isRunning = false
    @Published var errorMessage: String?

    var apiClient: WorkspaceAPIClient?

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

    func cleanupCache(targets: [String]) async {
        guard let apiClient = apiClient else {
            errorMessage = "API client not configured"
            return
        }

        isRunning = true
        errorMessage = nil

        do {
            lastCleanupResult = try await apiClient.cleanupCache(targets: targets)
        } catch {
            errorMessage = error.localizedDescription
        }

        isRunning = false
    }

    func runMonthlyCleanup(dryRun: Bool = false) async {
        guard let apiClient = apiClient else {
            errorMessage = "API client not configured"
            return
        }

        isRunning = true
        errorMessage = nil

        do {
            lastCleanupResult = try await apiClient.runMonthlyCleanup(dryRun: dryRun)
        } catch {
            errorMessage = error.localizedDescription
        }

        isRunning = false
    }

    var totalFreed: String {
        lastCleanupResult?.totalFreedHuman ?? "0 B"
    }

    var wasSuccessful: Bool {
        lastCleanupResult?.status == "ok"
    }
}


Now let me check a few more files to understand the complete patterns:


find /Users/neog/Apps/iOS/TOOL-WorkspaceManager/WorkspaceManager-iOS/Views -type f -name "*.swift" | head -10

List View files


     1→//
     2→//  SettingsManager.swift
     3→//  WorkspaceManager-iOS
     4→//
     5→//  Created on 2025-12-13
     6→//
     7→
     8→import Foundation
     9→
    10→@MainActor
    11→class SettingsManager: ObservableObject {
    12→    @Published var serverURL: String {
    13→        didSet { UserDefaults.standard.set(serverURL, forKey: "serverURL") }
    14→    }
    15→
    16→    @Published var autoRefresh: Bool {
    17→        didSet { UserDefaults.standard.set(autoRefresh, forKey: "autoRefresh") }
    18→    }
    19→
    20→    @Published var refreshInterval: TimeInterval {
    21→        didSet { UserDefaults.standard.set(refreshInterval, forKey: "refreshInterval") }
    22→    }
    23→
    24→    init() {
    25→        self.serverURL = UserDefaults.standard.string(forKey: "serverURL") ?? "http://100.75.88.8:9004"
    26→        self.autoRefresh = UserDefaults.standard.bool(forKey: "autoRefresh")
    27→        self.refreshInterval = UserDefaults.standard.double(forKey: "refreshInterval") == 0 ? 60 : UserDefaults.standard.double(forKey: "refreshInterval")
    28→    }
    29→
    30→    func resetToDefaults() {
    31→        serverURL = "http://100.75.88.8:9004"
    32→        autoRefresh = false
    33→        refreshInterval = 60
    34→    }
    35→}
    36→

<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>

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

import Foundation

@MainActor
class SettingsManager: ObservableObject {
    @Published var serverURL: String {
        didSet { UserDefaults.standard.set(serverURL, forKey: "serverURL") }
    }

    @Published var autoRefresh: Bool {
        didSet { UserDefaults.standard.set(autoRefresh, forKey: "autoRefresh") }
    }

    @Published var refreshInterval: TimeInterval {
        didSet { UserDefaults.standard.set(refreshInterval, forKey: "refreshInterval") }
    }

    init() {
        self.serverURL = UserDefaults.standard.string(forKey: "serverURL") ?? "http://100.75.88.8:9004"
        self.autoRefresh = UserDefaults.standard.bool(forKey: "autoRefresh")
        self.refreshInterval = UserDefaults.standard.double(forKey: "refreshInterval") == 0 ? 60 : UserDefaults.standard.double(forKey: "refreshInterval")
    }

    func resetToDefaults() {
        serverURL = "http://100.75.88.8:9004"
        autoRefresh = false
        refreshInterval = 60
    }
}


     1→//
     2→//  Project.swift
     3→//  WorkspaceManager-iOS
     4→//
     5→//  Created on 2025-12-13
     6→//
     7→
     8→import Foundation
     9→
    10→// MARK: - Projects Response
    11→struct ProjectsResponse: Codable {
    12→    let status: String
    13→    let timestamp: String
    14→    let data: ProjectsOverview
    15→}
    16→
    17→// MARK: - Projects Overview
    18→struct ProjectsOverview: Codable {
    19→    let core: ProjectCategory?
    20→    let tools: ProjectCategory?
    21→    let experiments: ProjectCategory?
    22→}
    23→
    24→// MARK: - Project Category
    25→struct ProjectCategory: Codable {
    26→    let projects: [Project]
    27→    let count: Int
    28→}
    29→
    30→// MARK: - Project
    31→struct Project: Codable, Identifiable {
    32→    var id: String { name }
    33→    let name: String
    34→    let path: String
    35→    let sizeBytes: Int64
    36→    let sizeHuman: String
    37→    let modified: String
    38→    let hasGit: Bool
    39→    let hasPackageJson: Bool
    40→    let hasRequirements: Bool
    41→
    42→    enum CodingKeys: String, CodingKey {
    43→        case name, path
    44→        case sizeBytes = "size_bytes"
    45→        case sizeHuman = "size_human"
    46→        case modified
    47→        case hasGit = "has_git"
    48→        case hasPackageJson = "has_package_json"
    49→        case hasRequirements = "has_requirements"
    50→    }
    51→}
    52→

<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>

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

import Foundation

// MARK: - Projects Response
struct ProjectsResponse: Codable {
    let status: String
    let timestamp: String
    let data: ProjectsOverview
}

// MARK: - Projects Overview
struct ProjectsOverview: Codable {
    let core: ProjectCategory?
    let tools: ProjectCategory?
    let experiments: ProjectCategory?
}

// MARK: - Project Category
struct ProjectCategory: Codable {
    let projects: [Project]
    let count: Int
}

// MARK: - Project
struct Project: Codable, Identifiable {
    var id: String { name }
    let name: String
    let path: String
    let sizeBytes: Int64
    let sizeHuman: String
    let modified: String
    let hasGit: Bool
    let hasPackageJson: Bool
    let hasRequirements: Bool

    enum CodingKeys: String, CodingKey {
        case name, path
        case sizeBytes = "size_bytes"
        case sizeHuman = "size_human"
        case modified
        case hasGit = "has_git"
        case hasPackageJson = "has_package_json"
        case hasRequirements = "has_requirements"
    }
}


Let me check one sample view and some model files:


     1→//
     2→//  DiskView.swift
     3→//  WorkspaceManager-iOS
     4→//
     5→//  Created on 2025-12-13
     6→//
     7→
     8→import SwiftUI
     9→
    10→struct DiskView: View {
    11→    @EnvironmentObject var apiClient: WorkspaceAPIClient
    12→    @StateObject private var viewModel = DiskViewModel()
    13→
    14→    var body: some View {
    15→        NavigationStack {
    16→            ScrollView {
    17→                VStack(spacing: 20) {
    18→                    // Header Card - Total Size
    19→                    if !viewModel.isLoading {
    20→                        StorageCard(
    21→                            title: "Armazenamento Total",
    22→                            value: viewModel.totalSize,
    23→                            icon: "internaldrive.fill",
    24→                            color: .blue
    25→                        )
    26→                    }
    27→
    28→                    // Directories Section
    29→                    if !viewModel.diskUsage.isEmpty {
    30→                        VStack(alignment: .leading, spacing: 12) {
    31→                            Text("Diretórios")
    32→                                .font(.headline)
    33→                                .foregroundStyle(.secondary)
    34→                                .padding(.horizontal)
    35→
    36→                            VStack(spacing: 8) {
    37→                                ForEach(viewModel.sortedDirectories, id: \.key) { key, info in
    38→                                    DirectoryRow(name: key, info: info)
    39→                                }
    40→                            }
    41→                        }
    42→                    }
    43→
    44→                    // Cache Section
    45→                    if !viewModel.cacheInfo.isEmpty {
    46→                        VStack(alignment: .leading, spacing: 12) {
    47→                            HStack {
    48→                                Text("Cache e Build Artifacts")
    49→                                    .font(.headline)
    50→                                    .foregroundStyle(.secondary)
    51→
    52→                                Spacer()
    53→
    54→                                Text(ByteCountFormatter.string(fromByteCount: viewModel.totalCacheSize, countStyle: .file))
    55→                                    .font(.subheadline.bold())
    56→                                    .foregroundStyle(.orange)
    57→                            }
    58→                            .padding(.horizontal)
    59→
    60→                            VStack(spacing: 8) {
    61→                                ForEach(viewModel.sortedCache, id: \.key) { key, cache in
    62→                                    CacheRow(name: key, info: cache)
    63→                                }
    64→                            }
    65→                        }
    66→                    }
    67→
    68→                    // Error Message
    69→                    if let error = viewModel.errorMessage {
    70→                        Text("Erro: \(error)")
    71→                            .font(.caption)
    72→                            .foregroundStyle(.red)
    73→                            .padding()
    74→                    }
    75→                }
    76→                .padding()
    77→            }
    78→            .navigationTitle("Disco")
    79→            .toolbar {
    80→                ToolbarItem(placement: .topBarTrailing) {
    81→                    if viewModel.isLoading {
    82→                        ProgressView()
    83→                    }
    84→                }
    85→            }
    86→            .refreshable {
    87→                await viewModel.loadData()
    88→            }
    89→            .task {
    90→                viewModel.apiClient = apiClient
    91→                await viewModel.loadData()
    92→            }
    93→        }
    94→    }
    95→}
    96→
    97→// MARK: - Directory Row
    98→struct DirectoryRow: View {
    99→    let name: String
   100→    let info: DiskInfo
   101→
   102→    var body: some View {
   103→        HStack(spacing: 12) {
   104→            Image(systemName: iconForDirectory(name))
   105→                .font(.title2)
   106→                .foregroundStyle(colorForDirectory(name))
   107→                .frame(width: 40)
   108→
   109→            VStack(alignment: .leading, spacing: 2) {
   110→                Text(name.capitalized)
   111→                    .font(.subheadline.bold())
   112→
   113→                Text(info.path)
   114→                    .font(.caption)
   115→                    .foregroundStyle(.secondary)
   116→                    .lineLimit(1)
   117→            }
   118→
   119→            Spacer()
   120→
   121→            VStack(alignment: .trailing, spacing: 2) {
   122→                Text(info.sizeHuman)
   123→                    .font(.subheadline.bold())
   124→
   125→                if !info.exists {
   126→                    Text("Não existe")
   127→                        .font(.caption)
   128→                        .foregroundStyle(.red)
   129→                }
   130→            }
   131→        }
   132→        .padding()
   133→        .background(.ultraThinMaterial, in: RoundedRectangle(cornerRadius: 12))
   134→    }
   135→
   136→    private func iconForDirectory(_ name: String) -> String {
   137→        switch name.lowercased() {
   138→        case "apps": return "app.fill"
   139→        case "web": return "globe"
   140→        case "projects": return "folder.fill"
   141→        case "services": return "server.rack"
   142→        case "scripts": return "terminal.fill"
   143→        case "archive": return "archivebox.fill"
   144→        default: return "folder"
   145→        }
   146→    }
   147→
   148→    private func colorForDirectory(_ name: String) -> Color {
   149→        switch name.lowercased() {
   150→        case "apps": return .purple
   151→        case "web": return .blue
   152→        case "projects": return .orange
   153→        case "services": return .green
   154→        case "scripts": return .pink
   155→        case "archive": return .gray
   156→        default: return .blue
   157→        }
   158→    }
   159→}
   160→
   161→// MARK: - Cache Row
   162→struct CacheRow: View {
   163→    let name: String
   164→    let info: CacheInfo
   165→
   166→    var body: some View {
   167→        HStack(spacing: 12) {
   168→            Image(systemName: "doc.fill")
   169→                .font(.title3)
   170→                .foregroundStyle(.orange)
   171→                .frame(width: 30)
   172→
   173→            VStack(alignment: .leading, spacing: 2) {
   174→                Text(formatCacheName(name))
   175→                    .font(.subheadline)
   176→
   177→                Text(info.path)
   178→                    .font(.caption)
   179→                    .foregroundStyle(.secondary)
   180→                    .lineLimit(1)
   181→            }
   182→
   183→            Spacer()
   184→
   185→            Text(info.sizeHuman)
   186→                .font(.subheadline.bold())
   187→                .foregroundStyle(.orange)
   188→        }
   189→        .padding()
   190→        .background(.orange.opacity(0.1), in: RoundedRectangle(cornerRadius: 12))
   191→    }
   192→
   193→    private func formatCacheName(_ name: String) -> String {
   194→        name.replacingOccurrences(of: "_", with: " ")
   195→            .capitalized
   196→    }
   197→}
   198→
   199→#Preview {
   200→    DiskView()
   201→        .environmentObject(WorkspaceAPIClient())
   202→        .environmentObject(SettingsManager())
   203→}
   204→

<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>

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

import SwiftUI

struct DiskView: View {
    @EnvironmentObject var apiClient: WorkspaceAPIClient
    @StateObject private var viewModel = DiskViewModel()

    var body: some View {
        NavigationStack {
            ScrollView {
                VStack(spacing: 20) {
                    // Header Card - Total Size
                    if !viewModel.isLoading {
                        StorageCard(
                            title: "Armazenamento Total",
                            value: viewModel.totalSize,
                            icon: "internaldrive.fill",
                            color: .blue
                        )
                    }

                    // Directories Section
                    if !viewModel.diskUsage.isEmpty {
                        VStack(alignment: .leading, spacing: 12) {
                            Text("Diretórios")
                                .font(.headline)
                                .foregroundStyle(.secondary)
                                .padding(.horizontal)

                            VStack(spacing: 8) {
                                ForEach(viewModel.sortedDirectories, id: \.key) { key, info in
                                    DirectoryRow(name: key, info: info)
                                }
                            }
                        }
                    }

                    // Cache Section
                    if !viewModel.cacheInfo.isEmpty {
                        VStack(alignment: .leading, spacing: 12) {
                            HStack {
                                Text("Cache e Build Artifacts")
                                    .font(.headline)
                                    .foregroundStyle(.secondary)

                                Spacer()

                                Text(ByteCountFormatter.string(fromByteCount: viewModel.totalCacheSize, countStyle: .file))
                                    .font(.subheadline.bold())
                                    .foregroundStyle(.orange)
                            }
                            .padding(.horizontal)

                            VStack(spacing: 8) {
                                ForEach(viewModel.sortedCache, id: \.key) { key, cache in
                                    CacheRow(name: key, info: cache)
                                }
                            }
                        }
                    }

                    // Error Message
                    if let error = viewModel.errorMessage {
                        Text("Erro: \(error)")
                            .font(.caption)
                            .foregroundStyle(.red)
                            .padding()
                    }
                }
                .padding()
            }
            .navigationTitle("Disco")
            .toolbar {
                ToolbarItem(placement: .topBarTrailing) {
                    if viewModel.isLoading {
                        ProgressView()
                    }
                }
            }
            .refreshable {
                await viewModel.loadData()
            }
            .task {
                viewModel.apiClient = apiClient
                await viewModel.loadData()
            }
        }
    }
}

// MARK: - Directory Row
struct DirectoryRow: View {
    let name: String
    let info: DiskInfo

    var body: some View {
        HStack(spacing: 12) {
            Image(systemName: iconForDirectory(name))
                .font(.title2)
                .foregroundStyle(colorForDirectory(name))
                .frame(width: 40)

            VStack(alignment: .leading, spacing: 2) {
                Text(name.capitalized)
                    .font(.subheadline.bold())

                Text(info.path)
                    .font(.caption)
                    .foregroundStyle(.secondary)
                    .lineLimit(1)
            }

            Spacer()

            VStack(alignment: .trailing, spacing: 2) {
                Text(info.sizeHuman)
                    .font(.subheadline.bold())

                if !info.exists {
                    Text("Não existe")
                        .font(.caption)
                        .foregroundStyle(.red)
                }
            }
        }
        .padding()
        .background(.ultraThinMaterial, in: RoundedRectangle(cornerRadius: 12))
    }

    private func iconForDirectory(_ name: String) -> String {
        switch name.lowercased() {
        case "apps": return "app.fill"
        case "web": return "globe"
        case "projects": return "folder.fill"
        case "services": return "server.rack"
        case "scripts": return "terminal.fill"
        case "archive": return "archivebox.fill"
        default: return "folder"
        }
    }

    private func colorForDirectory(_ name: String) -> Color {
        switch name.lowercased() {
        case "apps": return .purple
        case "web": return .blue
        case "projects": return .orange
        case "services": return .green
        case "scripts": return .pink
        case "archive": return .gray
        default: return .blue
        }
    }
}

// MARK: - Cache Row
struct CacheRow: View {
    let name: String
    let info: CacheInfo

    var body: some View {
        HStack(spacing: 12) {
            Image(systemName: "doc.fill")
                .font(.title3)
                .foregroundStyle(.orange)
                .frame(width: 30)

            VStack(alignment: .leading, spacing: 2) {
                Text(formatCacheName(name))
                    .font(.subheadline)

                Text(info.path)
                    .font(.caption)
                    .foregroundStyle(.secondary)
                    .lineLimit(1)
            }

            Spacer()

            Text(info.sizeHuman)
                .font(.subheadline.bold())
                .foregroundStyle(.orange)
        }
        .padding()
        .background(.orange.opacity(0.1), in: RoundedRectangle(cornerRadius: 12))
    }

    private func formatCacheName(_ name: String) -> String {
        name.replacingOccurrences(of: "_", with: " ")
            .capitalized
    }
}

#Preview {
    DiskView()
        .environmentObject(WorkspaceAPIClient())
        .environmentObject(SettingsManager())
}


     1→//
     2→//  Backup.swift
     3→//  WorkspaceManager-iOS
     4→//
     5→//  Created on 2025-12-13
     6→//
     7→
     8→import Foundation
     9→
    10→// MARK: - Backups Response
    11→struct BackupsResponse: Codable {
    12→    let status: String
    13→    let timestamp: String
    14→    let data: BackupsData
    15→}
    16→
    17→// MARK: - Backups Data
    18→struct BackupsData: Codable {
    19→    let backups: [Backup]
    20→    let total: Int
    21→}
    22→
    23→// MARK: - Backup
    24→struct Backup: Codable, Identifiable {
    25→    var id: String { name }
    26→    let name: String
    27→    let path: String
    28→    let sizeBytes: Int64
    29→    let sizeHuman: String
    30→    let modified: String
    31→
    32→    enum CodingKeys: String, CodingKey {
    33→        case name, path
    34→        case sizeBytes = "size_bytes"
    35→        case sizeHuman = "size_human"
    36→        case modified
    37→    }
    38→}
    39→
    40→// MARK: - iCloud Status Response
    41→struct ICloudStatusResponse: Codable {
    42→    let status: String
    43→    let timestamp: String
    44→    let data: ICloudStatus
    45→}
    46→
    47→// MARK: - iCloud Status
    48→struct ICloudStatus: Codable {
    49→    let accountId: String?
    50→    let syncActive: Bool
    51→    let icloudPath: String
    52→    let backupsPath: String
    53→    let backupsSizeBytes: Int64
    54→    let backupsSizeHuman: String
    55→
    56→    enum CodingKeys: String, CodingKey {
    57→        case accountId = "account_id"
    58→        case syncActive = "sync_active"
    59→        case icloudPath = "icloud_path"
    60→        case backupsPath = "backups_path"
    61→        case backupsSizeBytes = "backups_size_bytes"
    62→        case backupsSizeHuman = "backups_size_human"
    63→    }
    64→}
    65→

<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>

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

import Foundation

// MARK: - Backups Response
struct BackupsResponse: Codable {
    let status: String
    let timestamp: String
    let data: BackupsData
}

// MARK: - Backups Data
struct BackupsData: Codable {
    let backups: [Backup]
    let total: Int
}

// MARK: - Backup
struct Backup: Codable, Identifiable {
    var id: String { name }
    let name: String
    let path: String
    let sizeBytes: Int64
    let sizeHuman: String
    let modified: String

    enum CodingKeys: String, CodingKey {
        case name, path
        case sizeBytes = "size_bytes"
        case sizeHuman = "size_human"
        case modified
    }
}

// MARK: - iCloud Status Response
struct ICloudStatusResponse: Codable {
    let status: String
    let timestamp: String
    let data: ICloudStatus
}

// MARK: - iCloud Status
struct ICloudStatus: Codable {
    let accountId: String?
    let syncActive: Bool
    let icloudPath: String
    let backupsPath: String
    let backupsSizeBytes: Int64
    let backupsSizeHuman: String

    enum CodingKeys: String, CodingKey {
        case accountId = "account_id"
        case syncActive = "sync_active"
        case icloudPath = "icloud_path"
        case backupsPath = "backups_path"
        case backupsSizeBytes = "backups_size_bytes"
        case backupsSizeHuman = "backups_size_human"
    }
}


     1→//
     2→//  StorageCard.swift
     3→//  WorkspaceManager-iOS
     4→//
     5→//  Created on 2025-12-13
     6→//
     7→
     8→import SwiftUI
     9→
    10→struct StorageCard: View {
    11→    let title: String
    12→    let value: Int64
    13→    let icon: String
    14→    let color: Color
    15→
    16→    var body: some View {
    17→        HStack(spacing: 16) {
    18→            Image(systemName: icon)
    19→                .font(.system(size: 40))
    20→                .foregroundStyle(color)
    21→                .frame(width: 60)
    22→
    23→            VStack(alignment: .leading, spacing: 4) {
    24→                Text(title)
    25→                    .font(.subheadline)
    26→                    .foregroundStyle(.secondary)
    27→
    28→                Text(formatBytes(value))
    29→                    .font(.title2.bold())
    30→            }
    31→
    32→            Spacer()
    33→        }
    34→        .padding()
    35→        .background(.ultraThinMaterial, in: RoundedRectangle(cornerRadius: 16))
    36→    }
    37→
    38→    private func formatBytes(_ bytes: Int64) -> String {
    39→        ByteCountFormatter.string(fromByteCount: bytes, countStyle: .file)
    40→    }
    41→}
    42→
    43→#Preview {
    44→    StorageCard(
    45→        title: "Armazenamento Total",
    46→        value: 450000000,
    47→        icon: "internaldrive.fill",
    48→        color: .blue
    49→    )
    50→    .padding()
    51→}
    52→

<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>

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

import SwiftUI

struct StorageCard: View {
    let title: String
    let value: Int64
    let icon: String
    let color: Color

    var body: some View {
        HStack(spacing: 16) {
            Image(systemName: icon)
                .font(.system(size: 40))
                .foregroundStyle(color)
                .frame(width: 60)

            VStack(alignment: .leading, spacing: 4) {
                Text(title)
                    .font(.subheadline)
                    .foregroundStyle(.secondary)

                Text(formatBytes(value))
                    .font(.title2.bold())
            }

            Spacer()
        }
        .padding()
        .background(.ultraThinMaterial, in: RoundedRectangle(cornerRadius: 16))
    }

    private func formatBytes(_ bytes: Int64) -> String {
        ByteCountFormatter.string(fromByteCount: bytes, countStyle: .file)
    }
}

#Preview {
    StorageCard(
        title: "Armazenamento Total",
        value: 450000000,
        icon: "internaldrive.fill",
        color: .blue
    )
    .padding()
}


Perfect! Now let me check a few more patterns from other apps:


find /Users/neog/Apps/iOS/PROD-ProductivityHub -type f -name "DataManager.swift"

Find ProductivityHub DataManager


Show start of ProductivityHub DataManager


     1→//
     2→//  BackupsViewModel.swift
     3→//  WorkspaceManager-iOS
     4→//
     5→//  Created on 2025-12-13
     6→//
     7→
     8→import Foundation
     9→
    10→@MainActor
    11→class BackupsViewModel: ObservableObject {
    12→    @Published var backups: [Backup] = []
    13→    @Published var icloudStatus: ICloudStatus?
    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 backupsData = apiClient.getICloudBackups()
    34→            async let statusData = apiClient.getICloudStatus()
    35→
    36→            (backups, icloudStatus) = try await (backupsData, statusData)
    37→        } catch {
    38→            errorMessage = error.localizedDescription
    39→        }
    40→
    41→        isLoading = false
    42→    }
    43→
    44→    var sortedBackups: [Backup] {
    45→        backups.sorted { $0.modified > $1.modified }
    46→    }
    47→
    48→    var totalBackupSize: Int64 {
    49→        backups.reduce(0) { $0 + $1.sizeBytes }
    50→    }
    51→
    52→    var isSyncActive: Bool {
    53→        icloudStatus?.syncActive ?? false
    54→    }
    55→}
    56→

<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>

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

import Foundation

@MainActor
class BackupsViewModel: ObservableObject {
    @Published var backups: [Backup] = []
    @Published var icloudStatus: ICloudStatus?
    @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 backupsData = apiClient.getICloudBackups()
            async let statusData = apiClient.getICloudStatus()

            (backups, icloudStatus) = try await (backupsData, statusData)
        } catch {
            errorMessage = error.localizedDescription
        }

        isLoading = false
    }

    var sortedBackups: [Backup] {
        backups.sorted { $0.modified > $1.modified }
    }

    var totalBackupSize: Int64 {
        backups.reduce(0) { $0 + $1.sizeBytes }
    }

    var isSyncActive: Bool {
        icloudStatus?.syncActive ?? false
    }
}


//
//  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] = []

    // Consolidated features from Planner2026 and HabitTracker2026
    @Published var habits: [Habit] = []
    @Published var morningRituals: [MorningRitualDay] = []
    @Published var yearlyGoals: [YearlyGoal] = []

    // 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"


Perfect! I have enough information. Let me create a comprehensive summary report:

## iOS Apps Architecture Summary

Based on my exploration of **TOOL-WorkspaceManager-iOS** and **PROD-ProductivityHub-iOS**, here's a comprehensive analysis of the patterns and architecture used in your iOS applications:

---

## **Project Structure Pattern**

### WorkspaceManager-iOS (API-Connected Template)
```
WorkspaceManager-iOS/
├── App/
│   ├── WorkspaceManagerApp.swift      # @main entry point
│   └── MainTabView.swift              # Tab navigation
├── Models/                            # Codable data structures
│   ├── DiskUsage.swift
│   ├── Project.swift
│   ├── Backup.swift
│   └── CleanupResult.swift
├── Services/                          # Business logic layer
│   ├── WorkspaceAPIClient.swift       # API communication
│   └── SettingsManager.swift          # Settings persistence
├── ViewModels/                        # MVVM state management
│   ├── DiskViewModel.swift
│   ├── CleanupViewModel.swift
│   ├── BackupsViewModel.swift
│   └── ProjectsViewModel.swift
├── Views/                             # SwiftUI screens
│   ├── Disk/DiskView.swift
│   ├── Cleanup/CleanupView.swift
│   ├── Backups/BackupsView.swift
│   ├── Projects/ProjectsView.swift
│   └── Settings/SettingsView.swift
├── Components/                        # Reusable UI
│   ├── StorageCard.swift
│   ├── ProgressRing.swift
│   ├── StatRow.swift
│   └── ToastView.swift
└── Assets.xcassets/
```

### ProductivityHub-iOS (Local-First with Complex Features)
```
PROD-ProductivityHub/
├── App/
│   └── MainTabView.swift              # Adaptive nav (iPhone/iPad)
├── Features/                          # Feature-based organization
│   ├── Focus/FocusView.swift
│   ├── Tasks/TasksView.swift
│   ├── Journal/JournalView.swift
│   ├── Insights/InsightsView.swift
│   └── Settings/SettingsView.swift
├── Models/SharedModels.swift          # Unified data models
├── Services/
│   ├── DataManager.swift              # Singleton data + persistence
│   ├── TimerService.swift
│   ├── NotificationService.swift
│   └── ExportService.swift
├── Components/                        # Reusable UI components
│   ├── OnboardingTip.swift
│   └── ToastView.swift
├── HapticManager.swift                # Haptic feedback handler
└── Assets.xcassets/
```

---

## **Networking Approach**

### WorkspaceManager (Remote API Pattern)

**API Client Pattern:**
- **Class:** `WorkspaceAPIClient` (ObservableObject with @MainActor)
- **Session:** `URLSession.shared` with async/await
- **Base URL:** `http://100.75.88.8:9004` (Tailscale IP)
- **Error Handling:** Custom `APIError` enum with localized descriptions

**Example Methods:**
```swift
@MainActor
class WorkspaceAPIClient: ObservableObject {
    @Published var isConnected: Bool
    @Published var lastError: String?

    func getDiskOverview() async throws -> [String: DiskInfo]
    func cleanupCache(targets: [String]) async throws -> CleanupResult
    func getICloudBackups() async throws -> [Backup]
}
```

**Async/Await Pattern:**
- All API calls use `async/await` (not Combine)
- Multiple concurrent requests: `async let` syntax
- Main thread execution via `@MainActor`

### ProductivityHub (Local-First Pattern)

**Data Persistence:**
- **Storage:** UserDefaults with 3-layer backup system
- **Primary key:** `ProductivityHub_Tasks`
- **Backup 1/2 keys:** For corruption recovery
- **Cascade recovery:** Try primary → backup1 → backup2

**Data Validation:**
```swift
// Verify data can be decoded before saving
guard let encoded = try? JSONEncoder().encode(data) else { return }
guard (try? JSONDecoder().decode(type(of: data).self, from: encoded)) != nil else { return }
```

**Singleton DataManager:**
- Single source of truth for all data
- `@MainActor` for thread safety
- Debounced saves (500ms to prevent excessive disk writes)

---

## **UI Framework**

### SwiftUI (100% - Both Apps)

**Key Points:**
- iOS 17+ minimum deployment
- No UIKit (except HapticManager which uses UIImpactFeedbackGenerator)
- **ObservableObject** for view models
- **@Published** properties for state
- **@EnvironmentObject** for dependency injection
- **#Preview** for UI testing

### Adaptive Navigation

**WorkspaceManager:** TabView navigation (5 tabs)

**ProductivityHub:** Adaptive based on device size
```swift
if horizontalSizeClass == .regular {
    // iPad/Mac: NavigationSplitView with sidebar
    iPadNavigationView
} else {
    // iPhone: Traditional TabView
    iPhoneTabView
}
```

---

## **Common Architecture Patterns**

### 1. **MVVM Pattern**

**View Layer:**
```swift
struct DiskView: View {
    @EnvironmentObject var apiClient: WorkspaceAPIClient
    @StateObject private var viewModel = DiskViewModel()

    var body: some View { ... }
}
```

**ViewModel Layer:**
```swift
@MainActor
class DiskViewModel: ObservableObject {
    @Published var diskUsage: [String: DiskInfo] = [:]
    @Published var isLoading = false
    @Published var errorMessage: String?

    func loadData() async { ... }
}
```

**Model Layer:**
```swift
struct DiskInfo: Codable {
    let path: String
    let sizeBytes: Int64
    let sizeHuman: String

    enum CodingKeys: String, CodingKey {
        case sizeBytes = "size_bytes"
        case sizeHuman = "size_human"
    }
}
```

### 2. **Services Layer**

**API Client Service:**
- Handles all network communication
- Error handling with custom error types
- Health checking and connection status

**Settings Manager:**
- Wraps UserDefaults
- didSet observers for automatic persistence
- Reset functionality

### 3. **Component Pattern**

**Reusable Components:**
```swift
struct StorageCard: View {
    let title: String
    let value: Int64
    let icon: String
    let color: Color

    var body: some View { ... }
}
```

**Used across multiple views:**
- Consistent styling
- Type-safe parameters
- Built-in formatters (ByteCountFormatter)

### 4. **@MainActor Pattern**

Applied to:
- `WorkspaceAPIClient` - ensures thread-safe UI updates
- All ViewModels - prevents race conditions
- `DataManager` - single source of truth

---

## **Reusable Components & Services**

### Common Components

| Component | Purpose | Used In |
|-----------|---------|---------|
| **StorageCard** | Display storage info with icon + size | DiskView, multiple screens |
| **ProgressRing** | Circular progress indicator | InsightsView, ProjectsView |
| **StatRow** | Key-value stat display | Multiple detail screens |
| **ToastView** | Success/error notifications | App-wide |
| **OnboardingTip** | Contextual help hints | ProductivityHub (UX clarity) |

### Common Services

| Service | Responsibility | Pattern |
|---------|---|---|
| **WorkspaceAPIClient** | Remote API calls | URLSession + async/await |
| **SettingsManager** | UserDefaults wrapper | ObservableObject with didSet |
| **DataManager** | Local data + persistence | Singleton with 3-layer backup |
| **TimerService** | Focus/Pomodoro timer | Observable with background support |
| **HapticManager** | Haptic feedback | Static enum methods |
| **NotificationService** | Local notifications | Async scheduling |

---

## **Key Technical Decisions**

### 1. **Async/Await over Combine**
- Simpler, more readable code
- Better error handling
- Modern Swift concurrency

### 2. **UserDefaults over Core Data**
- No complex migrations needed
- Simpler for small-medium datasets
- Can migrate to Core Data later

### 3. **Singleton DataManager**
- Single point of access
- Prevents data inconsistencies
- Easy dependency injection via environment objects

### 4. **3-Layer Backup System**
- Protects against data corruption
- Automatic recovery
- No user intervention needed

### 5. **Feature-Based Folder Structure** (ProductivityHub)
- Scales better than MVVM folders
- Easier navigation as app grows
- Clear feature ownership

---

## **Networking Best Practices Observed**

1. **Error Handling:**
   ```swift
   enum APIError: LocalizedError {
       case invalidURL
       case serverError
       case decodingError
       case networkUnavailable
   }
   ```

2. **Response Wrapping:**
   ```swift
   struct DiskUsageResponse: Codable {
       let status: String
       let timestamp: String
       let data: [String: DiskInfo]
   }
   ```

3. **CodingKeys for Snake-case:**
   ```swift
   enum CodingKeys: String, CodingKey {
       case sizeBytes = "size_bytes"
       case sizeHuman = "size_human"
   }
   ```

4. **Health Checks:**
   ```swift
   func checkHealth() async throws -> Bool {
       // Called on app startup
       // Tracks connection status
   }
   ```

5. **Concurrent API Calls:**
   ```swift
   async let diskData = apiClient.getDiskOverview()
   async let cacheData = apiClient.getCacheInfo()
   (diskUsage, cacheInfo) = try await (diskData, cacheData)
   ```

---

## **Platform Support**

### WorkspaceManager-iOS
- iPhone, iPad, Mac Catalyst (future)
- Minimum iOS 17.0
- HTTP only (Tailscale for remote access)

### ProductivityHub-iOS
- **iPhone:** TabView navigation (bottom bar)
- **iPad/Mac:** NavigationSplitView with sidebar
- **Mac Catalyst:** Full native support with menu bar commands
- **Keyboard Shortcuts:** Command+1 through Command+5 (iPad/Mac)

---

## **Summary of Best Practices**

Your iOS apps demonstrate:

1. **Clean Architecture:** Clear separation between Models, ViewModels, Services, Views
2. **Modern Swift:** @MainActor, async/await, @Published, @Observable patterns
3. **Thread Safety:** Explicit @MainActor annotations prevent race conditions
4. **Error Handling:** Custom error enums with localized descriptions
5. **Testability:** Dependency injection via ViewModels and Services
6. **Reusability:** Component-based UI with type-safe parameters
7. **Data Resilience:** 3-layer backup system prevents data loss
8. **Network Resilience:** Health checks, connection status, error recovery
9. **User Experience:** Adaptive layouts, haptic feedback, toast notifications
10. **Accessibility:** Support for VoiceOver, proper labels, semantic UI

This architecture pattern is **production-ready** and suitable for apps of varying complexity, from simple API clients (WorkspaceManager) to feature-rich productivity apps (ProductivityHub).