     1→import SwiftUI
     2→import Charts
     3→
     4→// MARK: - Daily ROI Chart
     5→
     6→struct DailyROIChart: View {
     7→    let data: [DailyROIStats]
     8→
     9→    var body: some View {
    10→        Chart(data) { day in
    11→            BarMark(
    12→                x: .value("Date", day.date),
    13→                y: .value("Value", day.totalValue)
    14→            )
    15→            .foregroundStyle(.green.gradient)
    16→
    17→            BarMark(
    18→                x: .value("Date", day.date),
    19→                y: .value("Cost", -day.totalCost)
    20→            )
    21→            .foregroundStyle(.red.gradient)
    22→        }
    23→        .chartYAxis {
    24→            AxisMarks(position: .leading) { value in
    25→                AxisGridLine()
    26→                AxisValueLabel {
    27→                    if let doubleValue = value.as(Double.self) {
    28→                        Text(String(format: "$%.0f", abs(doubleValue)))
    29→                    }
    30→                }
    31→            }
    32→        }
    33→        .chartXAxis {
    34→            AxisMarks(values: .automatic) { value in
    35→                AxisValueLabel {
    36→                    if let dateStr = value.as(String.self) {
    37→                        Text(formatDate(dateStr))
    38→                    }
    39→                }
    40→            }
    41→        }
    42→        .frame(height: 200)
    43→    }
    44→
    45→    private func formatDate(_ dateStr: String) -> String {
    46→        // Assume format "2025-01-15"
    47→        let parts = dateStr.split(separator: "-")
    48→        if parts.count >= 3 {
    49→            return "\(parts[2])/\(parts[1])"
    50→        }
    51→        return dateStr
    52→    }
    53→}
    54→
    55→// MARK: - ROI Gauge
    56→
    57→struct ROIGauge: View {
    58→    let value: Double
    59→    let maxValue: Double
    60→
    61→    var body: some View {
    62→        Gauge(value: min(value, maxValue), in: 0...maxValue) {
    63→            Text("ROI")
    64→        } currentValueLabel: {
    65→            Text(String(format: "%.0f%%", value))
    66→                .font(.title2.bold())
    67→        } minimumValueLabel: {
    68→            Text("0%")
    69→        } maximumValueLabel: {
    70→            Text(String(format: "%.0f%%", maxValue))
    71→        }
    72→        .gaugeStyle(.accessoryCircular)
    73→        .tint(gaugeGradient)
    74→        .scaleEffect(1.5)
    75→    }
    76→
    77→    private var gaugeGradient: Gradient {
    78→        if value >= 200 {
    79→            return Gradient(colors: [.green, .mint])
    80→        } else if value >= 100 {
    81→            return Gradient(colors: [.yellow, .green])
    82→        } else if value >= 50 {
    83→            return Gradient(colors: [.orange, .yellow])
    84→        } else {
    85→            return Gradient(colors: [.red, .orange])
    86→        }
    87→    }
    88→}
    89→
    90→// MARK: - Cost Breakdown Chart
    91→
    92→struct CostBreakdownChart: View {
    93→    let bySource: [SourceROI]
    94→
    95→    var body: some View {
    96→        Chart(bySource) { source in
    97→            SectorMark(
    98→                angle: .value("Cost", source.totalCost),
    99→                innerRadius: .ratio(0.5),
   100→                angularInset: 1.5
   101→            )
   102→            .foregroundStyle(by: .value("Source", source.source))
   103→            .cornerRadius(4)
   104→        }
   105→        .chartLegend(position: .bottom, spacing: 10)
   106→        .frame(height: 200)
   107→    }
   108→}
   109→
   110→// MARK: - Runs Timeline Chart
   111→
   112→struct RunsTimelineChart: View {
   113→    let runs: [CCRun]
   114→
   115→    private var groupedByHour: [(String, Int)] {
   116→        let calendar = Calendar.current
   117→        var counts: [Int: Int] = [:]
   118→
   119→        for run in runs {
   120→            let hour = calendar.component(.hour, from: run.startedAt)
   121→            counts[hour, default: 0] += 1
   122→        }
   123→
   124→        return (0..<24).map { hour in
   125→            (String(format: "%02d:00", hour), counts[hour] ?? 0)
   126→        }
   127→    }
   128→
   129→    var body: some View {
   130→        Chart(groupedByHour, id: \.0) { hour, count in
   131→            BarMark(
   132→                x: .value("Hour", hour),
   133→                y: .value("Runs", count)
   134→            )
   135→            .foregroundStyle(.blue.gradient)
   136→        }
   137→        .chartXAxis {
   138→            AxisMarks(values: .stride(by: 4)) { _ in
   139→                AxisValueLabel()
   140→            }
   141→        }
   142→        .frame(height: 150)
   143→    }
   144→}
   145→
   146→// MARK: - Budget Progress Chart
   147→
   148→struct BudgetProgressChart: View {
   149→    let used: Double
   150→    let limit: Double
   151→    let label: String
   152→
   153→    private var percentage: Double {
   154→        guard limit > 0 else { return 0 }
   155→        return (used / limit) * 100
   156→    }
   157→
   158→    var body: some View {
   159→        VStack(alignment: .leading, spacing: 8) {
   160→            HStack {
   161→                Text(label)
   162→                    .font(.subheadline)
   163→                Spacer()
   164→                Text(String(format: "%.0f%%", percentage))
   165→                    .font(.subheadline.bold())
   166→                    .foregroundStyle(progressColor)
   167→            }
   168→
   169→            GeometryReader { geometry in
   170→                ZStack(alignment: .leading) {
   171→                    RoundedRectangle(cornerRadius: 4)
   172→                        .fill(Color.secondary.opacity(0.2))
   173→
   174→                    RoundedRectangle(cornerRadius: 4)
   175→                        .fill(progressColor.gradient)
   176→                        .frame(width: geometry.size.width * min(percentage / 100, 1))
   177→                }
   178→            }
   179→            .frame(height: 8)
   180→
   181→            HStack {
   182→                Text(String(format: "$%.2f", used))
   183→                    .font(.caption.monospacedDigit())
   184→                    .foregroundStyle(.secondary)
   185→                Spacer()
   186→                Text(String(format: "$%.2f", limit))
   187→                    .font(.caption.monospacedDigit())
   188→                    .foregroundStyle(.secondary)
   189→            }
   190→        }
   191→    }
   192→
   193→    private var progressColor: Color {
   194→        if percentage >= 100 {
   195→            return .red
   196→        } else if percentage >= 80 {
   197→            return .orange
   198→        } else {
   199→            return .green
   200→        }
   201→    }
   202→}
   203→
   204→// MARK: - Previews
   205→
   206→#Preview("Daily ROI") {
   207→    DailyROIChart(data: [
   208→        DailyROIStats(date: "2025-01-13", totalCost: 5.0, totalValue: 25.0, profit: 20.0, roiPercent: 400, runCount: 5),
   209→        DailyROIStats(date: "2025-01-14", totalCost: 8.0, totalValue: 40.0, profit: 32.0, roiPercent: 400, runCount: 8),
   210→        DailyROIStats(date: "2025-01-15", totalCost: 3.0, totalValue: 15.0, profit: 12.0, roiPercent: 400, runCount: 3)
   211→    ])
   212→    .padding()
   213→}
   214→
   215→#Preview("ROI Gauge") {
   216→    ROIGauge(value: 250, maxValue: 500)
   217→        .frame(width: 100, height: 100)
   218→}
   219→
   220→#Preview("Budget Progress") {
   221→    BudgetProgressChart(used: 45.0, limit: 100.0, label: "Daily Budget")
   222→        .padding()
   223→        .frame(width: 300)
   224→}
   225→

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

