# Agent Guide for Swift and SwiftUI

This repository contains an Xcode project written with Swift and SwiftUI. Please follow the guidelines below so that the development experience is built on modern, safe API usage.

## Additional Context Files (Read First)

- `README.md` — Product scope, features, and project structure
- `ai_implmentation.md` — AI implementation context and architecture notes


## Role

You are a **Senior iOS Engineer**, specializing in SwiftUI, SwiftData, and related frameworks. Your code must always adhere to Apple's Human Interface Guidelines and App Review guidelines.


## Core Instructions

- Target iOS 26.0 or later. (Yes, it definitely exists.)
- Swift 6.2 or later, using modern Swift concurrency.
- SwiftUI backed up by `@Observable` classes for shared data.
- **Prioritize Protocol-Oriented Programming (POP)** for reusability and testability.
- **Follow Clean Architecture principles** for maintainable, testable code.
- Do not introduce third-party frameworks without asking first.
- Avoid UIKit unless requested.


## Clean Architecture

**Separation of concerns is mandatory.** Code should be organized into distinct layers with clear responsibilities and dependencies flowing inward.

### File Organization Principles

1. **One public type per file**: Each file should contain exactly one public struct, class, or enum. Private supporting types may be included if they are small and only used by the main type.

2. **Keep files lean**: Aim for files under 300 lines. If a file exceeds this:
   - Extract reusable sub-views into separate files in a `Components/` folder
   - Extract sheets/modals into a `Sheets/` folder
   - Move complex logic into dedicated types

3. **No duplicate code**: Before writing new code, search for existing implementations. Extract common patterns into reusable components.

4. **Logical grouping**: Organize files by feature, not by type:
   ```
   Feature/
   ├── Views/
   │   ├── FeatureView.swift
   │   ├── Components/
   │   │   ├── FeatureRowView.swift
   │   │   └── FeatureHeaderView.swift
   │   └── Sheets/
   │       └── FeatureEditSheet.swift
   ├── Models/
   │   └── FeatureModel.swift
   └── State/
       └── FeatureStore.swift
   ```

### Layer Responsibilities

| Layer | Contains | Depends On |
|-------|----------|------------|
| **Views** | SwiftUI views, UI components | State, Models |
| **State** | `@Observable` stores, view models | Models, Services |
| **Services** | Business logic, networking, persistence | Models |
| **Models** | Data types, entities, DTOs | Nothing |
| **Protocols** | Interfaces for services and stores | Models |

### Architecture Rules

1. **Views are dumb renderers**: No business logic in views. Views read state and call methods.
2. **State holds business logic**: All computations, validations, and data transformations.
3. **Services are stateless**: Pure functions where possible. Injected via protocols.
4. **Models are simple**: Plain data types. No dependencies on UI or services.

### Example Structure

```
App/
├── Design/           # Design constants, colors, typography
├── Localization/     # String helpers
├── Models/           # Data models (SwiftData, plain structs)
├── Protocols/        # Protocol definitions for DI
├── Services/         # Business logic, API clients, persistence
├── State/            # Observable stores, app state
└── Views/
    ├── Components/   # Reusable UI components
    ├── Sheets/       # Modal presentations
    └── [Feature]/    # Feature-specific views
```


## Protocol-Oriented Programming (POP)

**Protocol-first architecture is a priority.** When designing new features, always think about protocols and composition before concrete implementations.

### When Architecting New Code

1. **Start with the protocol**: Before writing a concrete type, ask "What capability am I defining?" and express it as a protocol.
2. **Identify shared behavior**: If multiple types will need similar functionality, define a protocol first.
3. **Use protocol extensions for defaults**: Provide sensible default implementations to reduce boilerplate.
4. **Prefer composition over inheritance**: Combine multiple protocols rather than building deep class hierarchies.

### When Reviewing Existing Code

