Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion .claude/settings.local.json
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,12 @@
"Bash(time make:*)",
"Bash(# Fix UIComponents imports to UI-Components\nfind . -name \"\"*.swift\"\" -type f | while read -r file; do\n if grep -q \"\"import UIComponents\"\" \"\"$file\"\"; then\n echo \"\"Fixing: $file\"\"\n sed -i '''' ''s/import UIComponents/import UI_Components/g'' \"\"$file\"\"\n fi\ndone)",
"mcp__filesystem__search_files",
"mcp__filesystem__edit_file"
"mcp__filesystem__edit_file",
"mcp__github__list_pull_requests",
"mcp__puppeteer__puppeteer_screenshot",
"mcp__github__get_pull_request",
"mcp__github__get_pull_request_comments",
"mcp__github__get_pull_request_files"
],
"deny": []
},
Expand Down
5 changes: 5 additions & 0 deletions .vscode/extensions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"recommendations": [
"anthropic.claude-code"
]
}
52 changes: 52 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# ModularHomeInventory - Agent Guide

## Project Overview
- **Architecture**: 12-module SPM structure with Domain-Driven Design
- **Target**: iOS 17.0+ (iPhone & iPad Universal)
- **Swift Version**: 5.9 (DO NOT upgrade to Swift 6)
- **Bundle ID**: com.homeinventory.app
- **Team ID**: 2VXBQV4XC9

## Development Environment
- **Build System**: XcodeGen + Makefile with parallel module compilation
- **Key Files**:
- `project.yml` - XcodeGen configuration
- `Makefile` - Build system commands
- `CLAUDE.md` - Project-specific instructions

## Module Structure
Work within this 4-layer architecture:
Foundation Layer: Foundation-Core, Foundation-Models, Foundation-Resources
Infrastructure Layer: Infrastructure-Network, Infrastructure-Storage, Infrastructure-Security, Infrastructure-Monitoring
Services Layer: Services-Authentication, Services-Business, Services-External, Services-Search, Services-Sync
UI Layer: UI-Core, UI-Components, UI-Styles, UI-Navigation
Features Layer: Features-Inventory, Features-Scanner, Features-Settings, Features-Analytics, Features-Locations

## Development Workflow
1. **Always validate SPM**: Run `make validate-spm` before making changes
2. **Use parallel builds**: Prefer `make build-fast run` over `make build run`
3. **Clean rebuilds**: Use `make clean-all build run` if build issues occur
4. **Code quality**: Run `make lint format` before finalizing changes

## Testing & Validation
- **Primary validation**: `make build-fast` (tests currently disabled due to dependency issues)
- **UI validation**: `./UIScreenshots/run-screenshot-tests.sh both`
- **Feature tests**: `./UIScreenshots/test-data-features.sh`
- **Module validation**: `make validate-spm`

## Deployment
- **TestFlight**: `make testflight` or `fastlane testflight force:true`
- **Archive**: `make archive`
- **Release build**: `make build-release`

## Critical Notes
- Tests are currently disabled (see TODO-SPECIAL.md)
- Swift 6 upgrade is blocked due to compatibility requirements
- Use `make build-fast` for performance (parallel module builds)
- DerivedData conflicts resolved with `make clean-all`

## Agent Instructions
- Always check CLAUDE.md for latest project context
- Validate changes with build system before proposing diffs
- Follow existing code patterns and module dependencies
- Never bypass the established 12-module architecture
2 changes: 2 additions & 0 deletions App-Main/Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ let package = Package(
.package(path: "../Features-Analytics"),
.package(path: "../Features-Settings"),
.package(path: "../Features-Scanner"),
.package(path: "../Features-Receipts"),
],
targets: [
.target(
Expand Down Expand Up @@ -80,6 +81,7 @@ let package = Package(
.product(name: "FeaturesAnalytics", package: "Features-Analytics"),
.product(name: "FeaturesSettings", package: "Features-Settings"),
.product(name: "FeaturesScanner", package: "Features-Scanner"),
.product(name: "FeaturesReceipts", package: "Features-Receipts"),
]
),
]
Expand Down
4 changes: 3 additions & 1 deletion App-Main/Sources/AppMain/AppContainer.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import Foundation
import CoreGraphics
import Observation
import FoundationCore
import FoundationModels
import ServicesAuthentication
Expand All @@ -15,7 +16,8 @@ import InfrastructureMonitoring