// MARK: - Daily ROI Chart

struct DailyROIChart: View {
    let data: [DailyROIStats]

    var body: some View {
        Chart(data) { day in
            BarMark(
                x: .value("Date", day.date),
                y: .value("Value", day.totalValue)
            )
            .foregroundStyle(.green.gradient)

            BarMark(
                x: .value("Date", day.date),
                y: .value("Cost", -day.totalCost)
            )
            .foregroundStyle(.red.gradient)
        }
        .chartYAxis {
            AxisMarks(position: .leading) { value in
                AxisGridLine()
                AxisValueLabel {
                    if let doubleValue = value.as(Double.self) {
                        Text(String(format: "$%.0f", abs(doubleValue)))
                    }
                }
            }
        }
        .chartXAxis {
            AxisMarks(values: .automatic) { value in
                AxisValueLabel {
                    if let dateStr = value.as(String.self) {
                        Text(formatDate(dateStr))
                    }
                }
            }
        }
        .frame(height: 200)
    }

    private func formatDate(_ dateStr: String) -> String {
        // Assume format "2025-01-15"
        let parts = dateStr.split(separator: "-")
        if parts.count >= 3 {
            return "\(parts[2])/\(parts[1])"
        }
        return dateStr
    }
}

// MARK: - ROI Gauge

struct ROIGauge: View {
    let value: Double
    let maxValue: Double

    var body: some View {
        Gauge(value: min(value, maxValue), in: 0...maxValue) {
            Text("ROI")
        } currentValueLabel: {
            Text(String(format: "%.0f%%", value))
                .font(.title2.bold())
        } minimumValueLabel: {
            Text("0%")
        } maximumValueLabel: {
            Text(String(format: "%.0f%%", maxValue))
        }
        .gaugeStyle(.accessoryCircular)
        .tint(gaugeGradient)
        .scaleEffect(1.5)
    }

    private var gaugeGradient: Gradient {
        if value >= 200 {
            return Gradient(colors: [.green, .mint])
        } else if value >= 100 {
            return Gradient(colors: [.yellow, .green])
        } else if value >= 50 {
            return Gradient(colors: [.orange, .yellow])
        } else {
            return Gradient(colors: [.red, .orange])
        }
    }
}

// MARK: - Cost Breakdown Chart

struct CostBreakdownChart: View {
    let bySource: [SourceROI]

    var body: some View {
        Chart(bySource) { source in
            SectorMark(
                angle: .value("Cost", source.totalCost),
                innerRadius: .ratio(0.5),
                angularInset: 1.5
            )
            .foregroundStyle(by: .value("Source", source.source))
            .cornerRadius(4)
        }
        .chartLegend(position: .bottom, spacing: 10)
        .frame(height: 200)
    }
}

// MARK: - Runs Timeline Chart

struct RunsTimelineChart: View {
    let runs: [CCRun]

    private var groupedByHour: [(String, Int)] {
        let calendar = Calendar.current
        var counts: [Int: Int] = [:]

        for run in runs {
            let hour = calendar.component(.hour, from: run.startedAt)
            counts[hour, default: 0] += 1
        }

        return (0..<24).map { hour in
            (String(format: "%02d:00", hour), counts[hour] ?? 0)
        }
    }

    var body: some View {
        Chart(groupedByHour, id: \.0) { hour, count in
            BarMark(
                x: .value("Hour", hour),
                y: .value("Runs", count)
            )
            .foregroundStyle(.blue.gradient)
        }
        .chartXAxis {
            AxisMarks(values: .stride(by: 4)) { _ in
                AxisValueLabel()
            }
        }
        .frame(height: 150)
    }
}

// MARK: - Budget Progress Chart

struct BudgetProgressChart: View {
    let used: Double
    let limit: Double
    let label: String

    private var percentage: Double {
        guard limit > 0 else { return 0 }
        return (used / limit) * 100
    }