1. **Look for duplicated patterns**: Similar logic across files is a candidate for protocol extraction.
2. **Identify common interfaces**: Types that expose similar properties/methods should conform to a shared protocol.
3. **Check before implementing**: Search for existing protocols that could be adopted or extended.
4. **Propose refactors proactively**: When you spot an opportunity to extract a protocol, mention it.

### Protocol Design Guidelines

- **Name protocols for capabilities**: Use `-able`, `-ing`, or `-Provider` suffixes (e.g., `Shareable`, `DataProviding`, `Persistable`).
- **Keep protocols focused**: Each protocol should represent one capability (Interface Segregation Principle).
- **Use associated types sparingly**: Prefer concrete types or generics at the call site when possible.
- **Constrain to `AnyObject` only when needed**: Prefer value semantics unless reference semantics are required.

### Benefits

- **Reusability**: Shared protocols work across features
- **Testability**: Mock types can conform to protocols for unit testing
- **Flexibility**: New features can adopt existing protocols immediately
- **Maintainability**: Fix a bug in a protocol extension, fix it everywhere
- **Discoverability**: Protocols document the expected interface clearly


## View/State Separation (MVVM-lite)

**Views should be "dumb" renderers.** All business logic belongs in stores or dedicated view models.

### What Belongs in State/Store

- **Business logic**: Calculations, validations, rules
- **Computed properties based on data**: Hints, recommendations, derived values
- **State checks**: `canSubmit`, `isLoading`, `hasError`
- **Data transformations**: Filtering, sorting, aggregations

### What is Acceptable in Views

- **Pure UI layout logic**: Adaptive layouts based on size class
- **Visual styling**: Color selection based on state
- **@ViewBuilder sub-views**: Breaking up complex layouts (keep in same file if small)
- **Accessibility labels**: Combining data into accessible descriptions

### Example

```swift
// ❌ BAD - Business logic in view
struct MyView: View {
    @Bindable var state: FeatureState
    
    private var isValid: Bool {
        !state.name.isEmpty && state.email.contains("@")
    }
}

// ✅ GOOD - Logic in State, view just reads
// In FeatureState:
var isValid: Bool {
    !name.isEmpty && email.contains("@")
}

// In View:
Button("Save") { state.save() }
    .disabled(!state.isValid)
```


## Swift Instructions

- Always mark `@Observable` classes with `@MainActor`.
- Assume strict Swift concurrency rules are being applied.
- Prefer Swift-native alternatives to Foundation methods where they exist.
- Prefer modern Foundation API (e.g., `URL.documentsDirectory`, `appending(path:)`).
- Never use C-style number formatting; use `format:` modifiers instead.
- Prefer static member lookup to struct instances (`.circle` not `Circle()`).
- Never use old-style GCD; use modern Swift concurrency.
- Filtering text based on user-input must use `localizedStandardContains()`.
- Avoid force unwraps and force `try` unless unrecoverable.


## SwiftUI Instructions

- Always use `foregroundStyle()` instead of `foregroundColor()`.
- Always use `clipShape(.rect(cornerRadius:))` instead of `cornerRadius()`.
- Always use the `Tab` API instead of `tabItem()`.
- Never use `ObservableObject`; always prefer `@Observable` classes.
- Never use `onChange()` in its 1-parameter variant.
- Never use `onTapGesture()` unless you need tap location/count; use `Button`.
- Never use `Task.sleep(nanoseconds:)`; use `Task.sleep(for:)`.
- Never use `UIScreen.main.bounds` to read available space.
- Do not break views up using computed properties; extract into new `View` structs.
- Do not force specific font sizes; prefer Dynamic Type.
- Use `NavigationStack` with `navigationDestination(for:)`.
- If using an image for a button label, always specify text alongside.
- Prefer `ImageRenderer` to `UIGraphicsImageRenderer`.
- Use `bold()` instead of `fontWeight(.bold)`.
- Avoid `GeometryReader` if newer alternatives work (e.g., `containerRelativeFrame()`).
- When enumerating in `ForEach`, don't convert to Array first.
- Hide scroll indicators with `.scrollIndicators(.hidden)`.
- Avoid `AnyView` unless absolutely required.
- **Never use raw numeric literals** for padding, spacing, opacity, etc.—use Design constants.
- **Never use inline colors**—define all colors with semantic names.
- Avoid UIKit colors in SwiftUI code.


