---
name: swift-enterprise-architect
description: Kiến trúc và patterns cho ứng dụng SwiftUI Enterprise (MVVM, DI, Navigation, Project Structure). Use for iOS/macOS apps, SwiftUI development, hoặc khi cần structured Swift architecture.
compatibility: "Swift 5.9+, iOS 17+, macOS 14+, SwiftUI"
metadata:
  author: Velik Ho
  version: "1.0"
  references: "Apple SwiftUI Documentation, Swift Concurrency"
---

# Swift Enterprise Development Workflow

Quy trình 4 giai đoạn để phát triển ứng dụng SwiftUI theo chuẩn Enterprise.

## When to Use This Skill / Khi Nào Sử Dụng

Use this skill when:
- Building iOS/macOS/visionOS apps / Xây dựng app Apple platforms
- Creating enterprise SwiftUI applications / Tạo ứng dụng SwiftUI enterprise
- Need MVVM + DI architecture / Cần kiến trúc MVVM + DI
- Implementing navigation patterns / Triển khai điều hướng

**DO NOT use when:**
- Simple single-screen apps / App đơn giản 1 màn hình
- UIKit-only projects / Dự án chỉ UIKit
- Backend Swift (use Vapor patterns) / Swift backend

## Overview / Tổng Quan

```
┌──────────────────────────────────────────────────────────────────┐
│                 WORKFLOW 4 GIAI ĐOẠN (Swift Enterprise)          │
├──────────────────────────────────────────────────────────────────┤
│                                                                  │
│  ┌─────────────┐     ┌─────────────────┐                        │
│  │   PHASE 1   │────►│     PHASE 2     │                        │
│  │  PROJECT    │     │   ARCHITECTURE  │                        │
│  │  STRUCTURE  │     │                 │                        │
│  │ - Folders   │     │ - MVVM Pattern  │                        │
│  │ - Resources │     │ - DI Setup      │                        │
│  │ - Config    │     │ - Services      │                        │
│  └─────────────┘     └────────┬────────┘                        │
│                               │                                  │
│                               ▼                                  │
│  ┌─────────────┐     ┌─────────────────┐                        │
│  │   PHASE 4   │◄────│     PHASE 3     │                        │
│  │  PLATFORM   │     │   UI & NAV      │                        │
│  │             │     │                 │                        │
│  │ - Extensions│     │ - TabView       │                        │
│  │ - Platform  │     │ - NavStack      │                        │
│  │ - Native    │     │ - Sheets        │                        │
│  └─────────────┘     └─────────────────┘                        │
│                                                                  │
└──────────────────────────────────────────────────────────────────┘
```

---

## Phase 1: Project Structure / Cấu Trúc Dự Án

**Goal**: Thiết lập cấu trúc thư mục chuẩn Enterprise

### Project Structure

```
MyApp/
├── MyAppApp.swift              # App entry point
├── ContentView.swift           # Root view
├── Core/                       # Core utilities
│   ├── Constants/
│   │   └── Constants.swift     # App-wide constants
│   └── Extensions/
│       ├── String+Extensions.swift
│       └── View+Extensions.swift
├── Models/                     # Data models
│   └── User.swift
├── Services/                   # Business services
│   ├── APIService.swift
│   └── AuthManager.swift
├── ViewModels/                 # MVVM ViewModels
│   ├── AuthViewModel.swift
│   └── HomeViewModel.swift
├── Views/                      # SwiftUI Views
│   ├── Auth/
│   │   ├── LoginView.swift
│   │   └── RegisterView.swift
│   ├── Home/
│   │   └── HomeView.swift
│   └── Screens/
│       ├── ProfileView.swift
│       └── SettingsView.swift
└── Resources/
    ├── Assets.xcassets/
    └── Localizable.strings
```

### Constants Pattern