    var body: some View {
        VStack(alignment: .leading, spacing: 8) {
            HStack {
                Text(label)
                    .font(.subheadline)
                Spacer()
                Text(String(format: "%.0f%%", percentage))
                    .font(.subheadline.bold())
                    .foregroundStyle(progressColor)
            }

            GeometryReader { geometry in
                ZStack(alignment: .leading) {
                    RoundedRectangle(cornerRadius: 4)
                        .fill(Color.secondary.opacity(0.2))

                    RoundedRectangle(cornerRadius: 4)
                        .fill(progressColor.gradient)
                        .frame(width: geometry.size.width * min(percentage / 100, 1))
                }
            }
            .frame(height: 8)

            HStack {
                Text(String(format: "$%.2f", used))
                    .font(.caption.monospacedDigit())
                    .foregroundStyle(.secondary)
                Spacer()
                Text(String(format: "$%.2f", limit))
                    .font(.caption.monospacedDigit())
                    .foregroundStyle(.secondary)
            }
        }
    }

    private var progressColor: Color {
        if percentage >= 100 {
            return .red
        } else if percentage >= 80 {
            return .orange
        } else {
            return .green
        }
    }
}

// MARK: - Previews

#Preview("Daily ROI") {
    DailyROIChart(data: [
        DailyROIStats(date: "2025-01-13", totalCost: 5.0, totalValue: 25.0, profit: 20.0, roiPercent: 400, runCount: 5),
        DailyROIStats(date: "2025-01-14", totalCost: 8.0, totalValue: 40.0, profit: 32.0, roiPercent: 400, runCount: 8),
        DailyROIStats(date: "2025-01-15", totalCost: 3.0, totalValue: 15.0, profit: 12.0, roiPercent: 400, runCount: 3)
    ])
    .padding()
}

#Preview("ROI Gauge") {
    ROIGauge(value: 250, maxValue: 500)
        .frame(width: 100, height: 100)
}

#Preview("Budget Progress") {
    BudgetProgressChart(used: 45.0, limit: 100.0, label: "Daily Budget")
        .padding()
        .frame(width: 300)
}


Now I have enough context. Let me provide a comprehensive design plan for the StudioROI macOS app.

---

# StudioROI - macOS App Design Plan

## Executive Summary

StudioROI is a native macOS application for tracking ROI on a Mac Studio M3 Ultra investment of R$ 45,000. The app follows the established patterns from existing macOS apps in the workspace (NEOGHub, NEOG-Finance) with SwiftUI, NavigationSplitView, MenuBarExtra, and UserDefaults persistence with 3-layer backup.

---

## 1. Complete Project Structure

```
/Users/neog/Apps/macOS/StudioROI/
├── CLAUDE.md                           # Project documentation
├── Package.swift                       # Swift Package Manager
├── generate_project.rb                 # Xcode project generator
├── project.yml                         # XcodeGen config
├── StudioROI.xcodeproj/               # Generated Xcode project
│
└── StudioROI/
    ├── StudioROIApp.swift              # @main entry point + MenuBarExtra
    │
    ├── App/
    │   ├── AppState.swift              # @MainActor global state
    │   ├── ContentView.swift           # NavigationSplitView root
    │   └── MenuBar/
    │       └── MenuBarView.swift       # Menu bar quick status
    │
    ├── Models/
    │   ├── Investment.swift            # Investment configuration
    │   ├── RevenueEntry.swift          # Revenue entry model
    │   ├── RevenueCategory.swift       # Category enum
    │   ├── DepreciationConfig.swift    # Depreciation settings
    │   └── ROIStats.swift              # Computed statistics
    │
    ├── Services/
    │   ├── DataManager.swift           # Singleton + UserDefaults + 3-layer backup
    │   └── NotificationService.swift   # Native macOS notifications
    │
    ├── Views/
    │   ├── Dashboard/
    │   │   ├── DashboardView.swift     # Main dashboard with cards
    │   │   └── PaybackProgressCard.swift
    │   ├── Revenue/
    │   │   ├── RevenueListView.swift   # Revenue entries list
    │   │   ├── RevenueEntryRow.swift   # Individual entry row
    │   │   └── AddRevenueSheet.swift   # Add/Edit revenue form
    │   ├── Analytics/
    │   │   ├── AnalyticsView.swift     # Charts and projections
    │   │   └── ProjectionCalculator.swift
    │   ├── Settings/
    │   │   └── SettingsView.swift      # Investment config
    │   └── Sidebar/
    │       └── SidebarView.swift       # Navigation sidebar
    │
    ├── Components/
    │   ├── Charts/
    │   │   ├── RevenueTrendChart.swift # Monthly trend line chart
    │   │   ├── CategoryPieChart.swift  # Category breakdown
    │   │   └── PaybackCurveChart.swift # Projection curve
    │   └── Cards/
    │       ├── StatCard.swift          # Reusable stat card
    │       └── ProgressRing.swift      # Circular progress
    │
    ├── Extensions/
    │   ├── Double+Currency.swift       # Currency formatting (BRL)
    │   └── Date+Helpers.swift          # Date utilities
    │
    └── Resources/
        └── Assets.xcassets/            # App icons, colors
```

---

## 2. Data Models

### Investment.swift
```swift
import Foundation

struct Investment: Codable, Equatable {
    var id: UUID = UUID()
    var name: String = "Mac Studio M3 Ultra"
    var totalAmountBRL: Double = 45000.0
    var purchaseDate: Date = Date()
    var monthlyDepreciationRate: Double = 0.5  // 0.5% per month
    var notes: String = "96GB RAM, 1TB SSD"

    // Computed depreciation
    var currentDepreciation: Double {
        let months = Calendar.current.dateComponents([.month], from: purchaseDate, to: Date()).month ?? 0
        return min(totalAmountBRL * (monthlyDepreciationRate / 100) * Double(months), totalAmountBRL * 0.5)
    }

    var currentValue: Double {
        return totalAmountBRL - currentDepreciation
    }
}
```

### RevenueEntry.swift
```swift
import Foundation

struct RevenueEntry: Identifiable, Codable, Equatable, Hashable {
    var id: UUID = UUID()
    var amount: Double                          // R$ value
    var category: RevenueCategory
    var date: Date = Date()
    var description: String = ""
    var createdAt: Date = Date()
    var modifiedAt: Date = Date()

    // For sorting/filtering
    var monthKey: String {
        let formatter = DateFormatter()
        formatter.dateFormat = "yyyy-MM"
        return formatter.string(from: date)
    }

    var weekKey: String {
        let calendar = Calendar.current
        let week = calendar.component(.weekOfYear, from: date)
        let year = calendar.component(.year, from: date)
        return "\(year)-W\(week)"
    }
}
```

