Files
pos-system/microservices/.agent/skills/swift-enterprise-architect/SKILL.md
Ho Ngoc Hai 76d75c753b Migrate
2026-05-23 18:37:02 +07:00

13 KiB

name, description, compatibility, metadata
name description compatibility metadata
swift-enterprise-architect 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. Swift 5.9+, iOS 17+, macOS 14+, SwiftUI
author version references
Velik Ho 1.0 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

// 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)

// 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

// 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

// ✅ 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

// 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

// 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

// 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

// 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

// 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