swift-code-reviewer-skill 1.0.0

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,1131 @@
1
+ # Swift/SwiftUI Code Review Workflow
2
+
3
+ This document provides a detailed, step-by-step workflow for reviewing Swift and SwiftUI code changes. Follow this process to ensure comprehensive, consistent, and actionable code reviews.
4
+
5
+ ## Overview
6
+
7
+ The review workflow consists of four main phases:
8
+ 1. **Context Gathering**: Understand the project and scope
9
+ 2. **Automated Analysis**: Run quality checks across categories
10
+ 3. **Report Generation**: Aggregate and organize findings
11
+ 4. **Delivery**: Present actionable feedback
12
+
13
+ ---
14
+
15
+ ## Phase 1: Context Gathering
16
+
17
+ ### Step 1.1: Read Project-Specific Guidelines
18
+
19
+ **Objective**: Understand the project's coding standards and architecture
20
+
21
+ **Actions:**
22
+
23
+ 1. **Check for .claude/CLAUDE.md**
24
+ ```bash
25
+ # Check if project guidelines exist
26
+ if [ -f .claude/CLAUDE.md ]; then
27
+ echo "Project guidelines found"
28
+ fi
29
+ ```
30
+
31
+ 2. **Read the Guidelines File**
32
+ - Look for sections on:
33
+ - Coding standards
34
+ - Architecture patterns (MVVM, MVI, TCA)
35
+ - Dependency injection approach
36
+ - Error handling patterns
37
+ - Testing requirements
38
+ - Design system guidelines
39
+ - Navigation patterns
40
+
41
+ 3. **Read Related Architecture Documents**
42
+ Common files to check:
43
+ - `.claude/DependencyInjection-Architecture.md`
44
+ - `.claude/Design System Structure.md`
45
+ - `.claude/Navigation-Architecture.md`
46
+ - `.claude/Testing-Guidelines.md`
47
+
48
+ 4. **Extract Key Standards**
49
+ - Custom naming conventions
50
+ - Required property wrappers
51
+ - Error handling patterns
52
+ - ViewModel structure
53
+ - Repository patterns
54
+ - Testing coverage requirements
55
+
56
+ **Example Checklist:**
57
+ ```markdown
58
+ Project Guidelines Summary:
59
+ - Architecture: MVVM with Coordinators
60
+ - DI: Constructor injection preferred
61
+ - State Management: @Observable for ViewModels
62
+ - Error Handling: Result<Success, Error> pattern
63
+ - Testing: Minimum 80% coverage
64
+ - Design System: Use AppColors, AppFonts, AppSpacing
65
+ ```
66
+
67
+ ### Step 1.2: Identify Review Scope
68
+
69
+ **Objective**: Determine which files to review and what changed
70
+
71
+ **Scenarios:**
72
+
73
+ #### Scenario A: Review Pull Request / Merge Request
74
+
75
+ **GitHub (using gh CLI):**
76
+ ```bash
77
+ # Get PR details
78
+ gh pr view 123
79
+
80
+ # Get PR diff
81
+ gh pr diff 123 > pr_changes.diff
82
+
83
+ # List changed files
84
+ gh pr view 123 --json files -q '.files[].path'
85
+
86
+ # Get PR description
87
+ gh pr view 123 --json body -q '.body'
88
+ ```
89
+
90
+ **GitLab (using glab CLI):**
91
+ ```bash
92
+ # Get MR details
93
+ glab mr view 456
94
+
95
+ # Get MR diff
96
+ glab mr diff 456 > mr_changes.diff
97
+
98
+ # List changed files
99
+ glab mr view 456 --json
100
+
101
+ # Get MR description
102
+ glab mr view 456 --json
103
+ ```
104
+
105
+ **What to Extract:**
106
+ - List of changed files
107
+ - Nature of changes (addition, modification, deletion)
108
+ - PR/MR description and context
109
+ - Related issue/ticket numbers
110
+ - Author comments
111
+
112
+ #### Scenario B: Review Uncommitted Changes
113
+
114
+ ```bash
115
+ # Get all uncommitted changes
116
+ git diff > uncommitted_changes.diff
117
+
118
+ # Get staged changes only
119
+ git diff --cached > staged_changes.diff
120
+
121
+ # List modified files
122
+ git diff --name-only
123
+
124
+ # Get status for context
125
+ git status
126
+ ```
127
+
128
+ #### Scenario C: Review Specific Files
129
+
130
+ When user specifies files directly:
131
+ ```bash
132
+ # User says: "Review LoginView.swift and LoginViewModel.swift"
133
+ # Simply read those files
134
+ ```
135
+
136
+ #### Scenario D: Review Specific Directory
137
+
138
+ ```bash
139
+ # User says: "Review all ViewModels in Features/"
140
+ # Find all ViewModel files
141
+ find Features/ -name "*ViewModel.swift"
142
+ ```
143
+
144
+ **Categorize Changes:**
145
+
146
+ After identifying files, categorize by type:
147
+ - **UI Code**: Views, view modifiers, SwiftUI components
148
+ - **Business Logic**: ViewModels, services, use cases
149
+ - **Data Layer**: Repositories, network clients, database
150
+ - **Infrastructure**: Dependency injection, configuration
151
+ - **Tests**: Unit tests, UI tests, integration tests
152
+ - **Build**: Project configuration, build scripts
153
+
154
+ ### Step 1.3: Parse Diff for Context
155
+
156
+ **Objective**: Understand what actually changed in each file
157
+
158
+ **Diff Format:**
159
+ ```diff
160
+ diff --git a/Sources/Features/Login/LoginView.swift b/Sources/Features/Login/LoginView.swift
161
+ index abc123..def456 100644
162
+ --- a/Sources/Features/Login/LoginView.swift
163
+ +++ b/Sources/Features/Login/LoginView.swift
164
+ @@ -15,7 +15,8 @@ struct LoginView: View {
165
+ var body: some View {
166
+ VStack(spacing: 20) {
167
+ - TextField("Username", text: $username)
168
+ + TextField("Email", text: $email)
169
+ + .textInputAutocapitalization(.never)
170
+ }
171
+ }
172
+ }
173
+ ```
174
+
175
+ **Extraction Strategy:**
176
+
177
+ 1. **Identify Changed Lines**
178
+ - Lines starting with `-` are removed
179
+ - Lines starting with `+` are added
180
+ - Lines with context (no prefix) are unchanged
181
+
182
+ 2. **Track Line Numbers**
183
+ - `@@ -15,7 +15,8 @@` means:
184
+ - Original file: 7 lines starting at line 15
185
+ - New file: 8 lines starting at line 15
186
+
187
+ 3. **Group Related Changes**
188
+ - Multiple changes in same function/method
189
+ - Changes that span logical blocks
190
+ - Related changes across files
191
+
192
+ 4. **Determine Change Type**
193
+ - **Addition**: New functionality
194
+ - **Modification**: Behavior change
195
+ - **Deletion**: Removed code
196
+ - **Refactoring**: Structure change, same behavior
197
+ - **Bug Fix**: Error correction
198
+
199
+ ### Step 1.4: Read Files for Full Context
200
+
201
+ **Objective**: Understand the complete file, not just the diff
202
+
203
+ **Why Read Full Files:**
204
+ - Diff doesn't show overall structure
205
+ - Need to understand surrounding code
206
+ - Verify consistency with rest of file
207
+ - Check for patterns used elsewhere
208
+
209
+ **What to Read:**
210
+
211
+ 1. **Changed Files**
212
+ - Read complete file content
213
+ - Understand overall structure
214
+ - Note existing patterns
215
+ - Check for related code
216
+
217
+ 2. **Related Files**
218
+ - Files imported by changed files
219
+ - Files that import changed files
220
+ - Protocol definitions
221
+ - Parent classes or base views
222
+
223
+ **Example:**
224
+ ```swift
225
+ // If reviewing LoginView.swift, also read:
226
+ // - LoginViewModel.swift (referenced in view)
227
+ // - AuthService.swift (used by view model)
228
+ // - FormTextField.swift (component used in view)
229
+ ```
230
+
231
+ ### Step 1.5: Understand Change Purpose
232
+
233
+ **Objective**: Know why the change was made
234
+
235
+ **Sources of Information:**
236
+
237
+ 1. **PR/MR Description**
238
+ - Feature description
239
+ - Problem being solved
240
+ - Implementation approach
241
+
242
+ 2. **Commit Messages**
243
+ ```bash
244
+ # Get commit messages for PR
245
+ gh pr view 123 --json commits -q '.commits[].commit.message'
246
+ ```
247
+
248
+ 3. **Linked Issues/Tickets**
249
+ - User stories
250
+ - Bug reports
251
+ - Technical requirements
252
+
253
+ 4. **Code Comments**
254
+ - New comments explaining changes
255
+ - TODO or FIXME markers
256
+
257
+ **Create a Context Summary:**
258
+ ```markdown
259
+ Change Context:
260
+ - Purpose: Add email validation to login flow
261
+ - Scope: LoginView, LoginViewModel, ValidationService
262
+ - Type: Feature enhancement
263
+ - Risk: Medium (affects authentication flow)
264
+ - Testing: Unit tests added for ValidationService
265
+ ```
266
+
267
+ ---
268
+
269
+ ## Phase 2: Automated Analysis
270
+
271
+ ### Step 2.1: Swift Best Practices Check
272
+
273
+ **Reference**: `swift-best-practices` skill
274
+
275
+ **What to Check:**
276
+
277
+ #### Concurrency Safety
278
+ ```swift
279
+ // ❌ Bad: Mutable state without synchronization
280
+ class ViewModel {
281
+ var data: [Item] = [] // Can be accessed from any thread
282
+ }
283
+
284
+ // ✅ Good: MainActor for UI state
285
+ @MainActor
286
+ class ViewModel: ObservableObject {
287
+ @Published var data: [Item] = []
288
+ }
289
+ ```
290
+
291
+ **Checks:**
292
+ - [ ] All UI-related classes marked with `@MainActor`
293
+ - [ ] Mutable state properly isolated with actors
294
+ - [ ] Sendable conformance for types crossing actor boundaries
295
+ - [ ] No data races (shared mutable state)
296
+ - [ ] Async/await used instead of completion handlers
297
+ - [ ] Structured concurrency (Task, TaskGroup)
298
+
299
+ #### Error Handling
300
+ ```swift
301
+ // ❌ Bad: Force try
302
+ let data = try! decoder.decode(Model.self, from: json)
303
+
304
+ // ✅ Good: Typed throws (Swift 6+)
305
+ func fetchUser() throws(NetworkError) -> User {
306
+ // Implementation
307
+ }
308
+
309
+ // ✅ Good: Result type
310
+ func fetchUser() async -> Result<User, NetworkError> {
311
+ // Implementation
312
+ }
313
+ ```
314
+
315
+ **Checks:**
316
+ - [ ] No `try!` (force try)
317
+ - [ ] Proper error propagation
318
+ - [ ] Typed throws where appropriate
319
+ - [ ] Result type for recoverable errors
320
+ - [ ] Meaningful error messages
321
+
322
+ #### Optionals Handling
323
+ ```swift
324
+ // ❌ Bad: Force unwrap
325
+ let user = userRepository.currentUser!
326
+
327
+ // ✅ Good: Guard or if-let
328
+ guard let user = userRepository.currentUser else {
329
+ logger.error("No current user")
330
+ return
331
+ }
332
+
333
+ // ✅ Good: Optional chaining
334
+ let username = userRepository.currentUser?.name ?? "Guest"
335
+ ```
336
+
337
+ **Checks:**
338
+ - [ ] No force unwrapping (`!`)
339
+ - [ ] No forced casting (`as!`)
340
+ - [ ] Proper optional handling (guard, if-let, nil coalescing)
341
+ - [ ] Optional chaining used appropriately
342
+
343
+ #### Access Control
344
+ ```swift
345
+ // ✅ Good: Explicit access control
346
+ public protocol AuthService {
347
+ func login(email: String, password: String) async throws -> User
348
+ }
349
+
350
+ internal final class DefaultAuthService: AuthService {
351
+ private let networkClient: NetworkClient
352
+ private let tokenStorage: TokenStorage
353
+
354
+ internal init(networkClient: NetworkClient, tokenStorage: TokenStorage) {
355
+ self.networkClient = networkClient
356
+ self.tokenStorage = tokenStorage
357
+ }
358
+ }
359
+ ```
360
+
361
+ **Checks:**
362
+ - [ ] Explicit access control (not relying on defaults)
363
+ - [ ] Private for internal implementation details
364
+ - [ ] Internal for module-level sharing
365
+ - [ ] Public only for API surface
366
+ - [ ] Final classes when inheritance not needed
367
+
368
+ #### Naming Conventions
369
+ ```swift
370
+ // ✅ Good: Swift API Design Guidelines
371
+ func fetchUser(withID id: UUID) async throws -> User
372
+ func validate(email: String) -> Bool
373
+ var isLoading: Bool
374
+ let maximumRetryCount: Int
375
+ ```
376
+
377
+ **Checks:**
378
+ - [ ] Clear, descriptive names
379
+ - [ ] Proper parameter labels (argument labels + parameter names)
380
+ - [ ] Bool properties start with `is`, `has`, `should`
381
+ - [ ] Methods start with verbs
382
+ - [ ] Types use UpperCamelCase
383
+ - [ ] Properties/variables use lowerCamelCase
384
+
385
+ ### Step 2.2: SwiftUI Quality Check
386
+
387
+ **Reference**: `swiftui-expert-skill`
388
+
389
+ #### State Management
390
+ ```swift
391
+ // ✅ Good: @Observable for view models
392
+ @Observable
393
+ final class LoginViewModel {
394
+ var email: String = ""
395
+ var isLoading: Bool = false
396
+
397
+ func login() async {
398
+ // Implementation
399
+ }
400
+ }
401
+
402
+ struct LoginView: View {
403
+ let viewModel: LoginViewModel
404
+
405
+ var body: some View {
406
+ // View updates automatically when viewModel properties change
407
+ }
408
+ }
409
+ ```
410
+
411
+ **Checks:**
412
+ - [ ] @Observable used for view models (iOS 17+)
413
+ - [ ] @State for view-local state
414
+ - [ ] @Binding for two-way bindings
415
+ - [ ] @Environment for dependency injection
416
+ - [ ] No @StateObject with @Observable
417
+ - [ ] No @ObservedObject with @Observable
418
+ - [ ] Correct state ownership
419
+
420
+ #### Property Wrapper Selection Guide
421
+ | Scenario | Property Wrapper |
422
+ |----------|-----------------|
423
+ | View-local state (private to view) | `@State` |
424
+ | Two-way binding from parent | `@Binding` |
425
+ | Observable view model (iOS 17+) | `@Observable` class |
426
+ | Legacy view model (iOS 16-) | `@StateObject` or `@ObservedObject` |
427
+ | Environment dependency | `@Environment` |
428
+ | App-wide shared state | `@Environment` with custom key |
429
+ | UserDefaults-backed | `@AppStorage` |
430
+ | Keychain-backed | Custom property wrapper |
431
+
432
+ **Checks:**
433
+ - [ ] Correct property wrapper for use case
434
+ - [ ] No unnecessary state (derived values computed)
435
+ - [ ] State changes trigger appropriate view updates
436
+ - [ ] No state in static views
437
+
438
+ #### Modern API Usage
439
+ ```swift
440
+ // ❌ Bad: Deprecated API
441
+ .onAppear {
442
+ viewModel.load()
443
+ }
444
+
445
+ // ✅ Good: Modern task modifier
446
+ .task {
447
+ await viewModel.load()
448
+ }
449
+
450
+ // ❌ Bad: GeometryReader for simple cases
451
+ GeometryReader { geometry in
452
+ Text("Hello")
453
+ .frame(width: geometry.size.width)
454
+ }
455
+
456
+ // ✅ Good: Use frame with maxWidth
457
+ Text("Hello")
458
+ .frame(maxWidth: .infinity)
459
+ ```
460
+
461
+ **Checks:**
462
+ - [ ] No deprecated APIs (if modern alternatives exist)
463
+ - [ ] `.task` instead of `.onAppear` for async work
464
+ - [ ] `.onChange` with new syntax (iOS 17+)
465
+ - [ ] `NavigationStack` instead of `NavigationView`
466
+ - [ ] `@Observable` instead of `ObservableObject` (iOS 17+)
467
+ - [ ] Avoid GeometryReader unless necessary
468
+
469
+ #### View Composition
470
+ ```swift
471
+ // ❌ Bad: Monolithic view
472
+ struct LoginView: View {
473
+ var body: some View {
474
+ VStack {
475
+ // 200 lines of UI code
476
+ }
477
+ }
478
+ }
479
+
480
+ // ✅ Good: Extracted subviews
481
+ struct LoginView: View {
482
+ var body: some View {
483
+ VStack {
484
+ LoginHeaderView()
485
+ LoginFormView()
486
+ LoginActionsView()
487
+ }
488
+ }
489
+ }
490
+ ```
491
+
492
+ **Checks:**
493
+ - [ ] View body < 50 lines (guideline)
494
+ - [ ] Logical subviews extracted
495
+ - [ ] Reusable components identified
496
+ - [ ] Proper view hierarchy depth
497
+ - [ ] No excessive nesting (< 5 levels)
498
+
499
+ #### Accessibility
500
+ ```swift
501
+ // ✅ Good: Accessibility support
502
+ TextField("Email", text: $email)
503
+ .accessibilityLabel("Email address")
504
+ .accessibilityHint("Enter your email to log in")
505
+ .textContentType(.emailAddress)
506
+ .keyboardType(.emailAddress)
507
+ .textInputAutocapitalization(.never)
508
+
509
+ Button("Log In") {
510
+ login()
511
+ }
512
+ .accessibilityLabel("Log in button")
513
+ .accessibilityAddTraits(.isButton)
514
+ ```
515
+
516
+ **Checks:**
517
+ - [ ] Accessibility labels for non-text elements
518
+ - [ ] Accessibility hints for complex interactions
519
+ - [ ] Proper traits (button, header, etc.)
520
+ - [ ] Support for Dynamic Type
521
+ - [ ] Keyboard navigation support
522
+ - [ ] VoiceOver tested (if critical UI)
523
+
524
+ ### Step 2.3: Performance Check
525
+
526
+ **Reference**: `swiftui-performance-audit`
527
+
528
+ #### View Optimization
529
+ ```swift
530
+ // ❌ Bad: Heavy computation in body
531
+ struct ItemListView: View {
532
+ let items: [Item]
533
+
534
+ var body: some View {
535
+ let sortedItems = items.sorted { $0.date > $1.date } // ❌ Computed every render
536
+ List(sortedItems) { item in
537
+ ItemRow(item: item)
538
+ }
539
+ }
540
+ }
541
+
542
+ // ✅ Good: Computed property or view model
543
+ struct ItemListView: View {
544
+ let viewModel: ItemListViewModel
545
+
546
+ var body: some View {
547
+ List(viewModel.sortedItems) { item in // ✅ Cached in view model
548
+ ItemRow(item: item)
549
+ }
550
+ }
551
+ }
552
+ ```
553
+
554
+ **Checks:**
555
+ - [ ] No heavy computation in `body`
556
+ - [ ] No synchronous network calls in `body`
557
+ - [ ] No database queries in `body`
558
+ - [ ] Expensive computations cached or memoized
559
+ - [ ] View models have Equatable conformance
560
+
561
+ #### ForEach Performance
562
+ ```swift
563
+ // ❌ Bad: Unstable identity
564
+ List {
565
+ ForEach(items.indices, id: \.self) { index in // ❌ Index-based
566
+ ItemRow(item: items[index])
567
+ }
568
+ }
569
+
570
+ // ✅ Good: Stable identity
571
+ List {
572
+ ForEach(items) { item in // ✅ Using Identifiable
573
+ ItemRow(item: item)
574
+ }
575
+ }
576
+ ```
577
+
578
+ **Checks:**
579
+ - [ ] ForEach uses stable IDs (Identifiable or explicit id)
580
+ - [ ] No index-based iteration when data changes
581
+ - [ ] No array enumerated() in ForEach
582
+ - [ ] Proper identity for animations
583
+
584
+ #### Layout Performance
585
+ ```swift
586
+ // ❌ Bad: Excessive GeometryReader
587
+ GeometryReader { geometry in
588
+ VStack {
589
+ ForEach(items) { item in
590
+ GeometryReader { itemGeometry in // ❌ Nested GeometryReader
591
+ ItemView(item: item, width: itemGeometry.size.width)
592
+ }
593
+ }
594
+ }
595
+ }
596
+
597
+ // ✅ Good: Use layout protocol or simple frames
598
+ VStack {
599
+ ForEach(items) { item in
600
+ ItemView(item: item)
601
+ .frame(maxWidth: .infinity) // ✅ Simple frame
602
+ }
603
+ }
604
+ ```
605
+
606
+ **Checks:**
607
+ - [ ] Minimal GeometryReader usage
608
+ - [ ] No nested GeometryReaders
609
+ - [ ] Layout protocol for custom layouts
610
+ - [ ] Efficient frame calculations
611
+
612
+ #### Resource Management
613
+ ```swift
614
+ // ❌ Bad: Loading large image synchronously
615
+ struct PhotoView: View {
616
+ let imageURL: URL
617
+
618
+ var body: some View {
619
+ if let data = try? Data(contentsOf: imageURL), // ❌ Synchronous load
620
+ let image = UIImage(data: data) {
621
+ Image(uiImage: image)
622
+ }
623
+ }
624
+ }
625
+
626
+ // ✅ Good: Async loading with caching
627
+ struct PhotoView: View {
628
+ let imageURL: URL
629
+
630
+ var body: some View {
631
+ AsyncImage(url: imageURL) { phase in // ✅ Async with built-in caching
632
+ switch phase {
633
+ case .success(let image):
634
+ image.resizable().aspectRatio(contentMode: .fit)
635
+ case .failure:
636
+ Image(systemName: "photo")
637
+ case .empty:
638
+ ProgressView()
639
+ @unknown default:
640
+ EmptyView()
641
+ }
642
+ }
643
+ }
644
+ }
645
+ ```
646
+
647
+ **Checks:**
648
+ - [ ] AsyncImage for remote images
649
+ - [ ] Image caching implemented
650
+ - [ ] No synchronous I/O on main thread
651
+ - [ ] Lazy loading for large lists
652
+ - [ ] Proper memory management (no retain cycles)
653
+
654
+ ### Step 2.4: Security & Safety Check
655
+
656
+ #### Force Unwrap Audit
657
+ ```bash
658
+ # Search for force unwraps
659
+ grep -n "!" *.swift | grep -v "// " # Exclude comments
660
+ grep -n "as!" *.swift
661
+ grep -n "try!" *.swift
662
+ ```
663
+
664
+ **Checks:**
665
+ - [ ] No `!` force unwraps
666
+ - [ ] No `as!` forced casts
667
+ - [ ] No `try!` forced try
668
+ - [ ] Justify exceptions with comments
669
+
670
+ #### Sensitive Data
671
+ ```swift
672
+ // ❌ Bad: Storing password in UserDefaults
673
+ UserDefaults.standard.set(password, forKey: "password")
674
+
675
+ // ✅ Good: Using Keychain
676
+ KeychainService.shared.save(password, forKey: "user_password")
677
+
678
+ // ❌ Bad: Logging sensitive data
679
+ logger.debug("User password: \(password)")
680
+
681
+ // ✅ Good: Sanitized logging
682
+ logger.debug("User logged in successfully")
683
+ ```
684
+
685
+ **Checks:**
686
+ - [ ] No sensitive data in UserDefaults
687
+ - [ ] Keychain used for passwords, tokens
688
+ - [ ] No sensitive data in logs
689
+ - [ ] Secure network communication (HTTPS)
690
+ - [ ] No hardcoded credentials
691
+
692
+ #### Input Validation
693
+ ```swift
694
+ // ✅ Good: Email validation
695
+ func isValid(email: String) -> Bool {
696
+ let emailRegex = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}"
697
+ let predicate = NSPredicate(format: "SELF MATCHES %@", emailRegex)
698
+ return predicate.evaluate(with: email)
699
+ }
700
+
701
+ // ✅ Good: Bounds checking
702
+ func fetchItem(at index: Int) -> Item? {
703
+ guard items.indices.contains(index) else {
704
+ return nil
705
+ }
706
+ return items[index]
707
+ }
708
+ ```
709
+
710
+ **Checks:**
711
+ - [ ] User input validated
712
+ - [ ] Bounds checking for array access
713
+ - [ ] Type safety enforced
714
+ - [ ] SQL injection prevention (if using SQL)
715
+ - [ ] XSS prevention (if rendering web content)
716
+
717
+ ### Step 2.5: Architecture & Maintainability Check
718
+
719
+ #### Project Architecture Compliance
720
+ ```swift
721
+ // Example: MVVM Pattern
722
+
723
+ // ✅ Good: Clear separation
724
+ // View - Presentation only
725
+ struct LoginView: View {
726
+ let viewModel: LoginViewModel
727
+
728
+ var body: some View {
729
+ // UI only, no business logic
730
+ }
731
+ }
732
+
733
+ // ViewModel - Business logic
734
+ @Observable
735
+ final class LoginViewModel {
736
+ private let authService: AuthService
737
+
738
+ var email: String = ""
739
+ var isLoading: Bool = false
740
+
741
+ func login() async {
742
+ // Business logic
743
+ }
744
+ }
745
+
746
+ // Service - Data operations
747
+ protocol AuthService {
748
+ func login(email: String, password: String) async throws -> User
749
+ }
750
+ ```
751
+
752
+ **Checks:**
753
+ - [ ] Follows project architecture (MVVM, MVI, TCA)
754
+ - [ ] Clear layer separation (View/ViewModel/Service)
755
+ - [ ] No business logic in views
756
+ - [ ] No UI code in view models
757
+ - [ ] Dependency injection used
758
+ - [ ] Protocol-oriented design
759
+
760
+ #### Code Organization
761
+ ```swift
762
+ // ✅ Good: Organized with extensions
763
+ struct LoginView: View {
764
+ // MARK: - Properties
765
+ let viewModel: LoginViewModel
766
+
767
+ // MARK: - Body
768
+ var body: some View {
769
+ // Implementation
770
+ }
771
+ }
772
+
773
+ // MARK: - Subviews
774
+ private extension LoginView {
775
+ var headerView: some View {
776
+ // Implementation
777
+ }
778
+ }
779
+
780
+ // MARK: - Actions
781
+ private extension LoginView {
782
+ func handleLogin() {
783
+ // Implementation
784
+ }
785
+ }
786
+ ```
787
+
788
+ **Checks:**
789
+ - [ ] Logical file organization
790
+ - [ ] MARK comments for sections
791
+ - [ ] Extensions for protocol conformances
792
+ - [ ] Private extensions for private members
793
+ - [ ] Consistent file structure across project
794
+
795
+ #### Testability
796
+ ```swift
797
+ // ✅ Good: Testable design
798
+ protocol AuthService {
799
+ func login(email: String, password: String) async throws -> User
800
+ }
801
+
802
+ final class LoginViewModel {
803
+ private let authService: AuthService // ✅ Protocol for mocking
804
+
805
+ init(authService: AuthService) {
806
+ self.authService = authService
807
+ }
808
+ }
809
+
810
+ // Test
811
+ final class LoginViewModelTests: XCTestCase {
812
+ func testLogin() async throws {
813
+ let mockAuthService = MockAuthService() // ✅ Easy to mock
814
+ let viewModel = LoginViewModel(authService: mockAuthService)
815
+ // Test
816
+ }
817
+ }
818
+ ```
819
+
820
+ **Checks:**
821
+ - [ ] Dependencies are protocols (mockable)
822
+ - [ ] Constructor injection used
823
+ - [ ] No singletons (or testable singletons)
824
+ - [ ] Pure functions where possible
825
+ - [ ] Tests exist for critical paths
826
+
827
+ ### Step 2.6: Project-Specific Standards Check
828
+
829
+ **Load Custom Guidelines:**
830
+ 1. Read `.claude/CLAUDE.md`
831
+ 2. Extract project-specific rules
832
+ 3. Validate code against custom patterns
833
+
834
+ **Common Custom Standards:**
835
+
836
+ #### Example: Custom Error Handling
837
+ ```swift
838
+ // Project standard: All errors must conform to AppError
839
+ protocol AppError: Error {
840
+ var message: String { get }
841
+ var code: Int { get }
842
+ }
843
+
844
+ // ✅ Good: Follows project standard
845
+ enum LoginError: AppError {
846
+ case invalidCredentials
847
+ case networkFailure
848
+
849
+ var message: String {
850
+ switch self {
851
+ case .invalidCredentials: return "Invalid email or password"
852
+ case .networkFailure: return "Network connection failed"
853
+ }
854
+ }
855
+
856
+ var code: Int {
857
+ switch self {
858
+ case .invalidCredentials: return 1001
859
+ case .networkFailure: return 2001
860
+ }
861
+ }
862
+ }
863
+ ```
864
+
865
+ **Checks:**
866
+ - [ ] Custom error protocol conformance
867
+ - [ ] Project naming conventions
868
+ - [ ] Required ViewParsing patterns
869
+ - [ ] Design system usage (colors, fonts, spacing)
870
+ - [ ] Navigation patterns
871
+ - [ ] Testing coverage requirements
872
+
873
+ ---
874
+
875
+ ## Phase 3: Report Generation
876
+
877
+ ### Step 3.1: Categorize Findings
878
+
879
+ **Severity Levels:**
880
+
881
+ #### Critical
882
+ - Security vulnerabilities
883
+ - Data races and concurrency issues
884
+ - Force unwraps that can crash
885
+ - Memory leaks
886
+ - Breaking API changes
887
+
888
+ #### High
889
+ - Performance problems (O(n²) algorithms, excessive renders)
890
+ - Anti-patterns (improper state management, retain cycles)
891
+ - Major architecture violations
892
+ - Missing error handling
893
+
894
+ #### Medium
895
+ - Code quality issues (complex methods, duplication)
896
+ - Missing documentation
897
+ - Minor architecture inconsistencies
898
+ - Accessibility gaps
899
+
900
+ #### Low
901
+ - Style inconsistencies
902
+ - Naming improvements
903
+ - Refactoring suggestions
904
+ - Minor optimizations
905
+
906
+ ### Step 3.2: Include Positive Feedback
907
+
908
+ **Acknowledge Good Practices:**
909
+ ```markdown
910
+ ✅ **Excellent State Management** (LoginView.swift:23)
911
+ - Proper use of @Observable for view model
912
+ - Clean separation of concerns
913
+ - Immutable state design
914
+ ```
915
+
916
+ **Types of Positive Feedback:**
917
+ - Modern API adoption
918
+ - Strong architecture adherence
919
+ - Excellent test coverage
920
+ - Clear documentation
921
+ - Performance optimizations
922
+ - Security best practices
923
+
924
+ ### Step 3.3: Add Refactoring Suggestions
925
+
926
+ **Proactive Improvements:**
927
+ ```markdown
928
+ 💡 **Consider Extracting Subview** (LoginView.swift:45-78)
929
+ - The login form could be extracted into a reusable component
930
+ - Benefits: Better testability, improved reusability
931
+ - Suggested: Create `LoginFormView` component
932
+ ```
933
+
934
+ ### Step 3.4: Organize by File and Category
935
+
936
+ **Structure:**
937
+ ```markdown
938
+ ## File: LoginView.swift
939
+
940
+ ### ✅ Positive Feedback
941
+ 1. [positive item]
942
+
943
+ ### 🔴 Critical Issues
944
+ 1. [critical item]
945
+
946
+ ### 🟡 High Priority
947
+ 1. [high item]
948
+
949
+ ### 🟠 Medium Priority
950
+ 1. [medium item]
951
+
952
+ ### 🔵 Low Priority
953
+ 1. [low item]
954
+
955
+ ### 💡 Refactoring Suggestions
956
+ 1. [suggestion item]
957
+ ```
958
+
959
+ ---
960
+
961
+ ## Phase 4: Delivery
962
+
963
+ ### Step 4.1: Generate Summary
964
+
965
+ ```markdown
966
+ # Code Review Report
967
+
968
+ ## Summary
969
+ - **Files Reviewed**: 5
970
+ - **Total Findings**: 15
971
+ - **Critical**: 1
972
+ - **High**: 3
973
+ - **Medium**: 6
974
+ - **Low**: 5
975
+ - **Positive Feedback**: 12
976
+ - **Refactoring Suggestions**: 4
977
+
978
+ ## Executive Summary
979
+ This PR adds email validation to the login flow. Overall code quality is good
980
+ with modern SwiftUI patterns and proper architecture. One critical concurrency
981
+ issue must be fixed before merge. Several opportunities for performance
982
+ optimization identified.
983
+ ```
984
+
985
+ ### Step 4.2: Format with Code Examples
986
+
987
+ **Before/After Examples:**
988
+ ```markdown
989
+ #### 🔴 Data Race Risk (LoginViewModel.swift:45)
990
+ **Severity**: Critical
991
+ **Category**: Concurrency
992
+
993
+ **Issue**: Mutable state accessed without synchronization
994
+
995
+ **Current Code:**
996
+ ```swift
997
+ class LoginViewModel {
998
+ var isLoading = false // ❌ Can be accessed from any thread
999
+ }
1000
+ ```
1001
+
1002
+ **Recommended Fix:**
1003
+ ```swift
1004
+ @MainActor
1005
+ class LoginViewModel: ObservableObject {
1006
+ @Published var isLoading = false // ✅ MainActor-isolated
1007
+ }
1008
+ ```
1009
+
1010
+ **Reference**: swift-best-practices/references/concurrency.md
1011
+ ```
1012
+
1013
+ ### Step 4.3: Provide Actionable Items
1014
+
1015
+ ```markdown
1016
+ ## Prioritized Action Items
1017
+
1018
+ ### Must Fix (Before Merge)
1019
+ - [ ] Fix data race in LoginViewModel.swift:45
1020
+ - [ ] Remove force unwrap in LoginView.swift:89
1021
+
1022
+ ### Should Fix (This Sprint)
1023
+ - [ ] Add documentation to AuthService protocol
1024
+ - [ ] Improve error handling in NetworkClient.swift
1025
+ - [ ] Add unit tests for ValidationService
1026
+
1027
+ ### Consider (Future)
1028
+ - [ ] Extract login form into separate view
1029
+ - [ ] Implement retry logic for network failures
1030
+ - [ ] Add loading states for better UX
1031
+ ```
1032
+
1033
+ ---
1034
+
1035
+ ## Tips for Effective Reviews
1036
+
1037
+ ### Do's
1038
+ ✅ Read project guidelines first
1039
+ ✅ Understand the context and purpose
1040
+ ✅ Provide balanced feedback (positive + negative)
1041
+ ✅ Be specific with file:line references
1042
+ ✅ Include code examples for fixes
1043
+ ✅ Explain *why* something is an issue
1044
+ ✅ Prioritize by severity
1045
+ ✅ Suggest improvements, not just problems
1046
+ ✅ Link to documentation and resources
1047
+
1048
+ ### Don'ts
1049
+ ❌ Review without reading .claude/CLAUDE.md
1050
+ ❌ Only provide criticism (no positive feedback)
1051
+ ❌ Be vague ("this could be better")
1052
+ ❌ Nitpick style without real impact
1053
+ ❌ Ignore project-specific standards
1054
+ ❌ Review code you haven't read completely
1055
+ ❌ Suggest fixes without examples
1056
+
1057
+ ---
1058
+
1059
+ ## Appendix: Git Commands Reference
1060
+
1061
+ ### Common Git Operations
1062
+
1063
+ ```bash
1064
+ # View diff
1065
+ git diff # Uncommitted changes
1066
+ git diff --cached # Staged changes
1067
+ git diff HEAD~1 # Last commit
1068
+ git diff branch1..branch2 # Between branches
1069
+
1070
+ # View specific file diff
1071
+ git diff path/to/file.swift
1072
+
1073
+ # View commit
1074
+ git show <commit-hash>
1075
+
1076
+ # View file at specific commit
1077
+ git show <commit-hash>:path/to/file.swift
1078
+
1079
+ # List changed files
1080
+ git diff --name-only
1081
+ git diff --name-status # With status (M, A, D)
1082
+
1083
+ # View log
1084
+ git log --oneline
1085
+ git log --graph --oneline --all
1086
+
1087
+ # View file history
1088
+ git log --follow -- path/to/file.swift
1089
+ ```
1090
+
1091
+ ### GitHub CLI (gh)
1092
+
1093
+ ```bash
1094
+ # View PR
1095
+ gh pr view 123
1096
+ gh pr view 123 --json title,body,files
1097
+
1098
+ # View PR diff
1099
+ gh pr diff 123
1100
+
1101
+ # View PR checks
1102
+ gh pr checks 123
1103
+
1104
+ # List PR files
1105
+ gh pr view 123 --json files -q '.files[].path'
1106
+
1107
+ # View PR comments
1108
+ gh pr view 123 --json comments
1109
+ ```
1110
+
1111
+ ### GitLab CLI (glab)
1112
+
1113
+ ```bash
1114
+ # View MR
1115
+ glab mr view 456
1116
+
1117
+ # View MR diff
1118
+ glab mr diff 456
1119
+
1120
+ # List MR files
1121
+ glab mr view 456 --json
1122
+
1123
+ # View MR notes
1124
+ glab mr note list 456
1125
+ ```
1126
+
1127
+ ---
1128
+
1129
+ ## Version
1130
+ **Last Updated**: 2026-02-10
1131
+ **Version**: 1.0.0