### RevenueCategory.swift
```swift
import SwiftUI

enum RevenueCategory: String, Codable, CaseIterable, Identifiable {
    case lmStudio = "LM Studio API"
    case render = "Render/Conversion"
    case cicd = "CI/CD Builds"
    case consulting = "Consulting/Projects"

    var id: String { rawValue }

    var icon: String {
        switch self {
        case .lmStudio: return "brain"
        case .render: return "film"
        case .cicd: return "hammer.fill"
        case .consulting: return "briefcase.fill"
        }
    }

    var color: Color {
        switch self {
        case .lmStudio: return .purple
        case .render: return .orange
        case .cicd: return .blue
        case .consulting: return .green
        }
    }
}
```

### ROIStats.swift
```swift
import Foundation

struct ROIStats: Equatable {
    let totalRevenue: Double
    let totalInvestment: Double
    let remainingPayback: Double
    let paybackPercentage: Double
    let projectedPaybackDate: Date?
    let monthlyAverage: Double
    let weeklyAverage: Double
    let todayRevenue: Double
    let roiPercentage: Double

    var isPaybackComplete: Bool {
        return paybackPercentage >= 100
    }

    var daysToPayback: Int? {
        guard let date = projectedPaybackDate else { return nil }
        return Calendar.current.dateComponents([.day], from: Date(), to: date).day
    }
}
```

---

## 3. DataManager Implementation

```swift
import Foundation
import SwiftUI

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

    // MARK: - Published Properties
    @Published var investment: Investment = .init()
    @Published var revenueEntries: [RevenueEntry] = []
    @Published var customCategories: [String] = []

    // MARK: - UserDefaults Keys (3-layer backup)
    private let investmentKey = "StudioROI_Investment"
    private let revenueKey = "StudioROI_Revenue"
    private let revenueBackup1Key = "StudioROI_Revenue_backup1"
    private let revenueBackup2Key = "StudioROI_Revenue_backup2"

    // MARK: - Init
    private init() {
        loadData()
    }

    // MARK: - Computed Statistics

    var stats: ROIStats {
        let totalRevenue = revenueEntries.reduce(0) { $0 + $1.amount }
        let remainingPayback = max(0, investment.totalAmountBRL - totalRevenue)
        let paybackPercentage = (totalRevenue / investment.totalAmountBRL) * 100

        // Calculate averages
        let calendar = Calendar.current
        let monthlyGroups = Dictionary(grouping: revenueEntries) { $0.monthKey }
        let monthlyAverage = monthlyGroups.isEmpty ? 0 : totalRevenue / Double(monthlyGroups.count)

        let weeklyGroups = Dictionary(grouping: revenueEntries) { $0.weekKey }
        let weeklyAverage = weeklyGroups.isEmpty ? 0 : totalRevenue / Double(weeklyGroups.count)

        // Today's revenue
        let todayRevenue = revenueEntries
            .filter { calendar.isDateInToday($0.date) }
            .reduce(0) { $0 + $1.amount }

        // Projected payback date
        let projectedDate: Date? = {
            guard monthlyAverage > 0, remainingPayback > 0 else { return nil }
            let monthsToPayback = remainingPayback / monthlyAverage
            return calendar.date(byAdding: .month, value: Int(ceil(monthsToPayback)), to: Date())
        }()

        // ROI percentage
        let roi = totalRevenue > 0 ? ((totalRevenue - investment.totalAmountBRL) / investment.totalAmountBRL) * 100 : -100

        return ROIStats(
            totalRevenue: totalRevenue,
            totalInvestment: investment.totalAmountBRL,
            remainingPayback: remainingPayback,
            paybackPercentage: min(paybackPercentage, 100),
            projectedPaybackDate: paybackPercentage >= 100 ? nil : projectedDate,
            monthlyAverage: monthlyAverage,
            weeklyAverage: weeklyAverage,
            todayRevenue: todayRevenue,
            roiPercentage: roi
        )
    }

    var revenueByCategory: [RevenueCategory: Double] {
        Dictionary(grouping: revenueEntries, by: { $0.category })
            .mapValues { $0.reduce(0) { $0 + $1.amount } }
    }

    var monthlyRevenue: [(month: String, amount: Double)] {
        let grouped = Dictionary(grouping: revenueEntries) { $0.monthKey }
        return grouped.map { ($0.key, $0.value.reduce(0) { $0 + $1.amount }) }
            .sorted { $0.0 < $1.0 }
    }

    // MARK: - CRUD Operations

    func addRevenue(_ entry: RevenueEntry) {
        revenueEntries.append(entry)
        revenueEntries.sort { $0.date > $1.date }
        saveData()
    }

    func updateRevenue(_ entry: RevenueEntry) {
        if let index = revenueEntries.firstIndex(where: { $0.id == entry.id }) {
            var updated = entry
            updated.modifiedAt = Date()
            revenueEntries[index] = updated
            saveData()
        }
    }

    func deleteRevenue(_ entry: RevenueEntry) {
        revenueEntries.removeAll { $0.id == entry.id }
        saveData()
    }

    func updateInvestment(_ investment: Investment) {
        self.investment = investment
        saveInvestment()
    }

    // MARK: - Persistence (3-Layer Backup)

    private func saveData() {
        // Validate data can be decoded before saving
        guard let encoded = try? JSONEncoder().encode(revenueEntries),
              (try? JSONDecoder().decode([RevenueEntry].self, from: encoded)) != nil else {
            return
        }

        // Cascade backups: current -> backup1, backup1 -> backup2
        if let currentData = UserDefaults.standard.data(forKey: revenueKey) {
            if let backup1Data = UserDefaults.standard.data(forKey: revenueBackup1Key) {
                UserDefaults.standard.set(backup1Data, forKey: revenueBackup2Key)
            }
            UserDefaults.standard.set(currentData, forKey: revenueBackup1Key)
        }

        // Save new data
        UserDefaults.standard.set(encoded, forKey: revenueKey)
    }

    private func saveInvestment() {
        if let encoded = try? JSONEncoder().encode(investment) {
            UserDefaults.standard.set(encoded, forKey: investmentKey)
        }
    }

    private func loadData() {
        // Load investment
        if let data = UserDefaults.standard.data(forKey: investmentKey),
           let decoded = try? JSONDecoder().decode(Investment.self, from: data) {
            investment = decoded
        }

        // Load revenue with fallback to backups
        if let data = loadRevenueData() {
            revenueEntries = data.sorted { $0.date > $1.date }
        }
    }

    private func loadRevenueData() -> [RevenueEntry]? {
        // Try primary key
        if let data = UserDefaults.standard.data(forKey: revenueKey),
           let decoded = try? JSONDecoder().decode([RevenueEntry].self, from: data) {
            return decoded
        }

        // Try backup1
        if let data = UserDefaults.standard.data(forKey: revenueBackup1Key),
           let decoded = try? JSONDecoder().decode([RevenueEntry].self, from: data) {
            // Restore to primary
            UserDefaults.standard.set(data, forKey: revenueKey)
            return decoded
        }

        // Try backup2
        if let data = UserDefaults.standard.data(forKey: revenueBackup2Key),
           let decoded = try? JSONDecoder().decode([RevenueEntry].self, from: data) {
            // Restore to primary and backup1
            UserDefaults.standard.set(data, forKey: revenueKey)
            UserDefaults.standard.set(data, forKey: revenueBackup1Key)
            return decoded
        }

        return nil
    }

    func resetAllData() {
        revenueEntries = []
        investment = Investment()
        UserDefaults.standard.removeObject(forKey: revenueKey)
        UserDefaults.standard.removeObject(forKey: revenueBackup1Key)
        UserDefaults.standard.removeObject(forKey: revenueBackup2Key)
        UserDefaults.standard.removeObject(forKey: investmentKey)
    }
}
```