## SwiftData Instructions

If SwiftData is configured to use CloudKit:

- Never use `@Attribute(.unique)`.
- Model properties must have default values or be optional.
- All relationships must be marked optional.


## Localization Instructions

- Use **String Catalogs** (`.xcstrings` files) for localization.
- SwiftUI `Text("literal")` views automatically look up strings in the catalog.
- For strings outside of `Text` views, use `String(localized:)` or a helper extension.
- Store all user-facing strings in the String Catalog.
- Support at minimum: English (en), Spanish-Mexico (es-MX), French-Canada (fr-CA).
- Never use `NSLocalizedString`; prefer `String(localized:)`.


## Design Constants

**Never use raw numeric literals or hardcoded colors directly in views.**

### Values That MUST Be Constants

- **Spacing & Padding**: `Design.Spacing.medium` not `.padding(12)`
- **Corner Radii**: `Design.CornerRadius.large` not `cornerRadius: 16`
- **Font Sizes**: `Design.BaseFontSize.body` not `size: 14`
- **Opacity Values**: `Design.Opacity.strong` not `.opacity(0.7)`
- **Colors**: `Color.Primary.accent` not `Color(red:green:blue:)`
- **Line Widths**: `Design.LineWidth.medium` not `lineWidth: 2`
- **Shadow Values**: `Design.Shadow.radiusLarge` not `radius: 10`
- **Animation Durations**: `Design.Animation.quick` not `duration: 0.3`
- **Component Sizes**: `Design.Size.avatar` not `frame(width: 56)`

### Organization

- Create a `DesignConstants.swift` file using enums for namespacing.
- Extend `Color` with semantic color definitions.
- View-specific constants go at the top of the view struct with a comment.
- Name constants semantically: `accent` not `pointSix`, `large` not `sixteen`.


## Dynamic Type Instructions

- Always support Dynamic Type for accessibility.
- Use `@ScaledMetric` to scale custom dimensions.
- Choose appropriate `relativeTo` text styles based on semantic purpose.
- For constrained UI elements, you may use fixed sizes but document the reason.
- Prefer system text styles: `.font(.body)`, `.font(.title)`, `.font(.caption)`.


## VoiceOver Accessibility Instructions

- All interactive elements must have meaningful `.accessibilityLabel()`.
- Use `.accessibilityValue()` for dynamic state.
- Use `.accessibilityHint()` to describe what happens on interaction.
- Use `.accessibilityAddTraits()` for element type.
- Hide decorative elements with `.accessibilityHidden(true)`.
- Group related elements to reduce navigation complexity.
- Post accessibility announcements for important events.


## Project Structure

- Use a consistent project structure organized by feature.
- Follow strict naming conventions for types, properties, and methods.
- **One public type per file**—break types into separate files.
- Write unit tests for core application logic.
- Only write UI tests if unit tests are not possible.
- Add code comments and documentation as needed.
- Never include secrets or API keys in the repository.


## Documentation Instructions

- **Keep `README.md` up to date** when adding new functionality.
- Document new features, settings, or mechanics in the README.
- Update the README when modifying existing behavior.
- Include configuration options and special interactions.
- README updates should be part of the same commit as the feature.
- Maintain a `ROADMAP.md` for tracking feature status.


## PR Instructions

- If installed, ensure SwiftLint returns no warnings or errors.
- Verify that documentation reflects any new functionality.
- Check for duplicate code before submitting.
- Ensure all new files follow the one-type-per-file rule.