```swift
// Core/Constants/Constants.swift

// MARK: - API Configuration
enum APIConfig {
    static let baseURL = "https://api.example.com"
    static let apiVersion = "/api/v1"
    static let timeout: TimeInterval = 30.0
}

// MARK: - Storage Keys
enum StorageKeys {
    static let accessToken = "access_token"
    static let refreshToken = "refresh_token"
    static let userData = "user_data"
}

// MARK: - Design System
enum DesignSystem {
    // Spacing
    static let spacingXS: CGFloat = 4
    static let spacingSM: CGFloat = 8
    static let spacingMD: CGFloat = 16
    static let spacingLG: CGFloat = 24
    
    // Corner Radius
    static let cornerRadiusSM: CGFloat = 8
    static let cornerRadiusMD: CGFloat = 12
    static let cornerRadiusLG: CGFloat = 16
}
```

---

## Phase 2: Architecture (MVVM + DI) / Kiến Trúc

**Goal**: Thiết lập MVVM pattern với Swift Concurrency

### ViewModel Pattern (BẮT BUỘC)

```swift
// ViewModels/SomeViewModel.swift

import SwiftUI
import Combine

/// ViewModel for SomeView
/// ViewModel cho SomeView
@MainActor
final class SomeViewModel: ObservableObject {
    
    // MARK: - Published Properties
    
    /// Current items
    /// Các items hiện tại
    @Published private(set) var items: [Item] = []
    
    /// Loading state
    /// Trạng thái đang tải
    @Published private(set) var isLoading = false
    
    /// Error message
    /// Thông báo lỗi
    @Published var errorMessage: String?
    
    // MARK: - Dependencies
    
    private let service: SomeServiceProtocol
    
    // MARK: - Init
    
    /// Initialize with dependencies
    /// Khởi tạo với dependencies
    init(service: SomeServiceProtocol = SomeService.shared) {
        self.service = service
    }
    
    // MARK: - Public Methods
    
    /// Load items from service
    /// Tải items từ service
    func loadItems() async {
        isLoading = true
        errorMessage = nil
        
        do {
            items = try await service.fetchItems()
        } catch {
            errorMessage = error.localizedDescription
        }
        
        isLoading = false
    }
}
```

### Service Pattern

```swift
// Services/SomeService.swift

/// Service protocol for DI
/// Protocol service cho DI
protocol SomeServiceProtocol {
    func fetchItems() async throws -> [Item]
}

/// Main service implementation
/// Implementation service chính
final class SomeService: SomeServiceProtocol {
    
    /// Shared singleton
    /// Singleton dùng chung
    static let shared = SomeService()
    
    private init() {}
    
    func fetchItems() async throws -> [Item] {
        // Implementation
    }
}
```

### Dependency Injection via Init

```swift
// ✅ GOOD: Protocol-based DI
final class HomeViewModel: ObservableObject {
    private let authManager: AuthManagerProtocol
    private let apiService: APIServiceProtocol
    
    init(
        authManager: AuthManagerProtocol = AuthManager.shared,
        apiService: APIServiceProtocol = APIService.shared
    ) {
        self.authManager = authManager
        self.apiService = apiService
    }
}

// Testing
let mockAuth = MockAuthManager()
let viewModel = HomeViewModel(authManager: mockAuth)
```

---

## Phase 3: UI & Navigation / Giao Diện & Điều Hướng

**Goal**: Xây dựng UI với TabView và NavigationStack

### TabView Navigation

```swift
// ContentView.swift

struct ContentView: View {
    
    /// Selected tab
    @State private var selectedTab: Tab = .home
    
    /// Tab enumeration
    enum Tab: String, CaseIterable {
        case home, explore, profile
        
        var title: String {
            switch self {
            case .home: return "Home"
            case .explore: return "Explore"
            case .profile: return "Profile"
            }
        }
        
        var icon: String {
            switch self {
            case .home: return "house"
            case .explore: return "magnifyingglass"
            case .profile: return "person"
            }
        }
    }
    
    var body: some View {
        TabView(selection: $selectedTab) {
            HomeView()
                .tabItem { Label(Tab.home.title, systemImage: Tab.home.icon) }
                .tag(Tab.home)
            
            ExploreView()
                .tabItem { Label(Tab.explore.title, systemImage: Tab.explore.icon) }
                .tag(Tab.explore)
            
            ProfileView()
                .tabItem { Label(Tab.profile.title, systemImage: Tab.profile.icon) }
                .tag(Tab.profile)
        }
    }
}
```