---

## 4. View Hierarchy and Navigation

### App Entry Point (StudioROIApp.swift)
```swift
import SwiftUI

@main
struct StudioROIApp: App {
    @StateObject private var dataManager = DataManager.shared
    @AppStorage("StudioROI_ShowMenuBar") private var showMenuBar = true

    var body: some Scene {
        // Main Window
        WindowGroup {
            ContentView()
                .environmentObject(dataManager)
                .frame(minWidth: 900, minHeight: 600)
        }
        .commands {
            // Keyboard shortcuts
            CommandGroup(replacing: .newItem) {
                Button("Add Revenue") {
                    NotificationCenter.default.post(name: .addRevenueRequested, object: nil)
                }
                .keyboardShortcut("n", modifiers: .command)
            }

            CommandMenu("Navigation") {
                Button("Dashboard") { NotificationCenter.default.post(name: .navigateTo, object: SidebarItem.dashboard) }
                    .keyboardShortcut("1", modifiers: .command)
                Button("Revenue") { NotificationCenter.default.post(name: .navigateTo, object: SidebarItem.revenue) }
                    .keyboardShortcut("2", modifiers: .command)
                Button("Analytics") { NotificationCenter.default.post(name: .navigateTo, object: SidebarItem.analytics) }
                    .keyboardShortcut("3", modifiers: .command)
                Button("Settings") { NotificationCenter.default.post(name: .navigateTo, object: SidebarItem.settings) }
                    .keyboardShortcut(",", modifiers: .command)
            }
        }

        // Menu Bar Widget
        MenuBarExtra("StudioROI", systemImage: "desktopcomputer", isInserted: $showMenuBar) {
            MenuBarView()
                .environmentObject(dataManager)
        }
        .menuBarExtraStyle(.window)
    }
}

extension Notification.Name {
    static let addRevenueRequested = Notification.Name("addRevenueRequested")
    static let navigateTo = Notification.Name("navigateTo")
}
```

### ContentView.swift
```swift
import SwiftUI

struct ContentView: View {
    @EnvironmentObject var dataManager: DataManager
    @State private var selectedItem: SidebarItem = .dashboard
    @State private var columnVisibility: NavigationSplitViewVisibility = .all
    @State private var showingAddRevenue = false

    var body: some View {
        NavigationSplitView(columnVisibility: $columnVisibility) {
            SidebarView(selectedItem: $selectedItem)
                .navigationSplitViewColumnWidth(min: 180, ideal: 200, max: 240)
        } detail: {
            detailView
                .id(selectedItem)
        }
        .navigationSplitViewStyle(.balanced)
        .sheet(isPresented: $showingAddRevenue) {
            AddRevenueSheet()
        }
        .onReceive(NotificationCenter.default.publisher(for: .addRevenueRequested)) { _ in
            showingAddRevenue = true
        }
        .onReceive(NotificationCenter.default.publisher(for: .navigateTo)) { notification in
            if let item = notification.object as? SidebarItem {
                selectedItem = item
            }
        }
        // Keyboard shortcuts
        .onKeyPress(keys: [.init("1")], phases: .down) { press in
            if press.modifiers.contains(.command) {
                selectedItem = .dashboard
                return .handled
            }
            return .ignored
        }
        .onKeyPress(keys: [.init("2")], phases: .down) { press in
            if press.modifiers.contains(.command) {
                selectedItem = .revenue
                return .handled
            }
            return .ignored
        }
        .onKeyPress(keys: [.init("3")], phases: .down) { press in
            if press.modifiers.contains(.command) {
                selectedItem = .analytics
                return .handled
            }
            return .ignored
        }
    }

    @ViewBuilder
    private var detailView: some View {
        switch selectedItem {
        case .dashboard:
            DashboardView()
        case .revenue:
            RevenueListView()
        case .analytics:
            AnalyticsView()
        case .settings:
            SettingsView()
        }
    }
}
```

