swift-code-reviewer-skill 1.0.0 → 1.1.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.
package/CHANGELOG.md CHANGED
@@ -157,6 +157,12 @@ Provided complete examples for:
157
157
  - File-specific reviews
158
158
  - Multi-file reviews
159
159
 
160
+ ## [1.1.0] - 2026-03-16
161
+
162
+ ### Added
163
+
164
+ - increase adjusts from Dimillian skill and more scenarios to cover
165
+
160
166
  ## [Unreleased]
161
167
 
162
168
  ### Planned Features
@@ -181,6 +187,7 @@ Provided complete examples for:
181
187
 
182
188
  ## Version History Summary
183
189
 
190
+ - **1.1.0** (2026-03-16): Increase adjusts from Dimillian skill and more scenarios to cover
184
191
  - **1.0.0** (2026-02-10): Initial release with comprehensive review capabilities
185
192
 
186
193
  ---
package/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # Swift Code Reviewer Agent Skill
2
2
 
3
+ [![GitHub Sponsors](https://img.shields.io/github/sponsors/Viniciuscarvalho?style=social)](https://github.com/sponsors/Viniciuscarvalho)
4
+
3
5
  A comprehensive code review skill for Claude that performs multi-layer analysis of Swift and SwiftUI code, combining Apple's best practices with project-specific coding standards.
4
6
 
5
7
  ## Features
@@ -14,6 +16,7 @@ A comprehensive code review skill for Claude that performs multi-layer analysis
14
16
  ## What It Reviews
15
17
 
16
18
  ### Swift Quality
19
+
17
20
  - **Concurrency Safety**: Actor isolation, MainActor usage, Sendable conformance, data race prevention
18
21
  - **Error Handling**: Typed throws, Result types, proper error propagation
19
22
  - **Optionals**: Safe unwrapping, guard statements, no force unwraps
@@ -21,6 +24,7 @@ A comprehensive code review skill for Claude that performs multi-layer analysis
21
24
  - **Naming**: Swift API Design Guidelines compliance
22
25
 
23
26
  ### SwiftUI Patterns
27
+
24
28
  - **State Management**: @Observable, @State, @Binding, @Environment usage
25
29
  - **Property Wrappers**: Correct wrapper selection for each use case
26
30
  - **Modern APIs**: NavigationStack, .task, latest SwiftUI features
@@ -28,24 +32,28 @@ A comprehensive code review skill for Claude that performs multi-layer analysis
28
32
  - **Accessibility**: Labels, hints, Dynamic Type support
29
33
 
30
34
  ### Performance
35
+
31
36
  - **View Optimization**: Unnecessary updates, Equatable conformance
32
37
  - **ForEach Performance**: Stable identity, lazy loading
33
38
  - **Layout Efficiency**: GeometryReader usage, layout thrash
34
39
  - **Resource Management**: Image loading, memory leaks, async patterns
35
40
 
36
41
  ### Security & Safety
42
+
37
43
  - **Input Validation**: Sanitization, bounds checking, type safety
38
44
  - **Sensitive Data**: Keychain storage, biometric authentication, secure logging
39
45
  - **Network Security**: HTTPS enforcement, certificate pinning, API key protection
40
46
  - **Permissions**: Privacy descriptions, permission timing, graceful handling
41
47
 
42
48
  ### Architecture
49
+
43
50
  - **Pattern Compliance**: MVVM, MVI, TCA adherence
44
51
  - **Dependency Injection**: Constructor injection, protocol-based dependencies
45
52
  - **Code Organization**: File structure, MARK comments, logical grouping
46
53
  - **Testability**: Unit test coverage, mock usage, test structure
47
54
 
48
55
  ### Project Standards
56
+
49
57
  - **Custom Guidelines**: Validates against `.claude/CLAUDE.md` rules
50
58
  - **Design System**: Color palette, typography, spacing token usage
51
59
  - **Error Patterns**: Custom error type conformance
@@ -55,7 +63,7 @@ A comprehensive code review skill for Claude that performs multi-layer analysis
55
63
 
56
64
  ### Option 1: NPX (Recommended)
57
65
 
58
- The fastest way to install - no cloning required:
66
+ The fastest way to install always fetches the latest version, no cloning or manual updates required:
59
67
 
60
68
  ```bash
61
69
  npx swift-code-reviewer-skill
@@ -63,6 +71,8 @@ npx swift-code-reviewer-skill
63
71
 
64
72
  This automatically installs the skill to `~/.claude/skills/swift-code-reviewer-skill/`
65
73
 
74
+ > **Tip:** Running `npx swift-code-reviewer-skill` again at any time will update to the latest version automatically.
75
+
66
76
  To uninstall:
67
77
 
68
78
  ```bash
@@ -81,6 +91,7 @@ git clone https://github.com/Viniciuscarvalho/swift-code-reviewer-skill.git ~/.c
81
91
  ### Option 3: Manual Installation
82
92
 
83
93
  1. Create the skill directory:
94
+
84
95
  ```bash
85
96
  mkdir -p ~/.claude/skills/swift-code-reviewer-skill/references
86
97
  ```
@@ -98,6 +109,8 @@ ls ~/.claude/skills/swift-code-reviewer-skill/
98
109
 
99
110
  ## Usage
100
111
 
112
+ ![Swift Code Reviewer in action](assets/demo.png)
113
+
101
114
  ### Basic Usage
102
115
 
103
116
  The skill automatically activates when you ask Claude to review Swift/SwiftUI code:
@@ -119,6 +132,7 @@ Review UserProfileView.swift
119
132
  ```
120
133
 
121
134
  **What it does:**
135
+
122
136
  1. Reads `.claude/CLAUDE.md` for project standards
123
137
  2. Analyzes the file against all quality dimensions
124
138
  3. Provides structured feedback with severity levels
@@ -131,6 +145,7 @@ Review my uncommitted changes
131
145
  ```
132
146
 
133
147
  **What it does:**
148
+
134
149
  1. Runs `git diff` to identify changes
135
150
  2. Analyzes modified files
136
151
  3. Focuses on changed lines for efficiency
@@ -143,6 +158,7 @@ Review PR #123
143
158
  ```
144
159
 
145
160
  **What it does:**
161
+
146
162
  1. Fetches PR details using `gh pr view 123`
147
163
  2. Gets diff using `gh pr diff 123`
148
164
  3. Reads all changed files for context
@@ -155,6 +171,7 @@ Review MR #456
155
171
  ```
156
172
 
157
173
  **What it does:**
174
+
158
175
  1. Fetches MR details using `glab mr view 456`
159
176
  2. Gets diff and changed files
160
177
  3. Performs multi-layer analysis
@@ -167,6 +184,7 @@ Review LoginViewModel.swift against our coding standards
167
184
  ```
168
185
 
169
186
  **What it does:**
187
+
170
188
  1. Reads `.claude/CLAUDE.md` and related architecture docs
171
189
  2. Extracts project-specific rules
172
190
  3. Validates code against both Apple and project standards
@@ -179,6 +197,7 @@ Review all ViewModels in the Features folder
179
197
  ```
180
198
 
181
199
  **What it does:**
200
+
182
201
  1. Finds all matching files
183
202
  2. Analyzes each against architecture patterns
184
203
  3. Provides file-by-file review
@@ -254,6 +273,7 @@ Generates a structured markdown report:
254
273
  # Code Review Report
255
274
 
256
275
  ## Summary
276
+
257
277
  - Files Reviewed: 5
258
278
  - Critical: 0
259
279
  - High: 2
@@ -266,15 +286,19 @@ Generates a structured markdown report:
266
286
  ### File: LoginView.swift
267
287
 
268
288
  #### ✅ Positive Feedback
289
+
269
290
  1. Excellent use of @Observable for state management
270
291
 
271
292
  #### 🟡 High Priority
293
+
272
294
  1. Force unwrap detected at line 89 (potential crash)
273
295
 
274
296
  #### 💡 Refactoring Suggestions
297
+
275
298
  1. Consider extracting login form into separate view
276
299
 
277
300
  ## Prioritized Action Items
301
+
278
302
  [Must fix, should fix, consider items]
279
303
  ```
280
304
 
@@ -282,27 +306,30 @@ Generates a structured markdown report:
282
306
 
283
307
  ### Severity Levels
284
308
 
285
- | Severity | Icon | Description | Response Time |
286
- |----------|------|-------------|---------------|
287
- | **Critical** | 🔴 | Security vulnerabilities, crashes, data races | Must fix before merge |
288
- | **High** | 🟡 | Performance issues, anti-patterns, major violations | Should fix before merge |
289
- | **Medium** | 🟠 | Code quality, documentation, minor violations | Fix in current sprint |
290
- | **Low** | 🔵 | Style, suggestions, minor improvements | Consider for future |
309
+ | Severity | Icon | Description | Response Time |
310
+ | ------------ | ---- | --------------------------------------------------- | ----------------------- |
311
+ | **Critical** | 🔴 | Security vulnerabilities, crashes, data races | Must fix before merge |
312
+ | **High** | 🟡 | Performance issues, anti-patterns, major violations | Should fix before merge |
313
+ | **Medium** | 🟠 | Code quality, documentation, minor violations | Fix in current sprint |
314
+ | **Low** | 🔵 | Style, suggestions, minor improvements | Consider for future |
291
315
 
292
316
  ### Feedback Types
293
317
 
294
318
  **Positive Feedback** ✅
319
+
295
320
  - Acknowledges good practices
296
321
  - Highlights excellent implementations
297
322
  - Recognizes proper patterns
298
323
 
299
324
  **Issues** 🔴🟡🟠🔵
325
+
300
326
  - File and line references
301
327
  - Code examples (before/after)
302
328
  - Specific fixes with explanations
303
329
  - Links to documentation
304
330
 
305
331
  **Refactoring Suggestions** 💡
332
+
306
333
  - Proactive improvements
307
334
  - Modernization opportunities
308
335
  - Code simplification ideas
@@ -321,32 +348,40 @@ The skill reads `.claude/CLAUDE.md` to understand your project's:
321
348
 
322
349
  ### Example .claude/CLAUDE.md
323
350
 
324
- ```markdown
351
+ ````markdown
325
352
  # MyApp Coding Standards
326
353
 
327
354
  ## Architecture
355
+
328
356
  We use **MVVM with Coordinators**:
357
+
329
358
  - ViewModels MUST use @Observable (iOS 17+)
330
359
  - All dependencies MUST be injected via constructor
331
360
  - Views MUST NOT contain business logic
332
361
 
333
362
  ## Error Handling
363
+
334
364
  All errors MUST conform to AppError:
365
+
335
366
  ```swift
336
367
  protocol AppError: Error {
337
368
  var message: String { get }
338
369
  var code: Int { get }
339
370
  }
340
371
  ```
372
+ ````
341
373
 
342
374
  ## Design System
375
+
343
376
  - Use AppColors enum ONLY
344
377
  - Use AppFonts enum ONLY
345
378
  - Use AppSpacing for all padding
346
379
 
347
380
  ## Testing
381
+
348
382
  - Minimum coverage: 80%
349
383
  - All ViewModels MUST have unit tests
384
+
350
385
  ```
351
386
 
352
387
  The skill will validate your code against these standards and report violations.
@@ -391,8 +426,10 @@ For performance analysis
391
426
 
392
427
  **Input:**
393
428
  ```
429
+
394
430
  Review my uncommitted changes
395
- ```
431
+
432
+ ````
396
433
 
397
434
  **Output:**
398
435
  ```markdown
@@ -419,23 +456,27 @@ Review my uncommitted changes
419
456
  Current Code:
420
457
  ```swift
421
458
  let user = repository.currentUser!
422
- ```
459
+ ````
423
460
 
424
461
  Recommended Fix:
462
+
425
463
  ```swift
426
464
  guard let user = repository.currentUser else {
427
465
  logger.error("No current user")
428
466
  return
429
467
  }
430
468
  ```
469
+
431
470
  ```
432
471
 
433
472
  ### Example 2: Review Against Project Standards
434
473
 
435
474
  **Input:**
436
475
  ```
476
+
437
477
  Review LoginView.swift against our coding standards
438
- ```
478
+
479
+ ````
439
480
 
440
481
  **Output:**
441
482
  ```markdown
@@ -454,14 +495,16 @@ Review LoginView.swift against our coding standards
454
495
  Current Code:
455
496
  ```swift
456
497
  .foregroundColor(.blue) // ❌ Hardcoded
457
- ```
498
+ ````
458
499
 
459
500
  Expected Code:
501
+
460
502
  ```swift
461
503
  .foregroundColor(AppColors.primary) // ✅ Design system
462
504
  ```
463
505
 
464
506
  Reference: .claude/CLAUDE.md:Design System
507
+
465
508
  ```
466
509
 
467
510
  ## Requirements
@@ -534,3 +577,4 @@ MIT License - See [LICENSE](LICENSE) file for details
534
577
  **Made with ❤️ for the Swift community**
535
578
 
536
579
  If this skill helps improve your code reviews, please ⭐️ star the repository!
580
+ ```
package/SKILL.md CHANGED
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: swift-code-reviewer
3
- description: Perform thorough code reviews for Swift/SwiftUI code, analyzing code quality, architecture, performance, security, and adherence to Swift 6+ best practices, SwiftUI patterns, iOS/macOS platform guidelines, and project-specific coding standards from .claude/CLAUDE.md. Use when reviewing code changes, performing quality audits, or providing structured feedback on Swift codebases with all severity levels and positive feedback.
3
+ description: Perform thorough code reviews for Swift/SwiftUI code, analyzing code quality, architecture, performance, security, and adherence to Swift 6+ best practices, SwiftUI patterns, navigation architecture, sheet routing, theming, async state, iOS/macOS platform guidelines, and project-specific coding standards from .claude/CLAUDE.md. Use when reviewing code changes, performing quality audits, or providing structured feedback on Swift codebases with all severity levels and positive feedback.
4
4
  ---
5
5
 
6
6
  # Swift/SwiftUI Code Review Skill
@@ -389,6 +389,23 @@ This skill **references** (not duplicates) three foundational skills for domain
389
389
  - Reference performance-specific checks when reviewing view code
390
390
  - Apply recommendations from the skill to performance-sensitive paths
391
391
 
392
+ ### 4. swiftui-ui-patterns
393
+ **When to Use:** Reviewing navigation architecture, sheet/modal routing, TabView setup, theming, async state management, focus handling, or API client patterns
394
+
395
+ **What it Provides:**
396
+ - Navigation architecture (route enums, RouterPath, centralized navigationDestination)
397
+ - Sheet/modal routing (item-driven sheets, SheetDestination enum)
398
+ - TabView with independent per-tab navigation history
399
+ - Theming with semantic colors via `@Environment(Theme.self)`
400
+ - Async state patterns (`.task(id:)`, LoadState enum, CancellationError handling)
401
+ - Focus chaining with FocusField enum and `.onSubmit`
402
+ - Lightweight API client pattern (closure-based structs, `.live()` / `.mock()` factories)
403
+
404
+ **How to Leverage:**
405
+ - Read `~/.claude/skills/swiftui-ui-patterns/references/navigation.md` for route enum and RouterPath checks
406
+ - Reference `sheets-modals.md` for sheet routing validation
407
+ - Use `theming.md` for semantic color enforcement
408
+
392
409
  **Integration Strategy:**
393
410
  1. Load relevant reference files from these skills as needed
394
411
  2. Apply their checklist items to the review
@@ -619,6 +636,29 @@ Steps:
619
636
  5. Summarize common patterns and issues across all files
620
637
  ```
621
638
 
639
+ ### Example 6: Review Navigation / Routing Code
640
+ ```
641
+ User: "Review our navigation setup and routing code"
642
+
643
+ Steps:
644
+ 1. Read .claude/CLAUDE.md for project navigation patterns
645
+ 2. Read router/coordinator files (RouterPath, AppCoordinator, TabRouter)
646
+ 3. Read root views that set up NavigationStack and TabView
647
+ 4. Run navigation architecture checks:
648
+ - Route destinations use typed Hashable enum (not String/Int)
649
+ - RouterPath @Observable owns path (not ad-hoc @State)
650
+ - Single centralized .navigationDestination per stack
651
+ - .sheet(item:) preferred over .sheet(isPresented:) when model selected
652
+ - Multiple sheets use SheetDestination enum (not multiple booleans)
653
+ - Each tab has independent RouterPath (not shared)
654
+ - .onOpenURL at app root, not scattered in feature views
655
+ 5. Run async state checks:
656
+ - .task(id:) for input-driven async work
657
+ - CancellationError silenced
658
+ - LoadState<T> enum instead of multiple booleans
659
+ 6. Generate report with navigation-specific findings
660
+ ```
661
+
622
662
  ## Resources
623
663
 
624
664
  This skill includes the following reference materials:
@@ -685,6 +725,6 @@ For runtime analysis, recommend using Instruments or other profiling tools.
685
725
 
686
726
  ## Version
687
727
 
688
- **Version**: 1.0.0
689
- **Last Updated**: 2026-02-10
728
+ **Version**: 1.1.0
729
+ **Last Updated**: 2026-03-16
690
730
  **Compatible with**: Swift 6+, SwiftUI (iOS 17+, macOS 14+, watchOS 10+, tvOS 17+, visionOS 1+)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "swift-code-reviewer-skill",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "description": "Claude Code skill for comprehensive Swift/SwiftUI code reviews with multi-layer analysis",
5
5
  "keywords": [
6
6
  "claude",
@@ -593,6 +593,281 @@ struct UserListView: View {
593
593
 
594
594
  ---
595
595
 
596
+ ## 5A. Lightweight Client Pattern (Closure-Based)
597
+
598
+ ### 5A.1 Overview
599
+
600
+ **Purpose**: Define API clients as value-type structs with async closure properties, enabling easy swapping between live and mock implementations — especially for SwiftUI previews.
601
+
602
+ **Benefits:**
603
+ - Preview-friendly (no network calls in Xcode Previews)
604
+ - Testable without subclassing or protocol mocking boilerplate
605
+ - Composable: clients can be scoped per-feature
606
+ - No shared mutable singleton state
607
+
608
+ ### 5A.2 Implementation Pattern
609
+
610
+ **Check for:**
611
+ - [ ] API client defined as a `struct` with `async` closure properties (not a singleton class)
612
+ - [ ] Static factory `.live(baseURL:)` for production
613
+ - [ ] Static factory `.mock(...)` for previews and tests
614
+ - [ ] Store (`@Observable`) holds the client; views never call the client directly
615
+ - [ ] Client injected via `@Environment` or constructor
616
+
617
+ **Examples:**
618
+
619
+ ❌ **Bad: Singleton class client**
620
+ ```swift
621
+ final class UserAPIClient {
622
+ static let shared = UserAPIClient() // ❌ Singleton — untestable, preview-unfriendly
623
+
624
+ func fetchUser(id: UUID) async throws -> User {
625
+ let url = URL(string: "https://api.example.com/users/\(id)")!
626
+ let (data, _) = try await URLSession.shared.data(from: url)
627
+ return try JSONDecoder().decode(User.self, from: data)
628
+ }
629
+ }
630
+
631
+ final class UserViewModel {
632
+ func loadUser(id: UUID) async {
633
+ let user = try await UserAPIClient.shared.fetchUser(id: id) // ❌ Hard dependency
634
+ }
635
+ }
636
+ ```
637
+
638
+ ✅ **Good: Struct with closure properties**
639
+ ```swift
640
+ // Client defined as a struct with closure properties
641
+ struct UserAPIClient {
642
+ var fetchUser: (UUID) async throws -> User
643
+ var updateUser: (User) async throws -> User
644
+ var deleteUser: (UUID) async throws -> Void
645
+ }
646
+
647
+ // Live implementation
648
+ extension UserAPIClient {
649
+ static func live(baseURL: URL) -> Self {
650
+ UserAPIClient(
651
+ fetchUser: { id in
652
+ let url = baseURL.appendingPathComponent("users/\(id)")
653
+ let (data, _) = try await URLSession.shared.data(from: url)
654
+ return try JSONDecoder().decode(User.self, from: data)
655
+ },
656
+ updateUser: { user in
657
+ var request = URLRequest(url: baseURL.appendingPathComponent("users/\(user.id)"))
658
+ request.httpMethod = "PUT"
659
+ request.httpBody = try JSONEncoder().encode(user)
660
+ let (data, _) = try await URLSession.shared.data(for: request)
661
+ return try JSONDecoder().decode(User.self, from: data)
662
+ },
663
+ deleteUser: { id in
664
+ var request = URLRequest(url: baseURL.appendingPathComponent("users/\(id)"))
665
+ request.httpMethod = "DELETE"
666
+ _ = try await URLSession.shared.data(for: request)
667
+ }
668
+ )
669
+ }
670
+ }
671
+
672
+ // Mock implementation for previews and tests
673
+ extension UserAPIClient {
674
+ static func mock(
675
+ fetchUser: @escaping (UUID) async throws -> User = { _ in .mock },
676
+ updateUser: @escaping (User) async throws -> User = { $0 },
677
+ deleteUser: @escaping (UUID) async throws -> Void = { _ in }
678
+ ) -> Self {
679
+ UserAPIClient(
680
+ fetchUser: fetchUser,
681
+ updateUser: updateUser,
682
+ deleteUser: deleteUser
683
+ )
684
+ }
685
+ }
686
+
687
+ // Store holds the client — views never call it directly
688
+ @MainActor
689
+ @Observable
690
+ final class UserStore {
691
+ private let client: UserAPIClient
692
+ private(set) var user: User?
693
+ private(set) var isLoading = false
694
+
695
+ init(client: UserAPIClient) {
696
+ self.client = client
697
+ }
698
+
699
+ func loadUser(id: UUID) async {
700
+ isLoading = true
701
+ defer { isLoading = false }
702
+ user = try? await client.fetchUser(id)
703
+ }
704
+ }
705
+
706
+ // View uses Store, not Client directly
707
+ struct UserProfileView: View {
708
+ let store: UserStore
709
+
710
+ var body: some View {
711
+ Group {
712
+ if let user = store.user {
713
+ Text(user.name)
714
+ } else {
715
+ ProgressView()
716
+ }
717
+ }
718
+ .task { await store.loadUser(id: userID) }
719
+ }
720
+ }
721
+
722
+ // Preview uses mock client
723
+ #Preview {
724
+ UserProfileView(store: UserStore(client: .mock(
725
+ fetchUser: { _ in User(id: UUID(), name: "Preview User") }
726
+ )))
727
+ }
728
+
729
+ // App uses live client
730
+ @main
731
+ struct MyApp: App {
732
+ let userStore = UserStore(client: .live(baseURL: URL(string: "https://api.example.com")!))
733
+
734
+ var body: some Scene {
735
+ WindowGroup {
736
+ UserProfileView(store: userStore)
737
+ }
738
+ }
739
+ }
740
+ ```
741
+
742
+ ---
743
+
744
+ ## 5B. Per-Tab Navigation Architecture
745
+
746
+ ### 5B.1 Overview
747
+
748
+ **Purpose**: Provide each tab with its own independent navigation stack and router, preserving navigation history across tab switches and supporting deep link routing to a specific tab.
749
+
750
+ **Benefits:**
751
+ - Tab navigation state preserved when switching tabs (native iOS behavior)
752
+ - Deep links can target specific tabs without resetting all stacks
753
+ - Decoupled tab-specific routing logic
754
+
755
+ ### 5B.2 Implementation Pattern
756
+
757
+ **Check for:**
758
+ - [ ] `TabRouter` (or `AppTabRouter`) owns one `RouterPath` per tab
759
+ - [ ] `Binding(for tab:)` helper creates a `Binding<[Route]>` for each tab's stack
760
+ - [ ] Deep links dispatched to the correct tab's router (not a global path)
761
+ - [ ] Tab switching does not reset other tabs' navigation stacks
762
+
763
+ **Examples:**
764
+
765
+ ❌ **Bad: Single shared path for all tabs**
766
+ ```swift
767
+ struct MainTabView: View {
768
+ @State private var path = NavigationPath() // ❌ Shared — tab switch loses history
769
+ @State private var selectedTab = 0
770
+
771
+ var body: some View {
772
+ TabView(selection: $selectedTab) {
773
+ NavigationStack(path: $path) { HomeView() }.tag(0)
774
+ NavigationStack(path: $path) { SearchView() }.tag(1) // ❌ Same path!
775
+ }
776
+ }
777
+ }
778
+ ```
779
+
780
+ ✅ **Good: Per-tab RouterPath with deep link routing**
781
+ ```swift
782
+ @Observable
783
+ final class RouterPath {
784
+ var path: [AppRoute] = []
785
+
786
+ func navigate(to route: AppRoute) { path.append(route) }
787
+ func pop() { if !path.isEmpty { path.removeLast() } }
788
+ func popToRoot() { path.removeAll() }
789
+
790
+ func handle(url: URL) -> Bool {
791
+ guard let route = AppRoute(url: url) else { return false }
792
+ navigate(to: route)
793
+ return true
794
+ }
795
+ }
796
+
797
+ enum AppTab: Int, CaseIterable, Identifiable {
798
+ case home, search, notifications, profile
799
+ var id: Int { rawValue }
800
+ }
801
+
802
+ @Observable
803
+ final class AppTabRouter {
804
+ var selectedTab: AppTab = .home
805
+
806
+ var homeRouter = RouterPath()
807
+ var searchRouter = RouterPath()
808
+ var notificationsRouter = RouterPath()
809
+ var profileRouter = RouterPath()
810
+
811
+ // Binding helper for each tab's path
812
+ func pathBinding(for tab: AppTab) -> Binding<[AppRoute]> {
813
+ Binding(
814
+ get: { self.router(for: tab).path },
815
+ set: { self.router(for: tab).path = $0 }
816
+ )
817
+ }
818
+
819
+ func router(for tab: AppTab) -> RouterPath {
820
+ switch tab {
821
+ case .home: return homeRouter
822
+ case .search: return searchRouter
823
+ case .notifications: return notificationsRouter
824
+ case .profile: return profileRouter
825
+ }
826
+ }
827
+
828
+ // Route deep link to correct tab
829
+ func handle(url: URL) {
830
+ guard let route = AppRoute(url: url) else { return }
831
+ let targetTab = route.preferredTab
832
+ selectedTab = targetTab
833
+ router(for: targetTab).navigate(to: route)
834
+ }
835
+ }
836
+
837
+ struct MainTabView: View {
838
+ @State private var tabRouter = AppTabRouter()
839
+
840
+ var body: some View {
841
+ TabView(selection: $tabRouter.selectedTab) {
842
+ Tab("Home", systemImage: "house", value: AppTab.home) {
843
+ NavigationStack(path: tabRouter.pathBinding(for: .home)) {
844
+ HomeView(router: tabRouter.homeRouter)
845
+ .navigationDestination(for: AppRoute.self) { route in
846
+ routeDestination(route, router: tabRouter.homeRouter)
847
+ }
848
+ }
849
+ }
850
+
851
+ Tab("Search", systemImage: "magnifyingglass", value: AppTab.search) {
852
+ NavigationStack(path: tabRouter.pathBinding(for: .search)) {
853
+ SearchView(router: tabRouter.searchRouter)
854
+ .navigationDestination(for: AppRoute.self) { route in
855
+ routeDestination(route, router: tabRouter.searchRouter)
856
+ }
857
+ }
858
+ }
859
+
860
+ // ... other tabs
861
+ }
862
+ .onOpenURL { url in
863
+ tabRouter.handle(url: url) // ✅ Deep link dispatched to correct tab router
864
+ }
865
+ }
866
+ }
867
+ ```
868
+
869
+ ---
870
+
596
871
  ## 6. Testing Strategies
597
872
 
598
873
  ### 6.1 Unit Testing