### NavigationStack with Path

```swift
// Views/Home/HomeView.swift

struct HomeView: View {
    
    @StateObject private var viewModel = HomeViewModel()
    @State private var navigationPath = NavigationPath()
    
    var body: some View {
        NavigationStack(path: $navigationPath) {
            List(viewModel.items) { item in
                NavigationLink(value: item) {
                    ItemRow(item: item)
                }
            }
            .navigationTitle("Home")
            .navigationDestination(for: Item.self) { item in
                ItemDetailView(item: item)
            }
            .task {
                await viewModel.loadItems()
            }
        }
    }
}
```

### Auth State Conditional UI

```swift
// ContentView.swift with Auth State

struct ContentView: View {
    
    @StateObject private var authManager = AuthManager.shared
    
    var body: some View {
        Group {
            switch authManager.authState {
            case .unknown:
                ProgressView()
            case .unauthenticated:
                AuthContainerView()
            case .authenticated:
                MainTabView()
            }
        }
        .task {
            await authManager.initialize()
        }
    }
}
```

---

## Phase 4: Platform & Extensions / Nền Tảng & Extensions

### String Extensions

```swift
// Core/Extensions/String+Extensions.swift

extension String {
    
    /// Localized string
    /// Chuỗi đã bản địa hóa
    var localized: String {
        NSLocalizedString(self, comment: "")
    }
    
    /// Email validation
    /// Kiểm tra email hợp lệ
    var isValidEmail: Bool {
        let regex = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,64}"
        return NSPredicate(format: "SELF MATCHES %@", regex).evaluate(with: self)
    }
    
    /// Trimmed string
    /// Chuỗi đã trim
    var trimmed: String {
        trimmingCharacters(in: .whitespacesAndNewlines)
    }
}
```

### View Extensions

```swift
// Core/Extensions/View+Extensions.swift

extension View {
    
    /// Apply modifier conditionally
    /// Áp dụng modifier có điều kiện
    @ViewBuilder
    func `if`<Content: View>(_ condition: Bool, transform: (Self) -> Content) -> some View {
        if condition {
            transform(self)
        } else {
            self
        }
    }
    
    /// Hide keyboard
    /// Ẩn bàn phím
    func hideKeyboard() {
        UIApplication.shared.sendAction(
            #selector(UIResponder.resignFirstResponder),
            to: nil, from: nil, for: nil
        )
    }
}
```

---

## Common Mistakes / Lỗi Thường Gặp

| Mistake | Problem | Solution |
|---------|---------|----------|
| Logic in View | Hard to test | Move to ViewModel |
| Missing `@MainActor` | Thread issues | Add to ViewModel class |
| Force unwrap `!` | Crashes | Use `if let`, `guard let` |
| Singleton abuse | Hard to test | Protocol-based DI |
| No loading states | Bad UX | Add `isLoading` property |
| Hardcoded strings | No i18n | Use `String.localized` |

## Quick Reference / Tham Chiếu Nhanh

| Category | Standard |
|----------|----------|
| Architecture | MVVM + Protocol DI |
| ViewModel | `@MainActor final class` + `ObservableObject` |
| State | `@Published`, `@State`, `@StateObject` |
| Navigation | `NavigationStack` + `NavigationPath` |
| Tabs | `TabView` with enum-based `Tab` |
| Async | `async/await`, `.task {}` modifier |
| Constants | Enum-based (no instance) |
| Comments | Bilingual EN/VI |

## Resources / Tài Nguyên

- [Swift Networking](../swift-networking/SKILL.md) - HTTP client patterns
- [Swift Security](../swift-security/SKILL.md) - Keychain & Auth
- [Swift UI Components](../swift-ui-components/SKILL.md) - Reusable components
- [Apple SwiftUI Docs](https://developer.apple.com/documentation/swiftui/)
- [Swift Concurrency](https://developer.apple.com/documentation/swift/concurrency)
- [Project Rules](../project-rules/SKILL.md) - GoodGo coding standards