### SidebarView.swift
```swift
import SwiftUI

enum SidebarItem: String, CaseIterable, Identifiable {
    case dashboard = "Dashboard"
    case revenue = "Revenue"
    case analytics = "Analytics"
    case settings = "Settings"

    var id: String { rawValue }

    var icon: String {
        switch self {
        case .dashboard: return "gauge.with.dots.needle.bottom.50percent"
        case .revenue: return "dollarsign.circle.fill"
        case .analytics: return "chart.line.uptrend.xyaxis"
        case .settings: return "gearshape.fill"
        }
    }

    var shortcut: String {
        switch self {
        case .dashboard: return "1"
        case .revenue: return "2"
        case .analytics: return "3"
        case .settings: return ","
        }
    }
}

struct SidebarView: View {
    @Binding var selectedItem: SidebarItem
    @EnvironmentObject var dataManager: DataManager

    var body: some View {
        List(selection: $selectedItem) {
            Section("Navigation") {
                ForEach(SidebarItem.allCases) { item in
                    NavigationLink(value: item) {
                        Label(item.rawValue, systemImage: item.icon)
                    }
                }
            }

            Section("Quick Stats") {
                quickStatsSection
            }
        }
        .listStyle(.sidebar)
        .navigationTitle("StudioROI")
    }

    private var quickStatsSection: some View {
        VStack(alignment: .leading, spacing: 8) {
            HStack {
                Text("Payback")
                    .font(.caption)
                    .foregroundStyle(.secondary)
                Spacer()
                Text(String(format: "%.1f%%", dataManager.stats.paybackPercentage))
                    .font(.caption.bold())
                    .foregroundStyle(dataManager.stats.paybackPercentage >= 100 ? .green : .blue)
            }

            ProgressView(value: dataManager.stats.paybackPercentage / 100)
                .tint(dataManager.stats.paybackPercentage >= 100 ? .green : .blue)

            HStack {
                Text("Today")
                    .font(.caption)
                    .foregroundStyle(.secondary)
                Spacer()
                Text(dataManager.stats.todayRevenue.formatAsBRL())
                    .font(.caption.monospacedDigit())
            }
        }
        .padding(.vertical, 4)
    }
}
```

---

## 5. Menu Bar Implementation (MenuBarView.swift)

```swift
import SwiftUI

struct MenuBarView: View {
    @EnvironmentObject var dataManager: DataManager
    @State private var showingAddRevenue = false

    var body: some View {
        VStack(spacing: 0) {
            // Header
            headerSection

            Divider()

            // Payback Progress
            paybackSection

            Divider()

            // Today's Stats
            todaySection

            Divider()

            // Quick Actions
            quickActionsSection

            Divider()

            // Footer
            footerSection
        }
        .frame(width: 280)
        .sheet(isPresented: $showingAddRevenue) {
            AddRevenueSheet()
                .environmentObject(dataManager)
        }
    }

    // MARK: - Header

    private var headerSection: some View {
        HStack {
            Image(systemName: "desktopcomputer")
                .font(.title2)
                .foregroundStyle(.purple)

            VStack(alignment: .leading, spacing: 2) {
                Text("Mac Studio ROI")
                    .font(.headline)
                Text("M3 Ultra")
                    .font(.caption)
                    .foregroundStyle(.secondary)
            }

            Spacer()
        }
        .padding()
    }

    // MARK: - Payback Progress

    private var paybackSection: some View {
        VStack(spacing: 8) {
            HStack {
                Text("Payback Progress")
                    .font(.caption)
                    .foregroundStyle(.secondary)
                Spacer()
                Text(String(format: "%.1f%%", dataManager.stats.paybackPercentage))
                    .font(.title3.bold())
                    .foregroundStyle(paybackColor)
            }

            GeometryReader { geometry in
                ZStack(alignment: .leading) {
                    RoundedRectangle(cornerRadius: 4)
                        .fill(Color.secondary.opacity(0.2))

                    RoundedRectangle(cornerRadius: 4)
                        .fill(paybackColor.gradient)
                        .frame(width: geometry.size.width * min(dataManager.stats.paybackPercentage / 100, 1))
                }
            }
            .frame(height: 8)

            HStack {
                Text("Remaining:")
                    .font(.caption)
                    .foregroundStyle(.secondary)
                Spacer()
                Text(dataManager.stats.remainingPayback.formatAsBRL())
                    .font(.caption.monospacedDigit())
                    .foregroundStyle(.orange)
            }

            if let daysToPayback = dataManager.stats.daysToPayback {
                HStack {
                    Text("Est. Payback:")
                        .font(.caption)
                        .foregroundStyle(.secondary)
                    Spacer()
                    Text("\(daysToPayback) days")
                        .font(.caption)
                        .foregroundStyle(.secondary)
                }
            }
        }
        .padding()
    }

    // MARK: - Today's Stats

    private var todaySection: some View {
        VStack(spacing: 8) {
            HStack {
                Text("Today")
                    .font(.caption)
                    .foregroundStyle(.secondary)
                Spacer()
                Text(dataManager.stats.todayRevenue.formatAsBRL())
                    .font(.title3.bold())
                    .foregroundStyle(.green)
            }

            HStack {
                Text("Monthly Avg:")
                    .font(.caption)
                    .foregroundStyle(.secondary)
                Spacer()
                Text(dataManager.stats.monthlyAverage.formatAsBRL())
                    .font(.caption.monospacedDigit())
            }
        }
        .padding(.horizontal)
        .padding(.vertical, 8)
    }

    // MARK: - Quick Actions

    private var quickActionsSection: some View {
        VStack(spacing: 4) {
            Button {
                showingAddRevenue = true
            } label: {
                Label("Add Revenue", systemImage: "plus.circle.fill")
            }
            .buttonStyle(MenuBarButtonStyle())

            Button {
                openMainWindow()
            } label: {
                Label("Open Dashboard", systemImage: "gauge.with.dots.needle.bottom.50percent")
            }
            .buttonStyle(MenuBarButtonStyle())
        }
        .padding(.horizontal)
        .padding(.vertical, 8)
    }

    // MARK: - Footer

    private var footerSection: some View {
        HStack {
            Text("Investment: \(dataManager.investment.totalAmountBRL.formatAsBRL())")
                .font(.caption2)
                .foregroundStyle(.tertiary)

            Spacer()

            Button("Quit") {
                NSApplication.shared.terminate(nil)
            }
            .buttonStyle(.plain)
            .font(.caption)
            .foregroundStyle(.red)
        }
        .padding()
    }

    // MARK: - Helpers

    private var paybackColor: Color {
        let pct = dataManager.stats.paybackPercentage
        if pct >= 100 { return .green }
        if pct >= 75 { return .mint }
        if pct >= 50 { return .blue }
        if pct >= 25 { return .orange }
        return .red
    }

    private func openMainWindow() {
        NSApplication.shared.activate(ignoringOtherApps: true)
        if let window = NSApplication.shared.windows.first {
            window.makeKeyAndOrderFront(nil)
        }
    }
}

struct MenuBarButtonStyle: ButtonStyle {
    func makeBody(configuration: Configuration) -> some View {
        configuration.label
            .font(.caption)
            .frame(maxWidth: .infinity, alignment: .leading)
            .padding(.horizontal, 8)
            .padding(.vertical, 6)
            .background(configuration.isPressed ? Color.accentColor.opacity(0.2) : Color.clear)
            .cornerRadius(4)
    }
}
```

