> ## Documentation Index
> Fetch the complete documentation index at: https://docs.swiftaiboilerplate.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Core Module

> Foundation layer providing **typed error handling**, **PII-safe logging**, and shared utilities. Zero dependencies by design.

<Info>
  **Full technical details** in your project at `/docs/modules/Core.md`
</Info>

## What's new

* **v2.2.0** — the localized error surface lives next to Core: `AppError.localizedUserMessage` (en + es) is provided by the Localization package, and every UI error call site now displays it instead of the raw `userMessage`. See the [AI](/pages/modules/ai) and [Localization](/pages/modules/localization) modules for how this threads through the app.
* **v2.0** — `DeepLinkBus` (in Core) is `@Observable`. Consumers that used `.onReceive($bus.latest)` should migrate to `.onChange(of: bus.latest)`. SwiftUI's observation machinery does the rest.
* Swift 6 strict concurrency across the package.

## What You Get

* ✅ **AppError enum** - Maps all system errors to user-friendly messages
* ✅ **AppLogger** - OSLog-based with automatic PII redaction
* ✅ **ResultOrError** - Functional error handling patterns
* ✅ **Theme types** - `ThemeManager` with a `Theme` enum (system, light, dark, aurora, obsidian)
* ✅ **Zero dependencies** - Pure foundation layer

**Time saved: 6-10 hours** of error handling boilerplate, logging infrastructure, and testing.

## Key Components

### AppError (Production Type)

Here's a shortened version of the production enum from the boilerplate:

```swift theme={null}
public enum AppError: Error, Equatable, CustomStringConvertible, LocalizedError, Sendable {
    case network(code: Int, message: String?)
    case decoding
    case unauthorized
    case rateLimited(retryAfter: TimeInterval?)
    // Additional cases omitted for brevity.

    // User-friendly messages
    public var userMessage: String {
        switch self {
        case .network(_, let message) where message?.localizedCaseInsensitiveContains("offline") == true:
            return "You're offline. Please check your internet connection."
        case .network(_, let message) where message?.localizedCaseInsensitiveContains("timeout") == true:
            return "Request timed out. Please try again."
        case .unauthorized:
            return "Invalid email or password. Please check your credentials and try again."
        case .rateLimited:
            return "Too many requests. Please wait a moment and try again."
        // ... handles all cases with actionable messages
        }
    }
}
```

**SignInViewModel:**

```swift theme={null}
// From SwiftAIBoilerplatePro/AppShell/SignInView.swift
func signInWithApple() async {
    do {
        _ = try await authClient.signInWithApple()
        AppLogger.info("Apple sign in successful", category: AppLogger.ui)
        errorMessage = nil
    } catch {
        let appError = AppError.from(error)            // Auto-maps to AppError
        errorMessage = appError.localizedUserMessage   // Localized (en + es) message for the UI
        AppLogger.error("Apple sign in failed: \(error)", category: AppLogger.ui)
    }
}
```

`localizedUserMessage` is the localized counterpart to `AppError.userMessage`, supplied by the Localization package and used by every UI error call site.

**Production Value:**

* ✅ Auto-maps URLError, NSError, custom errors
* ✅ Preserves technical details for logging
* ✅ Provides actionable user messages
* ✅ Sendable for Swift 6 compatibility
* ✅ Equatable for testing

### AppLogger

Structured logging with PII redaction:

```swift theme={null}
// Usage
AppLogger.debug("Message sent", category: AppLogger.ui)
AppLogger.info("API call succeeded", category: AppLogger.networking)
AppLogger.error("Failed to save", category: AppLogger.storage)

// Redact sensitive data before logging
AppLogger.debug("API Key: \(AppLogger.redacted(apiKey))", category: AppLogger.networking)
```

**Categories** (each a `Logger`; pass as `category:`):

* `AppLogger.networking` - HTTP requests
* `AppLogger.ai` - LLM interactions
* `AppLogger.ui` - User interface events
* `AppLogger.feature` - Feature operations
* `AppLogger.storage` - SwiftData / Keychain / persistence
* `AppLogger.notifications` - Notification operations
* `AppLogger.auth` - Authentication flows
* `AppLogger.payments` - Subscriptions and purchases

`AppLogger.subsystem` is the shared subsystem identifier (a `String`), not a category.

## Customization Examples

### Add Custom Error Type

```swift theme={null}
// In AppError
case myFeature(reason: MyFeatureErrorReason)

enum MyFeatureErrorReason {
    case invalidInput
    case processingFailed
}

// Add user message
var userMessage: String {
    switch self {
    case .myFeature(.invalidInput):
        return "Please check your input"
    case .myFeature(.processingFailed):
        return "Processing failed. Please try again"
    }
}
```

### Add Custom Log Category

```swift theme={null}
import OSLog

extension AppLogger {
    static let myFeature = Logger(
        subsystem: subsystem,
        category: "MyFeature"
    )
}

// Use it
AppLogger.info("Feature initialized", category: AppLogger.myFeature)
```

## Key Files

| Component   | Location                                     |
| ----------- | -------------------------------------------- |
| AppError    | `Packages/Core/Sources/Core/AppError.swift`  |
| AppLogger   | `Packages/Core/Sources/Core/AppLogger.swift` |
| Diagnostics | `Packages/Core/Sources/Core/Diagnostics/`    |

## Dependencies

* **None** - Core has zero dependencies (by design)

## Used By

* ✅ All other modules (foundation layer)
* ✅ ViewModels (error handling)
* ✅ Services (logging)

## Best Practices

<AccordionGroup>
  <Accordion title="Error Handling">
    * Always map errors to `AppError`
    * Use specific error reasons
    * Provide actionable user messages
    * Log technical details separately
  </Accordion>

  <Accordion title="Logging">
    * Prefer `AppLogger` over `print()` in app code (`print()` is fine in `#Preview` blocks)
    * Choose appropriate log level
    * Use correct category
    * Redact PII automatically
  </Accordion>
</AccordionGroup>

## Learn More

<CardGroup cols={2}>
  <Card title="Full Documentation" icon="book" href="https://github.com/SwiftAIBoilerplatePro/SwiftAIBoilerplatePro-Distribution/blob/main/docs/modules/Core.md">
    Complete Core guide
  </Card>

  <Card title="Networking Module" icon="wifi" href="/pages/modules/networking">
    Uses Core for errors and logging
  </Card>

  <Card title="Storage Module" icon="database" href="/pages/modules/storage">
    Uses Core for error handling
  </Card>

  <Card title="Architecture" icon="diagram-project" href="/pages/architecture">
    See how Core fits in
  </Card>
</CardGroup>

## Test Coverage

**95%+** - Core is foundational, so it carries some of the highest coverage in the codebase. Its tests run alongside everything else in the single workspace pass: \~598 tests across 12 package test targets (the 11 reusable packages plus the `TestSupport` test-infrastructure package) and the app test suites, all driven by one `Boilerplate.xctestplan` run.

Tests include:

* Error mapping scenarios
* Logger output verification
* PII redaction
