@leejungkiin/awkit 1.0.5 β†’ 1.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,154 @@
1
+ # πŸ” Phase 0: Discovery (Satellite View) β€” iOS
2
+
3
+ > **Zoom Level:** 0 β€” ToΓ n cαΊ£nh
4
+ > **Goal:** Understand the app: structure, frameworks, components, screen flow.
5
+ > **Output:** App Map document.
6
+
7
+ ---
8
+
9
+ ## β›” OUTPUT RULE
10
+
11
+ ```
12
+ βœ… ALLOWED: Diagrams, tables, lists, reports
13
+ βœ… ALLOWED: Shell commands for scanning
14
+ ❌ BLOCKED: Any Swift code
15
+ ❌ BLOCKED: Any implementation decisions (those come in Phase 1)
16
+ ```
17
+
18
+ ---
19
+
20
+ ## πŸ“‹ Sub-steps
21
+
22
+ ### 0.1: Scan IPA Structure
23
+
24
+ Verify decrypted IPA output:
25
+ ```
26
+ Payload/App.app/
27
+ β”œβ”€β”€ App # Mach-O binary
28
+ β”œβ”€β”€ Info.plist # App metadata
29
+ β”œβ”€β”€ Frameworks/ # Embedded frameworks
30
+ β”‚ β”œβ”€β”€ SomeSDK.framework/
31
+ β”‚ └── libswiftCore.dylib
32
+ β”œβ”€β”€ Assets.car # Compiled asset catalog
33
+ β”œβ”€β”€ Base.lproj/ # Storyboards / XIBs (compiled)
34
+ β”œβ”€β”€ *.momd # Core Data models
35
+ └── [other resources]
36
+ ```
37
+
38
+ ### 0.2: Framework Scanner
39
+
40
+ Scan ALL dependencies before any coding:
41
+
42
+ 1. **Scan `Frameworks/` directory:**
43
+ ```
44
+ Frameworks/Alamofire.framework β†’ Alamofire (network)
45
+ Frameworks/SDWebImage.framework β†’ SDWebImage (image)
46
+ Frameworks/Realm.framework β†’ Realm (database)
47
+ Frameworks/FBSDKCoreKit.framework β†’ Facebook SDK
48
+ ```
49
+
50
+ 2. **Scan class-dump headers for imports:**
51
+ ```
52
+ #import <AFNetworking/...> β†’ AFNetworking
53
+ #import <Masonry/...> β†’ Masonry (auto-layout)
54
+ @import Firebase; β†’ Firebase SDK
55
+ @import GoogleMobileAds; β†’ AdMob
56
+ ```
57
+
58
+ 3. **Check Mach-O linked frameworks:**
59
+ ```bash
60
+ otool -L Payload/App.app/App | grep -v /System | grep -v /usr/lib
61
+ ```
62
+
63
+ 4. **Check embedded dylibs:**
64
+ ```bash
65
+ find Payload/App.app -name "*.dylib" -o -name "*.framework" | sort
66
+ ```
67
+
68
+ 5. **Check for CocoaPods / SPM markers:**
69
+ ```
70
+ Pods/ directory β†’ was using CocoaPods
71
+ .package.resolved β†’ was using SPM
72
+ ```
73
+
74
+ See `framework-patterns.md` for comprehensive detection patterns.
75
+
76
+ ### 0.3: Info.plist & Entitlements Analysis
77
+
78
+ Extract from `Info.plist`:
79
+
80
+ 1. Bundle ID (`CFBundleIdentifier`)
81
+ 2. Display Name
82
+ 3. Min Deployment Target
83
+ 4. Permissions (Privacy keys):
84
+ ```
85
+ NSCameraUsageDescription β†’ Camera
86
+ NSPhotoLibraryUsageDescription β†’ Photo Library
87
+ NSLocationWhenInUseUsageDescription β†’ Location
88
+ NSMicrophoneUsageDescription β†’ Microphone
89
+ ```
90
+ 5. URL Schemes (deep links)
91
+ 6. Capabilities from entitlements:
92
+ ```
93
+ com.apple.developer.associated-domains β†’ Universal Links
94
+ aps-environment β†’ Push Notifications
95
+ com.apple.developer.in-app-payments β†’ Apple Pay
96
+ ```
97
+
98
+ ### 0.4: Class Structure Analysis
99
+
100
+ From class-dump headers:
101
+
102
+ 1. **Entry points:** AppDelegate, SceneDelegate
103
+ 2. **Root ViewController:** Tab bar? Navigation?
104
+ 3. **Major ViewControllers** β†’ future SwiftUI screens
105
+ 4. **Model classes** β†’ domain models
106
+ 5. **Network managers** β†’ API client
107
+ 6. **Singleton/manager classes** β†’ services to extract
108
+
109
+ ### 0.5: Screen Flow Map
110
+
111
+ ```mermaid
112
+ graph LR
113
+ Launch --> Login
114
+ Login --> MainTab
115
+ MainTab --> Home
116
+ MainTab --> Search
117
+ MainTab --> Profile
118
+ Home --> Detail
119
+ Profile --> Settings
120
+ ```
121
+
122
+ ### 0.6: Complexity Estimate
123
+
124
+ | Area | Rating | Notes |
125
+ |------|--------|-------|
126
+ | Data Layer | ●●●○○ | [N] APIs, [N] Core Data entities |
127
+ | Core Logic | ●●○○○ | [N] crypto utils, [N] formatters |
128
+ | UI Screens | ●●●●○ | [N] screens, [N] complex views |
129
+ | SDK Integration | ●●○○○ | [N] third-party, [N] native dylibs |
130
+
131
+ ---
132
+
133
+ ## πŸ“Š Output: App Map
134
+
135
+ Document all findings in structured format (adapt from Android `templates/app-map.md`).
136
+
137
+ ---
138
+
139
+ ## βœ… Gate
140
+
141
+ ```
142
+ "πŸ—ΊοΈ App Map xong. Anh review:
143
+ - [N] screens detected
144
+ - [N] frameworks found ([N] reuse, [N] replace)
145
+ - [N] native dylibs
146
+ - Complexity: [Low/Medium/High]
147
+
148
+ CΓ³ gΓ¬ cαΊ§n Δ‘iều chỉnh khΓ΄ng?
149
+ β†’ OK β†’ Phase 1 (Architecture Design)"
150
+ ```
151
+
152
+ ---
153
+
154
+ *Phase 0: Discovery β€” Know your target before you build*
@@ -0,0 +1,173 @@
1
+ # πŸ—οΈ Phase 1: Architecture (District View) β€” iOS
2
+
3
+ > **Zoom Level:** 1 β€” Architecture Design
4
+ > **Goal:** Design overall architecture with UI-First build order. NO code bodies.
5
+ > **Input:** Completed App Map from Phase 0.
6
+ > **Output:** Architecture Blueprint document.
7
+
8
+ ---
9
+
10
+ ## β›” OUTPUT RULE
11
+
12
+ ```
13
+ βœ… ALLOWED: Architecture diagrams, layer maps, feature-to-file mapping, API endpoint tables
14
+ βœ… ALLOWED: File paths, module names, dependency lists
15
+ ⚠️ ALLOWED: Package.swift skeleton (dependencies only)
16
+ ❌ BLOCKED: Function bodies, implementation details, actual Swift code
17
+ ```
18
+
19
+ ---
20
+
21
+ ## πŸ“‹ Sub-steps
22
+
23
+ ### 1.1: Layer Design
24
+
25
+ ```
26
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
27
+ β”‚ Presentation β”‚
28
+ β”‚ β”œβ”€β”€ Screens/ ([N] screens) β”‚
29
+ β”‚ β”œβ”€β”€ Navigation/ (NavigationStack) β”‚
30
+ β”‚ β”œβ”€β”€ Theme/ (Design system) β”‚
31
+ β”‚ └── Components/ (Shared views) β”‚
32
+ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
33
+ β”‚ Domain β”‚
34
+ β”‚ β”œβ”€β”€ Models/ ([N] business models) β”‚
35
+ β”‚ β”œβ”€β”€ Repositories/ ([N] protocols) β”‚
36
+ β”‚ └── UseCases/ ([N] use cases) β”‚
37
+ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
38
+ β”‚ Data β”‚
39
+ β”‚ β”œβ”€β”€ Network/ ([N] API endpoints) β”‚
40
+ β”‚ β”œβ”€β”€ Local/ (SwiftData, Keychain) β”‚
41
+ β”‚ └── Repositories/ (implementations) β”‚
42
+ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
43
+ β”‚ DI / Utilities β”‚
44
+ β”‚ └── Container, extensions, crypto β”‚
45
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
46
+ ```
47
+
48
+ ### 1.2: Feature β†’ File Mapping
49
+
50
+ | Feature | Domain Model | Repository Protocol | UseCase | Screen | ViewModel |
51
+ |---------|-------------|-------------------|---------|--------|-----------|
52
+ | Auth | User, Token | AuthRepository | LoginUC | LoginScreen | AuthVM |
53
+ | Home | Feed | HomeRepository | GetFeedUC | HomeScreen | HomeVM |
54
+ | ... | ... | ... | ... | ... | ... |
55
+
56
+ ### 1.3: API Endpoint Inventory
57
+
58
+ | # | Method | Endpoint | Auth | Request | Response | Notes |
59
+ |---|--------|----------|------|---------|----------|-------|
60
+ | 1 | POST | /auth/login | No | email, pwd | JWT | - |
61
+ | 2 | GET | /users/me | Bearer | - | User | - |
62
+
63
+ **How to find in headers/disassembly:**
64
+ ```objc
65
+ // class-dump output
66
+ - (void)requestWithURL:(NSURL *)url completion:(void (^)(id, NSError *))completion;
67
+ // Look for string constants with "https://" or "api/"
68
+ // Hopper: search for NSURLSession, dataTaskWithRequest
69
+ ```
70
+
71
+ ### 1.4: Data Schema Inventory
72
+
73
+ | Model | Key Fields | Source | Storage |
74
+ |-------|-----------|--------|---------|
75
+ | User | id, name, email, avatar | API | SwiftData + Memory |
76
+ | Settings | theme, language | Local | UserDefaults |
77
+
78
+ ### 1.5: Project Structure
79
+
80
+ ```
81
+ App/
82
+ β”œβ”€β”€ App.swift # @main entry point
83
+ β”œβ”€β”€ AppDelegate.swift # UIKit lifecycle (for SDK init)
84
+ β”œβ”€β”€ Info.plist
85
+ β”œβ”€β”€ Assets.xcassets/
86
+ β”œβ”€β”€ DI/
87
+ β”‚ └── AppContainer.swift
88
+ β”œβ”€β”€ Data/
89
+ β”‚ β”œβ”€β”€ Network/
90
+ β”‚ β”‚ β”œβ”€β”€ APIClient.swift
91
+ β”‚ β”‚ β”œβ”€β”€ Endpoints/
92
+ β”‚ β”‚ └── DTOs/
93
+ β”‚ β”œβ”€β”€ Local/
94
+ β”‚ β”‚ β”œβ”€β”€ SwiftDataModels/
95
+ β”‚ β”‚ β”œβ”€β”€ KeychainService.swift
96
+ β”‚ β”‚ └── UserDefaultsKeys.swift
97
+ β”‚ └── Repositories/
98
+ β”œβ”€β”€ Domain/
99
+ β”‚ β”œβ”€β”€ Models/
100
+ β”‚ β”œβ”€β”€ Repositories/ # Protocols
101
+ β”‚ └── UseCases/
102
+ β”œβ”€β”€ Presentation/
103
+ β”‚ β”œβ”€β”€ Navigation/
104
+ β”‚ β”œβ”€β”€ Theme/
105
+ β”‚ β”œβ”€β”€ Components/
106
+ β”‚ └── Screens/
107
+ β”‚ β”œβ”€β”€ Launch/
108
+ β”‚ β”œβ”€β”€ Auth/
109
+ β”‚ β”œβ”€β”€ Home/
110
+ β”‚ └── [feature]/
111
+ β”œβ”€β”€ Utilities/
112
+ β”‚ β”œβ”€β”€ Extensions/
113
+ β”‚ β”œβ”€β”€ Crypto/
114
+ β”‚ └── Helpers/
115
+ └── Resources/
116
+ β”œβ”€β”€ Localizable.xcstrings
117
+ └── Fonts/
118
+ ```
119
+
120
+ ### 1.6: Build Order (UI-First) ⭐
121
+
122
+ > **IMPORTANT:** UI-First build order β€” design and approve UI before coding logic.
123
+
124
+ ```
125
+ Foundation (one-time):
126
+ 1. 🟒 Xcode project setup + Theme/Design System
127
+ 2. 🟒 Navigation structure (NavigationStack, TabView)
128
+ 3. 🟒 DI Container skeleton
129
+
130
+ Per Feature (repeat for each):
131
+ 4. πŸ“ Blueprint: Contracts (models, protocols, use cases, state)
132
+ 5. 🎨 UI Shell: Visual implementation + Resource extraction
133
+ 6. 🚦 GATE: User approve UI
134
+ 7. πŸ”¨ Logic: Domain β†’ Data β†’ ViewModel β†’ Wire UI
135
+ 8. πŸ§ͺ Test: Integration + Parity
136
+
137
+ Final (one-time):
138
+ 9. πŸ“¦ SDK Integration + Native libs
139
+ 10. βœ… Full Parity Check
140
+ ```
141
+
142
+ ### 1.7: Tech Stack Decisions
143
+
144
+ | Decision | Choice | Rationale |
145
+ |----------|--------|-----------|
146
+ | Image Loading | Kingfisher | Mature, async, cache |
147
+ | State Management | @Observable | iOS 17+ native |
148
+ | Package Manager | SPM | Apple-native, modern |
149
+ | ... | ... | ... |
150
+
151
+ ---
152
+
153
+ ## πŸ“Š Output: Architecture Blueprint
154
+
155
+ Structured document with all sections above.
156
+
157
+ ---
158
+
159
+ ## βœ… Gate
160
+
161
+ ```
162
+ "πŸ—οΈ Architecture Blueprint xong.
163
+ Build order: UI-First per feature.
164
+ Anh muα»‘n bαΊ―t Δ‘αΊ§u tα»« feature nΓ o?
165
+ Em suggest: [Feature X] vì [reason]."
166
+
167
+ β†’ User picks feature β†’ Phase 2 (Blueprint + UI Design)
168
+ β†’ User wants changes β†’ Adjust architecture
169
+ ```
170
+
171
+ ---
172
+
173
+ *Phase 1: Architecture β€” Design before you build, UI before logic*
@@ -0,0 +1,348 @@
1
+ # πŸ“ Phase 2: Blueprint + UI Design (Per Feature) β€” iOS
2
+
3
+ > **Zoom Level:** 2 β€” Feature Detail
4
+ > **Goal:** Design contracts AND code UI visual shell for ONE feature.
5
+ > **Input:** Architecture Blueprint (Phase 1) + user's chosen feature.
6
+ > **Output:** Approved contracts + Working SwiftUI shell with mock data.
7
+
8
+ ---
9
+
10
+ ## β›” OUTPUT RULE
11
+
12
+ ```
13
+ PART A β€” Contracts (signatures only):
14
+ βœ… Protocol definitions, struct/enum types
15
+ βœ… APIClient endpoint definitions (signature only, no body)
16
+ βœ… ViewState struct, ViewAction enum
17
+ ❌ Function body implementations (use fatalError("TODO"))
18
+
19
+ PART B β€” UI (visual code):
20
+ βœ… Full SwiftUI code for screen
21
+ βœ… Hardcoded mock data (using ViewState from Part A)
22
+ βœ… Real resources (icons, colors, images extracted in 2.7)
23
+ βœ… #Preview for ALL states (normal, loading, error, empty)
24
+ ❌ Real ViewModel connection β€” use parameter defaults
25
+ ❌ Real API calls
26
+ ❌ Business logic
27
+ ```
28
+
29
+ ---
30
+
31
+ ## πŸ“‹ Sub-steps
32
+
33
+ ### 2.1: Deep Source Reading
34
+
35
+ Read class-dump headers + Hopper pseudo-code for the chosen feature.
36
+
37
+ **What to extract:**
38
+ - Class hierarchy (@interface, @protocol)
39
+ - Property declarations β†’ model fields
40
+ - Method signatures β†’ API contracts
41
+ - String constants β†’ URLs, keys
42
+ - Delegate/callback patterns β†’ async contract signatures
43
+
44
+ **ObjC Header Quick Ref:**
45
+ ```objc
46
+ @interface ClassName : SuperClass <Protocol1, Protocol2>
47
+ @property (nonatomic, copy) NSString *name; // β†’ let name: String
48
+ @property (nonatomic, strong) NSArray *items; // β†’ let items: [Item]
49
+ @property (nonatomic, assign) BOOL isActive; // β†’ let isActive: Bool
50
+ @property (nullable, nonatomic, copy) NSString *bio; // β†’ let bio: String?
51
+ - (void)fetchDataWithCompletion:(void (^)(id, NSError *))completion;
52
+ // β†’ func fetchData() async throws -> Data
53
+ @end
54
+ ```
55
+
56
+ See `objc-reading-guide.md` for comprehensive guide.
57
+
58
+ ### 2.2: Domain Model Contracts
59
+
60
+ ```swift
61
+ // Domain model
62
+ struct User: Identifiable, Sendable {
63
+ let id: String
64
+ let fullName: String
65
+ let email: String
66
+ let avatarURL: URL?
67
+ let isVerified: Bool
68
+ }
69
+
70
+ // DTO (from API)
71
+ struct UserDTO: Codable {
72
+ let userId: String
73
+ let fullName: String
74
+ let email: String
75
+ let avatarUrl: String?
76
+ let isVerified: Bool
77
+
78
+ enum CodingKeys: String, CodingKey {
79
+ case userId = "user_id"
80
+ case fullName = "full_name"
81
+ case email
82
+ case avatarUrl = "avatar_url"
83
+ case isVerified = "is_verified"
84
+ }
85
+
86
+ func toDomain() -> User {
87
+ User(id: userId, fullName: fullName, email: email,
88
+ avatarURL: avatarUrl.flatMap(URL.init), isVerified: isVerified)
89
+ }
90
+ }
91
+ ```
92
+
93
+ ### 2.3: Repository Contract
94
+
95
+ ```swift
96
+ protocol AuthRepository: Sendable {
97
+ func login(email: String, password: String) async throws -> User
98
+ func register(name: String, email: String, password: String) async throws -> User
99
+ func logout() async
100
+ func isLoggedIn() -> Bool
101
+ func currentUser() async -> User?
102
+ }
103
+ ```
104
+
105
+ ### 2.4: API Contract
106
+
107
+ ```swift
108
+ enum AuthEndpoint {
109
+ case login(email: String, password: String)
110
+ case register(name: String, email: String, password: String)
111
+ case currentUser
112
+
113
+ var path: String { /* ... */ }
114
+ var method: HTTPMethod { /* ... */ }
115
+ // Signature only, no URLRequest body yet
116
+ }
117
+ ```
118
+
119
+ ### 2.5: UseCase Signatures
120
+
121
+ ```swift
122
+ struct LoginUseCase {
123
+ private let authRepo: AuthRepository
124
+
125
+ func execute(email: String, password: String) async throws -> User {
126
+ fatalError("TODO: implement in Phase 3")
127
+ }
128
+ }
129
+ ```
130
+
131
+ ### 2.6: UI State Design
132
+
133
+ ```swift
134
+ // State
135
+ struct LoginViewState {
136
+ var email: String = ""
137
+ var password: String = ""
138
+ var isLoading: Bool = false
139
+ var error: String? = nil
140
+ var isPasswordVisible: Bool = false
141
+ }
142
+
143
+ // Actions (user interactions)
144
+ enum LoginAction {
145
+ case updateEmail(String)
146
+ case updatePassword(String)
147
+ case togglePasswordVisibility
148
+ case submit
149
+ }
150
+
151
+ // Events (one-time navigation/alerts)
152
+ enum LoginEvent {
153
+ case navigateToHome
154
+ case showError(String)
155
+ }
156
+
157
+ // Mock data for Preview
158
+ extension LoginViewState {
159
+ static let normal = LoginViewState(email: "user@example.com")
160
+ static let loading = LoginViewState(isLoading: true)
161
+ static let error = LoginViewState(error: "Invalid credentials")
162
+ }
163
+ ```
164
+
165
+ ### 2.7: Resource Extraction ⭐ (Before UI code!)
166
+
167
+ > **Why here?** UI code (2.8) needs real assets. If resources come later, UI will be full of placeholders β€” defeating the purpose of visual parity.
168
+
169
+ **Process:**
170
+ 1. Extract from `Assets.car` (use `acextract` or screen captures)
171
+ 2. Extract from IPA bundle: png, pdf, json, fonts
172
+ 3. Copy ONLY needed resources to new Xcode project `Assets.xcassets`
173
+ 4. Map string tables to `Localizable.xcstrings`
174
+
175
+ **Output:**
176
+ ```markdown
177
+ ### πŸ“¦ Resources for [Screen]
178
+ - Images: [list from Assets.xcassets]
179
+ - Colors: [list β€” add to Color extension or asset catalog]
180
+ - Strings: [list β€” add to Localizable.xcstrings]
181
+ - Fonts: [custom fonts if any]
182
+ βœ… All accessible in SwiftUI
183
+ ```
184
+
185
+ ### 2.8: UI Implementation β€” Visual Shell ⭐
186
+
187
+ > **Goal:** Code the screen with HARDCODED mock data. Pixel-perfect visual parity with original app.
188
+
189
+ **Rules:**
190
+ ```
191
+ βœ… MUST DO:
192
+ - Use ViewState from 2.6 (hardcode sample values as defaults)
193
+ - Use REAL resources extracted in 2.7
194
+ - Display ALL visual elements from original app
195
+ - Match: spacing, font size, colors, icon placement
196
+ - Code ALL states: normal, loading, error, empty
197
+ - Create #Preview for each state
198
+
199
+ ❌ MUST NOT:
200
+ - Connect real ViewModel (use parameter defaults)
201
+ - Call real APIs
202
+ - Code business logic
203
+ - Use DI/injection
204
+ ```
205
+
206
+ **Pattern β€” Stateless View:**
207
+ ```swift
208
+ struct LoginScreenContent: View {
209
+ var state: LoginViewState = .normal // Hardcoded default
210
+ var onAction: (LoginAction) -> Void = { _ in } // No-op default
211
+
212
+ var body: some View {
213
+ VStack(spacing: 24) {
214
+ // Logo β€” real resource from 2.7
215
+ Image("app_logo")
216
+ .resizable()
217
+ .frame(width: 120, height: 120)
218
+
219
+ Spacer().frame(height: 24)
220
+
221
+ // Email
222
+ TextField("Email", text: .constant(state.email))
223
+ .textFieldStyle(.roundedBorder)
224
+ .keyboardType(.emailAddress)
225
+ .textContentType(.emailAddress)
226
+
227
+ // Password with toggle
228
+ HStack {
229
+ if state.isPasswordVisible {
230
+ TextField("Password", text: .constant(state.password))
231
+ } else {
232
+ SecureField("Password", text: .constant(state.password))
233
+ }
234
+ Button { onAction(.togglePasswordVisibility) } label: {
235
+ Image(systemName: state.isPasswordVisible ? "eye.slash" : "eye")
236
+ .foregroundColor(.secondary)
237
+ }
238
+ }
239
+ .textFieldStyle(.roundedBorder)
240
+
241
+ // Login Button
242
+ Button { onAction(.submit) } label: {
243
+ if state.isLoading {
244
+ ProgressView()
245
+ .tint(.white)
246
+ } else {
247
+ Text("Login")
248
+ .fontWeight(.semibold)
249
+ }
250
+ }
251
+ .frame(maxWidth: .infinity, minHeight: 50)
252
+ .background(Color.accentColor)
253
+ .foregroundColor(.white)
254
+ .cornerRadius(12)
255
+ .disabled(state.isLoading)
256
+
257
+ // Error
258
+ if let error = state.error {
259
+ Text(error)
260
+ .foregroundColor(.red)
261
+ .font(.caption)
262
+ }
263
+ }
264
+ .padding(24)
265
+ }
266
+ }
267
+
268
+ // ===== PREVIEWS =====
269
+ #Preview("Normal") {
270
+ LoginScreenContent(state: .normal)
271
+ }
272
+
273
+ #Preview("Loading") {
274
+ LoginScreenContent(state: .loading)
275
+ }
276
+
277
+ #Preview("Error") {
278
+ LoginScreenContent(state: .error)
279
+ }
280
+ ```
281
+
282
+ ### 2.9: Visual Parity Check ⭐
283
+
284
+ Compare UI shell with original app screenshot:
285
+
286
+ ```markdown
287
+ ### πŸ“Έ Visual Parity: [Screen Name]
288
+
289
+ Layout:
290
+ - [ ] Structure matches original (components, sections)
291
+ - [ ] Spacing between elements correct
292
+ - [ ] Alignment matches
293
+
294
+ Styling:
295
+ - [ ] Colors match (background, text, buttons, header)
296
+ - [ ] Typography matches (font size, weight)
297
+ - [ ] Icons/images correct and positioned
298
+ - [ ] Borders, shadows, rounded corners
299
+
300
+ States:
301
+ - [ ] Normal state displays correctly
302
+ - [ ] Loading state β€” progress in right position
303
+ - [ ] Error state β€” error message shows properly
304
+ - [ ] Empty state β€” guidance shown
305
+
306
+ Platform:
307
+ - [ ] iOS conventions followed (safe area, etc.)
308
+ - [ ] Dynamic Type support
309
+ - [ ] Looks good on different iPhone sizes
310
+ ```
311
+
312
+ ---
313
+
314
+ ## πŸ“Š Output: Feature Blueprint + UI
315
+
316
+ Structured document with contracts + screen screenshots.
317
+
318
+ ---
319
+
320
+ ## βœ… Gate (MANDATORY)
321
+
322
+ ```
323
+ "πŸ“ Blueprint + UI cho [Feature] xong:
324
+
325
+ πŸ“ Contracts:
326
+ - [N] domain models
327
+ - [N] repository protocols
328
+ - [N] use case signatures
329
+ - [N] API endpoints
330
+
331
+ 🎨 UI:
332
+ - [Screen] implemented with mock data
333
+ - Resources: [N] images, [N] strings, [N] colors
334
+ - Previews: [N] states (normal, loading, error, empty)
335
+
336
+ πŸ“Έ Visual Parity: [OK / cαΊ§n chỉnh X, Y, Z]
337
+
338
+ Anh xem UI + contracts α»•n khΓ΄ng?
339
+ β†’ βœ… Approve β†’ Phase 3 (Logic Build)
340
+ β†’ 🎨 Adjust UI β†’ fix then re-check
341
+ β†’ πŸ“ Adjust contracts β†’ revise blueprint"
342
+ ```
343
+
344
+ > ⚠️ **DO NOT proceed to Phase 3 until user approves BOTH UI and contracts.**
345
+
346
+ ---
347
+
348
+ *Phase 2: Blueprint + UI Design β€” See it before you code it*