---

## 6. Key SwiftUI Views

### DashboardView.swift
```swift
import SwiftUI
import Charts

struct DashboardView: View {
    @EnvironmentObject var dataManager: DataManager
    @State private var showingAddRevenue = false

    var body: some View {
        ScrollView {
            VStack(spacing: 20) {
                // Header with main progress
                mainProgressSection

                // Stats cards grid
                statsGrid

                // Recent revenue
                recentRevenueSection

                // Category breakdown
                categorySection
            }
            .padding()
        }
        .navigationTitle("Dashboard")
        .toolbar {
            ToolbarItem(placement: .primaryAction) {
                Button {
                    showingAddRevenue = true
                } label: {
                    Label("Add Revenue", systemImage: "plus")
                }
                .keyboardShortcut("n", modifiers: .command)
            }
        }
        .sheet(isPresented: $showingAddRevenue) {
            AddRevenueSheet()
        }
    }

    // MARK: - Main Progress

    private var mainProgressSection: some View {
        HStack(spacing: 24) {
            // Progress Ring
            ZStack {
                Circle()
                    .stroke(Color.secondary.opacity(0.2), lineWidth: 12)

                Circle()
                    .trim(from: 0, to: min(dataManager.stats.paybackPercentage / 100, 1))
                    .stroke(
                        AngularGradient(
                            gradient: Gradient(colors: [.blue, .purple, .blue]),
                            center: .center
                        ),
                        style: StrokeStyle(lineWidth: 12, lineCap: .round)
                    )
                    .rotationEffect(.degrees(-90))
                    .animation(.spring(response: 0.8), value: dataManager.stats.paybackPercentage)

                VStack(spacing: 4) {
                    Text(String(format: "%.1f%%", dataManager.stats.paybackPercentage))
                        .font(.system(size: 32, weight: .bold, design: .rounded))
                    Text("Payback")
                        .font(.caption)
                        .foregroundStyle(.secondary)
                }
            }
            .frame(width: 160, height: 160)

            // Stats
            VStack(alignment: .leading, spacing: 12) {
                VStack(alignment: .leading, spacing: 4) {
                    Text("Total Revenue")
                        .font(.caption)
                        .foregroundStyle(.secondary)
                    Text(dataManager.stats.totalRevenue.formatAsBRL())
                        .font(.title2.bold())
                        .foregroundStyle(.green)
                }

                VStack(alignment: .leading, spacing: 4) {
                    Text("Remaining")
                        .font(.caption)
                        .foregroundStyle(.secondary)
                    Text(dataManager.stats.remainingPayback.formatAsBRL())
                        .font(.title2.bold())
                        .foregroundStyle(.orange)
                }

                if let projectedDate = dataManager.stats.projectedPaybackDate {
                    VStack(alignment: .leading, spacing: 4) {
                        Text("Projected Payback")
                            .font(.caption)
                            .foregroundStyle(.secondary)
                        Text(projectedDate, style: .date)
                            .font(.subheadline)
                    }
                }
            }

            Spacer()
        }
        .padding()
        .background(Color(nsColor: .controlBackgroundColor))
        .cornerRadius(12)
    }

    // MARK: - Stats Grid

    private var statsGrid: some View {
        LazyVGrid(columns: [
            GridItem(.flexible()),
            GridItem(.flexible()),
            GridItem(.flexible()),
            GridItem(.flexible())
        ], spacing: 16) {
            StatCard(
                title: "Today",
                value: dataManager.stats.todayRevenue.formatAsBRL(),
                icon: "calendar",
                color: .blue
            )

            StatCard(
                title: "Weekly Avg",
                value: dataManager.stats.weeklyAverage.formatAsBRL(),
                icon: "chart.bar.fill",
                color: .purple
            )

            StatCard(
                title: "Monthly Avg",
                value: dataManager.stats.monthlyAverage.formatAsBRL(),
                icon: "chart.line.uptrend.xyaxis",
                color: .green
            )

            StatCard(
                title: "ROI",
                value: String(format: "%.1f%%", dataManager.stats.roiPercentage),
                icon: "percent",
                color: dataManager.stats.roiPercentage >= 0 ? .green : .red
            )
        }
    }

    // MARK: - Recent Revenue

    private var recentRevenueSection: some View {
        VStack(alignment: .leading, spacing: 12) {
            HStack {
                Text("Recent Revenue")
                    .font(.headline)
                Spacer()
                NavigationLink(value: SidebarItem.revenue) {
                    Text("See All")
                        .font(.caption)
                }
                .buttonStyle(.plain)
            }

            if dataManager.revenueEntries.isEmpty {
                ContentUnavailableView {
                    Label("No Revenue Yet", systemImage: "dollarsign.circle")
                } description: {
                    Text("Add your first revenue entry to start tracking ROI.")
                } actions: {
                    Button("Add Revenue") {
                        showingAddRevenue = true
                    }
                    .buttonStyle(.borderedProminent)
                }
            } else {
                ForEach(dataManager.revenueEntries.prefix(5)) { entry in
                    RevenueEntryRow(entry: entry)
                }
            }
        }
        .padding()
        .background(Color(nsColor: .controlBackgroundColor))
        .cornerRadius(12)
    }

    // MARK: - Category Section

    private var categorySection: some View {
        VStack(alignment: .leading, spacing: 12) {
            Text("Revenue by Category")
                .font(.headline)

            if dataManager.revenueByCategory.isEmpty {
                Text("No data available")
                    .font(.caption)
                    .foregroundStyle(.secondary)
            } else {
                HStack(spacing: 20) {
                    // Pie Chart
                    Chart(dataManager.revenueByCategory.sorted(by: { $0.value > $1.value }), id: \.key) { category, amount in
                        SectorMark(
                            angle: .value("Amount", amount),
                            innerRadius: .ratio(0.5),
                            angularInset: 1.5
                        )
                        .foregroundStyle(category.color)
                        .cornerRadius(4)
                    }
                    .frame(width: 200, height: 200)

                    // Legend
                    VStack(alignment: .leading, spacing: 8) {
                        ForEach(RevenueCategory.allCases) { category in
                            if let amount = dataManager.revenueByCategory[category] {
                                HStack {
                                    Circle()
                                        .fill(category.color)
                                        .frame(width: 10, height: 10)
                                    Text(category.rawValue)
                                        .font(.caption)
                                    Spacer()
                                    Text(amount.formatAsBRL())
                                        .font(.caption.monospacedDigit())
                                }
                            }
                        }
                    }

                    Spacer()
                }
            }
        }
        .padding()
        .background(Color(nsColor: .controlBackgroundColor))
        .cornerRadius(12)
    }
}

struct StatCard: View {
    let title: String
    let value: String
    let icon: String
    let color: Color

    var body: some View {
        VStack(alignment: .leading, spacing: 8) {
            HStack {
                Image(systemName: icon)
                    .foregroundStyle(color)
                Spacer()
            }

            Text(value)
                .font(.title3.bold())

            Text(title)
                .font(.caption)
                .foregroundStyle(.secondary)
        }
        .padding()
        .background(Color(nsColor: .controlBackgroundColor))
        .cornerRadius(8)
    }
}
```

