@buivietphi/skill-mobile-mt 2.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,416 @@
1
+ # Architecture Intelligence — Patterns from 30+ Production Repos
2
+
3
+ > On-demand. Load when: "architecture", "structure", "setup project", "best practices", "how to organize"
4
+ > Source: Analyzed 30+ open-source production mobile apps (total 200k+ GitHub stars)
5
+
6
+ ---
7
+
8
+ ## Reference Repos (by platform)
9
+
10
+ | Platform | Repo | Stars | Key Pattern |
11
+ |----------|------|-------|-------------|
12
+ | **RN** | Ignite (infinitered) | 19.7k | MST + MMKV + generators |
13
+ | **RN** | Obytes Template | 4k | Zustand + TanStack Query + Expo Router |
14
+ | **RN** | Expensify/App | 4.7k | Onyx custom state + centralized constants |
15
+ | **RN** | Mattermost Mobile | 2.6k | WatermelonDB + offline-first + WebSocket |
16
+ | **RN** | Artsy Eigen | 3.8k | Relay/GraphQL + Scene pattern |
17
+ | **Flutter** | Immich | 93.5k | Riverpod + drift + auto_route + clean arch |
18
+ | **Flutter** | AppFlowy | 68.2k | BLoC + GetIt + startup/ pattern |
19
+ | **Flutter** | Spotube | 44.6k | Riverpod + Hooks + custom hooks folder |
20
+ | **Flutter** | Hiddify | 26.7k | Riverpod + go_router + bootstrap.dart |
21
+ | **Flutter** | Ente Photos | 24.8k | Melos monorepo + gateway pattern |
22
+ | **iOS** | TCA (Point-Free) | 14.4k | Unidirectional + TestStore + @Dependency |
23
+ | **iOS** | Clean Arch SwiftUI | 6.5k | Redux state + @Environment DI |
24
+ | **iOS** | Modern Clean Arch | 4.1k | Tuist + 5-layer DDD + MVVM+TCA coexist |
25
+ | **Android** | Now in Android | 20.7k | Official Google arch + no-mock testing |
26
+ | **Android** | Android Showcase | 6.7k | Konsist validation + Koin DI |
27
+ | **Android** | Mihon | 18.8k | Plugin/extension arch + MVI |
28
+
29
+ ---
30
+
31
+ ## Cross-Platform Architecture Patterns
32
+
33
+ ### 1. Dual State Management (Client + Server)
34
+
35
+ **The pattern:** Separate client state (UI, forms) from server state (API cache).
36
+
37
+ | Platform | Client State | Server State |
38
+ |----------|-------------|--------------|
39
+ | React Native | Zustand / MST | TanStack Query |
40
+ | Flutter | Riverpod | Riverpod + drift |
41
+ | iOS | @Observable / TCA | URLSession cache |
42
+ | Android | ViewModel + Flow | Repository + Room |
43
+
44
+ ```typescript
45
+ // RN: Zustand for client + TanStack Query for server
46
+ const useAuthStore = create((set) => ({
47
+ token: null,
48
+ setToken: (t) => set({ token: t }),
49
+ }));
50
+
51
+ const { data, isLoading } = useQuery({
52
+ queryKey: ['products'],
53
+ queryFn: () => api.getProducts(),
54
+ staleTime: 5 * 60 * 1000,
55
+ });
56
+ ```
57
+
58
+ ```dart
59
+ // Flutter: Riverpod for both, but separated
60
+ @riverpod
61
+ class AuthNotifier extends _$AuthNotifier { ... } // client
62
+
63
+ @riverpod
64
+ Future<List<Product>> products(Ref ref) async { ... } // server
65
+ ```
66
+
67
+ ### 2. Feature-Based Module Organization
68
+
69
+ **Every top repo (100%) uses feature-based organization, NOT type-based.**
70
+
71
+ ```
72
+ // ✅ CORRECT: Feature-based (Immich, Obytes, Hiddify, Now in Android)
73
+ src/features/
74
+ auth/
75
+ domain/ # entities, use cases, repo interfaces
76
+ data/ # repo impl, API, DTOs, mappers
77
+ presentation/ # screens, widgets, viewmodels
78
+
79
+ // ❌ WRONG: Type-based (no production app uses this)
80
+ src/
81
+ models/
82
+ services/
83
+ screens/
84
+ widgets/
85
+ ```
86
+
87
+ ### 3. Centralized Constants Pattern (Expensify)
88
+
89
+ ```typescript
90
+ // src/ROUTES.ts — Prevents string duplication
91
+ const ROUTES = {
92
+ HOME: 'home',
93
+ SETTINGS: 'settings',
94
+ PROFILE: 'profile/:id',
95
+ } as const;
96
+
97
+ // src/SCREENS.ts — Screen component names
98
+ const SCREENS = {
99
+ HOME: 'HomeScreen',
100
+ SETTINGS: 'SettingsScreen',
101
+ } as const;
102
+ ```
103
+
104
+ ### 4. Bootstrap / Startup Pattern (Hiddify, AppFlowy)
105
+
106
+ ```dart
107
+ // bootstrap.dart — Clean app initialization
108
+ Future<void> bootstrap() async {
109
+ WidgetsFlutterBinding.ensureInitialized();
110
+
111
+ // 1. Core services
112
+ await Firebase.initializeApp();
113
+ await Hive.initFlutter();
114
+
115
+ // 2. DI registration
116
+ setupServiceLocator();
117
+
118
+ // 3. Run app
119
+ runApp(
120
+ ProviderScope(
121
+ observers: [RiverpodObserver()],
122
+ child: const App(),
123
+ ),
124
+ );
125
+ }
126
+
127
+ // main.dart
128
+ void main() => bootstrap();
129
+
130
+ // main_prod.dart — Production flavor
131
+ void main() {
132
+ const env = Environment.production;
133
+ bootstrap(env: env);
134
+ }
135
+ ```
136
+
137
+ ### 5. Draft Pairs for Forms (Expensify)
138
+
139
+ ```typescript
140
+ // Every form has FORM + FORM_DRAFT for unsaved changes
141
+ const ONYX_KEYS = {
142
+ WORKSPACE_SETTINGS_FORM: 'workspaceSettingsForm',
143
+ WORKSPACE_SETTINGS_FORM_DRAFT: 'workspaceSettingsFormDraft',
144
+ } as const;
145
+
146
+ // Save draft on every keystroke → restore on crash/back
147
+ // Only commit FORM when user explicitly saves
148
+ ```
149
+
150
+ ### 6. Database Subscription Pattern (Mattermost)
151
+
152
+ ```
153
+ database/
154
+ models/ # WatermelonDB model definitions
155
+ schema/ # DB structure + versioning
156
+ migration/ # Schema migrations
157
+ operator/ # Complex query logic (keeps models clean)
158
+ subscription/ # Reactive UI updates from DB changes
159
+ exceptions/ # Custom error classes
160
+ manager/ # DB lifecycle (create, reset, destroy)
161
+ ```
162
+
163
+ ### 7. Functional Error Handling (Flutter — dartz)
164
+
165
+ ```dart
166
+ // Instead of try/catch everywhere, use Either<Failure, Success>
167
+ Future<Either<AppException, User>> getUser(String id) async {
168
+ try {
169
+ final response = await dio.get('/users/$id');
170
+ return Right(User.fromJson(response.data));
171
+ } on DioException catch (e) {
172
+ return Left(NetworkException(e.message));
173
+ }
174
+ }
175
+
176
+ // Usage — forces caller to handle both cases
177
+ final result = await getUser('123');
178
+ result.fold(
179
+ (failure) => showError(failure.message),
180
+ (user) => showProfile(user),
181
+ );
182
+ ```
183
+
184
+ ### 8. Architecture Validation (Android Showcase — Konsist)
185
+
186
+ ```kotlin
187
+ // Programmatically enforce architecture rules
188
+ @Test
189
+ fun `domain layer should not depend on data layer`() {
190
+ Konsist.scopeFromModule("feature-album/domain")
191
+ .classes()
192
+ .assertFalse { it.hasImport { import -> import.hasNameContaining("data") } }
193
+ }
194
+
195
+ @Test
196
+ fun `use cases should have 'UseCase' suffix`() {
197
+ Konsist.scopeFromModule("feature-album/domain")
198
+ .classes()
199
+ .withNameContaining("UseCase")
200
+ .assertTrue { it.hasPublicFunction("invoke") }
201
+ }
202
+ ```
203
+
204
+ ---
205
+
206
+ ## Platform-Specific Intelligence
207
+
208
+ ### React Native — Must-Know Patterns
209
+
210
+ | Pattern | Old Way | New Way (2024-2025) | Source |
211
+ |---------|---------|---------------------|--------|
212
+ | Storage | AsyncStorage | MMKV (60x faster) | Ignite, Obytes |
213
+ | Routing | React Navigation | Expo Router (file-based) | Obytes |
214
+ | Server state | Redux + thunk | TanStack Query | Obytes, TCM |
215
+ | Client state | Redux | Zustand | Obytes |
216
+ | E2E testing | Detox | Maestro | Ignite, Obytes |
217
+ | Forms | Formik + Yup | TanStack Form + Zod | Obytes |
218
+ | Styling | StyleSheet | NativeWind (TailwindCSS) | Obytes |
219
+ | Animations | Animated API | Reanimated 3 | All |
220
+ | Images | Image | expo-image / FastImage | All |
221
+
222
+ ### Flutter — Must-Know Patterns
223
+
224
+ | Pattern | Old Way | New Way (2024-2025) | Source |
225
+ |---------|---------|---------------------|--------|
226
+ | State | setState / Provider | Riverpod + code-gen | Immich, Hiddify, Spotube |
227
+ | State (alt) | BLoC manual | BLoC + freezed | AppFlowy |
228
+ | Navigation | Navigator 2.0 | auto_route / go_router | Immich / Hiddify |
229
+ | Database | sqflite | drift (type-safe ORM) | Immich, Spotube |
230
+ | Models | manual fromJson | freezed + json_serializable | All |
231
+ | i18n | .arb files | slang (type-safe, generated) | Hiddify |
232
+ | HTTP | http package | dio + smart_retry | Hiddify |
233
+ | HTTP (perf) | dio on all | cronet (Android) + cupertino_http (iOS) | Immich |
234
+ | Monorepo | N/A | Melos | Ente |
235
+ | DI | manual | Riverpod providers / GetIt | Immich / AppFlowy |
236
+
237
+ ### iOS Swift — Must-Know Patterns
238
+
239
+ | Pattern | Traditional | Modern (2024-2025) | Source |
240
+ |---------|-------------|---------------------|--------|
241
+ | Architecture | MVVM manual | TCA (macro-driven) | Point-Free |
242
+ | DI | Swinject | @Dependency (Point-Free) / @Environment | TCA / nalexn |
243
+ | Testing | XCTest + mocks | TestStore (deterministic) | TCA |
244
+ | Navigation | NavigationView | NavigationStack + Coordinator | sergdort |
245
+ | Modularization | One target | Tuist multi-module | sergdort |
246
+ | Data binding | Combine | @Observable macro | iOS 17+ |
247
+ | SwiftUI testing | None | ViewInspector | nalexn |
248
+ | Concurrency | GCD / Combine | async/await + actors | All |
249
+
250
+ ### Android Kotlin — Must-Know Patterns
251
+
252
+ | Pattern | Traditional | Modern (2024-2025) | Source |
253
+ |---------|-------------|---------------------|--------|
254
+ | UI | XML Views | Jetpack Compose | All |
255
+ | Architecture | MVVM | MVVM + UDF (Now in Android) | Google |
256
+ | DI | Dagger 2 | Hilt | Now in Android |
257
+ | DI (lightweight) | N/A | Koin | Android Showcase |
258
+ | Testing | Mockito | No-mock test doubles | Now in Android |
259
+ | Arch validation | Manual review | Konsist | Android Showcase |
260
+ | Performance | ProGuard | Baseline Profiles + R8 | Now in Android |
261
+ | Navigation | Fragment nav | Compose Navigation (type-safe) | All |
262
+ | Build config | build.gradle | Convention Plugins | Now in Android |
263
+ | Screenshot test | None | Roborazzi | Now in Android |
264
+
265
+ ---
266
+
267
+ ## Production Folder Structure Templates
268
+
269
+ ### React Native (Expo Router — based on Obytes)
270
+
271
+ ```
272
+ src/
273
+ app/ # Expo Router file-based routes
274
+ (app)/ # Authenticated group
275
+ _layout.tsx
276
+ (tabs)/ # Tab navigator
277
+ login.tsx
278
+ onboarding.tsx
279
+ _layout.tsx # Root layout
280
+ features/ # Feature modules
281
+ auth/
282
+ hooks/
283
+ components/
284
+ services/
285
+ types.ts
286
+ products/
287
+ hooks/
288
+ components/
289
+ services/
290
+ components/
291
+ ui/ # Design system (Button, Input, Card)
292
+ lib/
293
+ api/ # Axios + TanStack Query setup
294
+ auth/ # Token management (Zustand + MMKV)
295
+ hooks/ # Shared hooks
296
+ i18n/ # Internationalization
297
+ storage.ts # MMKV wrapper
298
+ utils.ts # Utilities
299
+ translations/ # Language files
300
+ ```
301
+
302
+ ### Flutter (Riverpod + Clean — based on Immich)
303
+
304
+ ```
305
+ lib/
306
+ main.dart
307
+ bootstrap.dart # App initialization
308
+ app/
309
+ app.dart # MaterialApp.router
310
+ router.dart # auto_route / go_router config
311
+ theme/
312
+ features/
313
+ auth/
314
+ domain/ # Entities, use cases, repo interfaces
315
+ data/ # Repo impl, datasources, DTOs
316
+ presentation/ # Screens + widgets
317
+ providers/ # Riverpod providers
318
+ [feature]/
319
+ shared/
320
+ widgets/ # Reusable UI
321
+ extensions/ # Dart extensions
322
+ constants/ # App-wide constants
323
+ interfaces/ # Abstract contracts
324
+ models/ # Shared DTOs
325
+ utils/ # Utilities
326
+ l10n/ # Localization
327
+ ```
328
+
329
+ ### iOS SwiftUI (TCA — based on Point-Free + sergdort)
330
+
331
+ ```
332
+ App/
333
+ AppDelegate.swift
334
+ AppModule.swift # Composition root
335
+ Features/
336
+ Auth/
337
+ AuthFeature.swift # @Reducer
338
+ AuthView.swift # SwiftUI View
339
+ AuthClient.swift # @Dependency
340
+ Home/
341
+ HomeFeature.swift
342
+ HomeView.swift
343
+ Settings/
344
+ Shared/
345
+ Models/
346
+ Extensions/
347
+ UI/ # Shared SwiftUI components
348
+ Clients/ # API, Storage, Keychain
349
+ Platform/
350
+ Networking/
351
+ Persistence/
352
+ Tests/
353
+ AuthFeatureTests.swift # TestStore tests
354
+ ```
355
+
356
+ ### Android Kotlin (Now in Android — based on Google reference)
357
+
358
+ ```
359
+ app/ # Main application
360
+ core/
361
+ common/ # Shared utilities
362
+ data/ # Repository implementations
363
+ database/ # Room database
364
+ datastore/ # Proto DataStore
365
+ network/ # Retrofit + OkHttp
366
+ model/ # Core models
367
+ ui/ # Shared Compose components
368
+ testing/ # Test utilities
369
+ feature/
370
+ auth/
371
+ src/main/
372
+ AuthScreen.kt # Compose UI
373
+ AuthViewModel.kt # ViewModel
374
+ AuthUiState.kt # UI state sealed class
375
+ navigation/ # Feature nav graph
376
+ home/
377
+ settings/
378
+ build-logic/ # Convention plugins
379
+ convention/
380
+ AndroidApplicationConventionPlugin.kt
381
+ AndroidFeatureConventionPlugin.kt
382
+ ```
383
+
384
+ ---
385
+
386
+ ## Decision Matrix — When to Use What
387
+
388
+ ### State Management
389
+
390
+ | Condition | RN | Flutter | iOS | Android |
391
+ |-----------|-----|---------|-----|---------|
392
+ | Simple app (<10 screens) | Zustand | Riverpod | @Observable | ViewModel + StateFlow |
393
+ | Complex app (10-50 screens) | Zustand + TanStack Query | Riverpod + freezed | TCA | MVVM + Hilt + Flow |
394
+ | Enterprise (50+ screens) | Onyx (custom) / Redux Toolkit | BLoC + GetIt | TCA + Tuist | MVVM + Hilt + Convention Plugins |
395
+ | Offline-first | TanStack Query + WatermelonDB | Riverpod + drift | TCA + SwiftData | Room + WorkManager |
396
+
397
+ ### Navigation
398
+
399
+ | Condition | RN | Flutter | iOS | Android |
400
+ |-----------|-----|---------|-----|---------|
401
+ | Expo project | Expo Router | — | — | — |
402
+ | RN CLI project | React Navigation | — | — | — |
403
+ | Type-safe routes | — | auto_route | NavigationStack | Compose Navigation |
404
+ | Declarative | Expo Router | go_router | NavigationStack | Compose Navigation |
405
+ | Deep linking | Expo Linking | app_links | Universal Links | App Links |
406
+
407
+ ### Testing
408
+
409
+ | What | RN | Flutter | iOS | Android |
410
+ |------|-----|---------|-----|---------|
411
+ | Unit | Jest | test + mocktail | XCTest / TestStore | JUnit + no-mock doubles |
412
+ | Widget/Component | React Testing Library | widget test | ViewInspector | Compose Testing |
413
+ | E2E | Maestro | integration_test | XCUITest | Macrobenchmark |
414
+ | Screenshot | — | golden_toolkit | — | Roborazzi |
415
+ | Architecture | Dependency Cruiser | — | — | Konsist |
416
+ | Performance | Reassure | DevTools | Instruments | Baseline Profiles |
@@ -0,0 +1,71 @@
1
+ # Bug Detection — Auto Scanner
2
+
3
+ > Always loaded. All platforms.
4
+
5
+ ---
6
+
7
+ ## Scan Order (by severity)
8
+
9
+ ### 1. Crash Risks (CRITICAL)
10
+ ```
11
+ ├── Force unwrap (! / !! / non-null assertion)
12
+ ├── Array out of bounds
13
+ ├── Unhandled null on API response
14
+ ├── Missing try/catch on async ops
15
+ ├── Missing error boundaries (RN)
16
+ ├── Infinite recursion
17
+ └── Division by zero
18
+ ```
19
+
20
+ ### 2. Memory Leaks (HIGH)
21
+ ```
22
+ RN: useEffect without cleanup, listeners not removed, timers not cleared
23
+ Flutter: StreamSubscription/Controller not disposed
24
+ iOS: [weak self] missing, observers not removed
25
+ Android: Context leak, BroadcastReceiver not unregistered
26
+ ```
27
+
28
+ ### 3. Race Conditions (HIGH)
29
+ ```
30
+ ├── Button tappable during async op → add isSubmitting flag
31
+ ├── setState after unmount → track mounted state
32
+ ├── Multiple 401s → queue token refresh
33
+ └── Optimistic update without rollback → save previous state
34
+ ```
35
+
36
+ ### 4. Security (HIGH)
37
+ ```
38
+ ├── Hardcoded secrets → env / secure config
39
+ ├── Tokens in AsyncStorage/SharedPrefs → SecureStore/Keychain
40
+ ├── Sensitive data in logs → strip before logging
41
+ ├── Deep links unvalidated → validate params
42
+ └── Debug mode in release → strip debug flags
43
+ ```
44
+
45
+ ### 5. Performance (MEDIUM)
46
+ ```
47
+ ├── ScrollView for long lists → FlatList/ListView.builder/LazyColumn
48
+ ├── Inline functions in render → useCallback/memo/const
49
+ ├── Index as key → stable unique ID
50
+ ├── Large images unoptimized → resize, cache
51
+ ├── Main thread blocking → background thread
52
+ └── Missing pagination → add cursor/offset
53
+ ```
54
+
55
+ ### 6. UX (MEDIUM)
56
+ ```
57
+ ├── Touch targets < 44pt/48dp
58
+ ├── Missing loading/error/empty states
59
+ ├── No keyboard dismiss
60
+ ├── Missing safe area handling
61
+ └── No accessibility labels
62
+ ```
63
+
64
+ ## Report Format
65
+
66
+ ```
67
+ 🐛 [SEVERITY] — [file:line]
68
+ Issue: [description]
69
+ Impact: [what breaks]
70
+ Fix: [code change]
71
+ ```