/// Central dependency injection container for the entire application
@MainActor
public final class AppContainer: ObservableObject {
@Observable
public final class AppContainer {

// MARK: - Singleton

Expand Down
21 changes: 12 additions & 9 deletions App-Main/Sources/AppMain/AppCoordinator.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import SwiftUI
import Foundation
import Observation
import FoundationModels
import FoundationCore
import FeaturesInventory
Expand All @@ -11,15 +12,16 @@ import FeaturesSettings

/// Modern app coordinator for the new modular architecture
@MainActor
public final class AppCoordinator: ObservableObject {
@Observable
public final class AppCoordinator {

// MARK: - Published Properties

@Published public var isInitialized = false
@Published public var showOnboarding = false
@Published public var selectedTab = 0
@Published public var isLoading = false
@Published public var error: AppError?
public var isInitialized = false
public var showOnboarding = false
public var selectedTab = 0
public var isLoading = false
public var error: AppError?

// MARK: - Dependencies

Expand Down Expand Up @@ -233,9 +235,10 @@ public final class AppCoordinator: ObservableObject {

/// Stub implementation of SettingsCoordinator for build compatibility
@MainActor
public final class SettingsCoordinator: ObservableObject {
@Published public var navigationPath = NavigationPath()
@Published public var presentedSheet: String?
@Observable
public final class SettingsCoordinator {
public var navigationPath = NavigationPath()
public var presentedSheet: String?

public init() {}

Expand Down
4 changes: 3 additions & 1 deletion App-Main/Sources/AppMain/AppMain.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import SwiftUI
import UIStyles

/// Main entry point for the modular App-Main module
public struct AppMain {
Expand All @@ -7,6 +8,7 @@ public struct AppMain {
@MainActor
public static func createMainView() -> some View {
ContentView()
.environmentObject(AppContainer.shared)
.environment(AppContainer.shared)
.themedWithManager()
}
}
8 changes: 5 additions & 3 deletions App-Main/Sources/AppMain/ConfigurationManager.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import Foundation
import Observation

/// Manages application configuration and environment settings
public final class ConfigurationManager: ObservableObject {
@Observable
public final class ConfigurationManager {

// MARK: - Environment Detection

Expand Down Expand Up @@ -192,15 +194,15 @@ public final class ConfigurationManager: ObservableObject {

public func updateConfiguration(key: String, value: Any) {
userDefaults.set(value, forKey: key)
objectWillChange.send()
// No need for manual change notification with @Observable
}

public func resetToDefaults() {
let configKeys = userDefaults.dictionaryRepresentation().keys.filter { $0.hasPrefix("Config_") }
for key in configKeys {
userDefaults.removeObject(forKey: key)
}
objectWillChange.send()
// No need for manual change notification with @Observable
}
}

Expand Down
12 changes: 7 additions & 5 deletions App-Main/Sources/AppMain/FeatureFlagManager.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import Foundation
import Observation

/// Manages feature flags for gradual feature rollouts and A/B testing
public final class FeatureFlagManager: ObservableObject {
@Observable
public final class FeatureFlagManager {

// MARK: - Storage

Expand All @@ -10,7 +12,7 @@ public final class FeatureFlagManager: ObservableObject {

// MARK: - Published Properties

@Published public private(set) var flags: [String: FeatureFlag] = [:]
public private(set) var flags: [String: FeatureFlag] = [:]

// MARK: - Feature Flags

Expand Down Expand Up @@ -93,7 +95,7 @@ public final class FeatureFlagManager: ObservableObject {

// Persist override
userDefaults.set(enabled, forKey: "Flag_\(flag.rawValue)")
objectWillChange.send()
// No need for manual change notification with @Observable
}

/// Reset flag to default value
Expand All @@ -104,7 +106,7 @@ public final class FeatureFlagManager: ObservableObject {

// Remove override
userDefaults.removeObject(forKey: "Flag_\(flag.rawValue)")
objectWillChange.send()
// No need for manual change notification with @Observable
}
}

Expand Down Expand Up @@ -227,7 +229,7 @@ public final class FeatureFlagManager: ObservableObject {
}
}

objectWillChange.send()
// No need for manual change notification with @Observable
}

private func getCurrentUser() -> FeatureFlagUser {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import SwiftUI
import Observation
import UINavigation
import FoundationModels

Expand Down Expand Up @@ -34,15 +35,16 @@ public enum AnalyticsSheet: Identifiable {

/// Coordinator for analytics feature navigation
@MainActor
public final class AnalyticsCoordinator: ObservableObject {
@Observable
public final class AnalyticsCoordinator {

// MARK: - Properties

@Published public var path = NavigationPath()
@Published public var sheet: AnalyticsSheet?
@Published public var isShowingAlert = false
@Published public var alertTitle = ""
@Published public var alertMessage = ""
public var path = NavigationPath()
public var sheet: AnalyticsSheet?
public var isShowingAlert = false
public var alertTitle = ""
public var alertMessage = ""

// MARK: - Initialization

Expand Down Expand Up @@ -128,7 +130,7 @@ public final class AnalyticsCoordinator: ObservableObject {
/// Root view for analytics feature with navigation
public struct AnalyticsCoordinatorView: View {

@StateObject private var coordinator = AnalyticsCoordinator()
@State private var coordinator = AnalyticsCoordinator()

public var body: some View {
NavigationStack(path: $coordinator.path) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,25 +1,27 @@
import SwiftUI
import Foundation
import Combine
import Observation
import FoundationModels

// MARK: - Analytics Dashboard View Model

/// View model for managing the analytics dashboard state and business logic
@MainActor
public final class AnalyticsDashboardViewModel: ObservableObject {
@Observable
public final class AnalyticsDashboardViewModel {

// MARK: - Published Properties
// MARK: - Properties

@Published public var selectedPeriod: AnalyticsPeriod = .month
@Published public var isLoading: Bool = false
@Published public var totalItemsCount: Int = 0
@Published public var totalValue: Decimal = 0
@Published public var categoryBreakdown: [CategoryData] = []
@Published public var locationBreakdown: [LocationData] = []
@Published public var recentActivity: [ActivityItem] = []
@Published public var valueOverTime: [ChartDataPoint] = []
@Published public var itemsOverTime: [ChartDataPoint] = []
public var selectedPeriod: AnalyticsPeriod = .month
public var isLoading: Bool = false
public var totalItemsCount: Int = 0
public var totalValue: Decimal = 0
public var categoryBreakdown: [CategoryData] = []
public var locationBreakdown: [LocationData] = []
public var recentActivity: [ActivityItem] = []
public var valueOverTime: [ChartDataPoint] = []
public var itemsOverTime: [ChartDataPoint] = []

// MARK: - Private Properties

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import SwiftUI
import Observation
import FoundationModels
import UIComponents
import UIStyles
Expand All @@ -12,7 +13,7 @@ public struct AnalyticsDashboardView: View {

// MARK: - Properties

@StateObject private var viewModel = AnalyticsDashboardViewModel()
@State private var viewModel = AnalyticsDashboardViewModel()
@Environment(\.theme) private var theme

// MARK: - Body
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import SwiftUI
import Observation
import FoundationModels
import UIComponents
import UIStyles
Expand All @@ -12,7 +13,7 @@ public struct CategoryBreakdownView: View {
// MARK: - Properties

let category: ItemCategory
@StateObject private var viewModel: CategoryBreakdownViewModel
@State private var viewModel: CategoryBreakdownViewModel
@Environment(\.theme) private var theme
@EnvironmentObject private var coordinator: AnalyticsCoordinator

Expand Down Expand Up @@ -265,17 +266,18 @@ private struct ItemRow: View {
// MARK: - View Model

@MainActor
final class CategoryBreakdownViewModel: ObservableObject {
@Observable
final class CategoryBreakdownViewModel {

let category: ItemCategory

@Published var itemCount: Int = 0
@Published var totalValue: Decimal = 0
@Published var averageValue: Decimal = 0
@Published var highestValue: Decimal = 0
@Published var lowestValue: Decimal = 0
@Published var valueTrend: Double = 0
@Published var topItems: [ItemSummary] = []
var itemCount: Int = 0
var totalValue: Decimal = 0
var averageValue: Decimal = 0
var highestValue: Decimal = 0
var lowestValue: Decimal = 0
var valueTrend: Double = 0
var topItems: [ItemSummary] = []

init(category: ItemCategory) {
self.category = category
Expand Down
Loading