---

## 7. Keyboard Shortcuts

| Shortcut | Action |
|----------|--------|
| `Cmd+1` | Go to Dashboard |
| `Cmd+2` | Go to Revenue |
| `Cmd+3` | Go to Analytics |
| `Cmd+,` | Go to Settings |
| `Cmd+N` | Add new revenue entry |
| `Cmd+R` | Refresh data |
| `Delete` | Delete selected revenue entry |

---

## 8. Complete File List with Descriptions

| File | Description |
|------|-------------|
| `StudioROIApp.swift` | Main app entry, WindowGroup + MenuBarExtra |
| `App/AppState.swift` | Global state (@MainActor, @Published) |
| `App/ContentView.swift` | NavigationSplitView root with keyboard shortcuts |
| `App/MenuBar/MenuBarView.swift` | Menu bar widget with payback progress |
| `Models/Investment.swift` | Investment configuration (amount, depreciation) |
| `Models/RevenueEntry.swift` | Revenue entry model (Codable, Identifiable) |
| `Models/RevenueCategory.swift` | Category enum with icons and colors |
| `Models/ROIStats.swift` | Computed statistics struct |
| `Services/DataManager.swift` | Singleton, CRUD, 3-layer backup persistence |
| `Services/NotificationService.swift` | macOS native notifications |
| `Views/Dashboard/DashboardView.swift` | Main dashboard with progress ring and cards |
| `Views/Dashboard/PaybackProgressCard.swift` | Reusable payback progress component |
| `Views/Revenue/RevenueListView.swift` | List of all revenue entries with filters |
| `Views/Revenue/RevenueEntryRow.swift` | Individual revenue entry row |
| `Views/Revenue/AddRevenueSheet.swift` | Form to add/edit revenue entry |
| `Views/Analytics/AnalyticsView.swift` | Charts and projections view |
| `Views/Analytics/ProjectionCalculator.swift` | Payback projection logic |
| `Views/Settings/SettingsView.swift` | Investment config, categories, reset |
| `Views/Sidebar/SidebarView.swift` | Navigation sidebar with quick stats |
| `Components/Charts/RevenueTrendChart.swift` | Monthly revenue line chart |
| `Components/Charts/CategoryPieChart.swift` | Category breakdown pie chart |
| `Components/Charts/PaybackCurveChart.swift` | Projection curve chart |
| `Components/Cards/StatCard.swift` | Reusable stat card component |
| `Components/Cards/ProgressRing.swift` | Circular progress indicator |
| `Extensions/Double+Currency.swift` | BRL currency formatting |
| `Extensions/Date+Helpers.swift` | Date utility extensions |
| `CLAUDE.md` | Project documentation for Claude Code |

---

### Critical Files for Implementation

1. **`/Users/neog/Apps/macOS/StudioROI/StudioROI/Services/DataManager.swift`** - Core data management with 3-layer backup, all CRUD operations, and computed statistics
2. **`/Users/neog/Apps/macOS/StudioROI/StudioROI/Views/Dashboard/DashboardView.swift`** - Main dashboard view with progress ring, stats grid, and category breakdown
3. **`/Users/neog/Apps/macOS/StudioROI/StudioROI/App/MenuBar/MenuBarView.swift`** - Menu bar widget for quick payback status and add revenue
4. **`/Users/neog/Apps/macOS/NEOGHub/NEOGCommand/App/MenuBar/MenuBarView.swift`** - Reference pattern for MenuBarExtra implementation
5. **`/Users/neog/Apps/macOS/NEOG-Finance/Sources/NEOGFinance/Services/DataManager.swift`** - Reference pattern for DataManager singleton with UserDefaults