@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,423 @@
1
+ # CI/CD Pipelines — GitHub Actions for Mobile
2
+
3
+ > Automate: test → build → distribute. Never ship without CI.
4
+
5
+ ---
6
+
7
+ ## React Native — CI Pipeline
8
+
9
+ ```yaml
10
+ # .github/workflows/rn-ci.yml
11
+ name: React Native CI
12
+
13
+ on:
14
+ push:
15
+ branches: [main, develop]
16
+ pull_request:
17
+ branches: [main]
18
+
19
+ jobs:
20
+ test:
21
+ runs-on: ubuntu-latest
22
+ steps:
23
+ - uses: actions/checkout@v4
24
+
25
+ - uses: actions/setup-node@v4
26
+ with:
27
+ node-version: '20'
28
+ cache: 'yarn' # or npm, pnpm
29
+
30
+ - name: Install dependencies
31
+ run: yarn install --frozen-lockfile
32
+
33
+ - name: TypeScript check
34
+ run: yarn tsc --noEmit
35
+
36
+ - name: Lint
37
+ run: yarn lint
38
+
39
+ - name: Unit tests
40
+ run: yarn test --ci --coverage --maxWorkers=2
41
+
42
+ - name: Upload coverage
43
+ uses: codecov/codecov-action@v4
44
+ with:
45
+ token: ${{ secrets.CODECOV_TOKEN }}
46
+
47
+ build-android:
48
+ runs-on: ubuntu-latest
49
+ needs: test
50
+ steps:
51
+ - uses: actions/checkout@v4
52
+
53
+ - uses: actions/setup-node@v4
54
+ with:
55
+ node-version: '20'
56
+ cache: 'yarn'
57
+
58
+ - uses: actions/setup-java@v4
59
+ with:
60
+ distribution: 'temurin'
61
+ java-version: '17'
62
+
63
+ - name: Cache Gradle
64
+ uses: actions/cache@v4
65
+ with:
66
+ path: |
67
+ ~/.gradle/caches
68
+ ~/.gradle/wrapper
69
+ key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*') }}
70
+
71
+ - name: Install dependencies
72
+ run: yarn install --frozen-lockfile
73
+
74
+ - name: Build Android APK (debug)
75
+ run: cd android && ./gradlew assembleDebug
76
+
77
+ - name: Upload APK
78
+ uses: actions/upload-artifact@v4
79
+ with:
80
+ name: app-debug.apk
81
+ path: android/app/build/outputs/apk/debug/app-debug.apk
82
+
83
+ build-ios:
84
+ runs-on: macos-15
85
+ needs: test
86
+ steps:
87
+ - uses: actions/checkout@v4
88
+
89
+ - uses: actions/setup-node@v4
90
+ with:
91
+ node-version: '20'
92
+ cache: 'yarn'
93
+
94
+ - name: Cache CocoaPods
95
+ uses: actions/cache@v4
96
+ with:
97
+ path: ios/Pods
98
+ key: ${{ runner.os }}-pods-${{ hashFiles('ios/Podfile.lock') }}
99
+
100
+ - name: Install dependencies
101
+ run: yarn install --frozen-lockfile && cd ios && pod install
102
+
103
+ - name: Build iOS (simulator)
104
+ run: |
105
+ xcodebuild -workspace ios/MyApp.xcworkspace \
106
+ -scheme MyApp \
107
+ -sdk iphonesimulator \
108
+ -configuration Debug \
109
+ -derivedDataPath ios/build \
110
+ CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO
111
+ ```
112
+
113
+ ---
114
+
115
+ ## React Native — E2E with Detox
116
+
117
+ ```yaml
118
+ # .github/workflows/rn-e2e.yml
119
+ name: E2E Tests (Detox)
120
+
121
+ on:
122
+ push:
123
+ branches: [main]
124
+
125
+ jobs:
126
+ e2e-ios:
127
+ runs-on: macos-15
128
+ steps:
129
+ - uses: actions/checkout@v4
130
+
131
+ - uses: actions/setup-node@v4
132
+ with:
133
+ node-version: '20'
134
+ cache: 'yarn'
135
+
136
+ - name: Install dependencies
137
+ run: yarn install --frozen-lockfile && cd ios && pod install
138
+
139
+ - name: Install Detox CLI
140
+ run: npm install -g detox-cli
141
+
142
+ - name: Build for Detox
143
+ run: detox build --configuration ios.sim.debug
144
+
145
+ - name: Run E2E tests
146
+ run: detox test --configuration ios.sim.debug --headless
147
+
148
+ - name: Upload Detox artifacts on failure
149
+ if: failure()
150
+ uses: actions/upload-artifact@v4
151
+ with:
152
+ name: detox-artifacts
153
+ path: artifacts/
154
+ ```
155
+
156
+ ---
157
+
158
+ ## Flutter — CI Pipeline
159
+
160
+ ```yaml
161
+ # .github/workflows/flutter-ci.yml
162
+ name: Flutter CI
163
+
164
+ on:
165
+ push:
166
+ branches: [main, develop]
167
+ pull_request:
168
+ branches: [main]
169
+
170
+ jobs:
171
+ test:
172
+ runs-on: ubuntu-latest
173
+ steps:
174
+ - uses: actions/checkout@v4
175
+
176
+ - uses: subosito/flutter-action@v2
177
+ with:
178
+ flutter-version: '3.27.x'
179
+ cache: true
180
+
181
+ - name: Install dependencies
182
+ run: flutter pub get
183
+
184
+ - name: Analyze
185
+ run: flutter analyze
186
+
187
+ - name: Unit + Widget tests
188
+ run: flutter test --coverage
189
+
190
+ - name: Upload coverage
191
+ uses: codecov/codecov-action@v4
192
+
193
+ build-android:
194
+ runs-on: ubuntu-latest
195
+ needs: test
196
+ steps:
197
+ - uses: actions/checkout@v4
198
+
199
+ - uses: actions/setup-java@v4
200
+ with:
201
+ distribution: 'temurin'
202
+ java-version: '17'
203
+
204
+ - uses: subosito/flutter-action@v2
205
+ with:
206
+ flutter-version: '3.27.x'
207
+ cache: true
208
+
209
+ - name: Install dependencies
210
+ run: flutter pub get
211
+
212
+ - name: Build APK
213
+ run: flutter build apk --debug
214
+
215
+ - name: Upload APK
216
+ uses: actions/upload-artifact@v4
217
+ with:
218
+ name: flutter-debug.apk
219
+ path: build/app/outputs/flutter-apk/app-debug.apk
220
+
221
+ build-ios:
222
+ runs-on: macos-15
223
+ needs: test
224
+ steps:
225
+ - uses: actions/checkout@v4
226
+
227
+ - uses: subosito/flutter-action@v2
228
+ with:
229
+ flutter-version: '3.27.x'
230
+ cache: true
231
+
232
+ - name: Install dependencies
233
+ run: flutter pub get
234
+
235
+ - name: Build iOS (no codesign)
236
+ run: flutter build ios --debug --no-codesign
237
+ ```
238
+
239
+ ---
240
+
241
+ ## iOS — Release to TestFlight (Fastlane)
242
+
243
+ ```yaml
244
+ # .github/workflows/ios-release.yml
245
+ name: iOS Release
246
+
247
+ on:
248
+ push:
249
+ tags: ['v*']
250
+
251
+ jobs:
252
+ release:
253
+ runs-on: macos-15
254
+ steps:
255
+ - uses: actions/checkout@v4
256
+
257
+ - uses: actions/setup-node@v4
258
+ with:
259
+ node-version: '20'
260
+ cache: 'yarn'
261
+
262
+ - name: Install dependencies
263
+ run: yarn install --frozen-lockfile && cd ios && pod install
264
+
265
+ - name: Setup certificates
266
+ uses: apple-actions/import-codesign-certs@v2
267
+ with:
268
+ p12-file-base64: ${{ secrets.CERTIFICATES_P12 }}
269
+ p12-password: ${{ secrets.CERTIFICATES_P12_PASSWORD }}
270
+
271
+ - name: Setup provisioning profile
272
+ uses: apple-actions/download-provisioning-profiles@v1
273
+ with:
274
+ bundle-id: com.myapp
275
+ issuer-id: ${{ secrets.APPSTORE_ISSUER_ID }}
276
+ api-key-id: ${{ secrets.APPSTORE_KEY_ID }}
277
+ api-private-key: ${{ secrets.APPSTORE_PRIVATE_KEY }}
278
+
279
+ - name: Deploy to TestFlight
280
+ run: bundle exec fastlane ios beta
281
+ env:
282
+ APP_STORE_CONNECT_API_KEY_KEY_ID: ${{ secrets.APPSTORE_KEY_ID }}
283
+ APP_STORE_CONNECT_API_KEY_ISSUER_ID: ${{ secrets.APPSTORE_ISSUER_ID }}
284
+ APP_STORE_CONNECT_API_KEY_KEY: ${{ secrets.APPSTORE_PRIVATE_KEY }}
285
+ ```
286
+
287
+ ```ruby
288
+ # ios/Fastfile
289
+ lane :beta do
290
+ build_app(
291
+ workspace: "MyApp.xcworkspace",
292
+ scheme: "MyApp",
293
+ configuration: "Release",
294
+ export_method: "app-store"
295
+ )
296
+ upload_to_testflight(skip_waiting_for_build_processing: true)
297
+ end
298
+ ```
299
+
300
+ ---
301
+
302
+ ## Android — Release to Play Store (Fastlane)
303
+
304
+ ```yaml
305
+ # .github/workflows/android-release.yml
306
+ name: Android Release
307
+
308
+ on:
309
+ push:
310
+ tags: ['v*']
311
+
312
+ jobs:
313
+ release:
314
+ runs-on: ubuntu-latest
315
+ steps:
316
+ - uses: actions/checkout@v4
317
+
318
+ - uses: actions/setup-java@v4
319
+ with:
320
+ distribution: 'temurin'
321
+ java-version: '17'
322
+
323
+ - uses: actions/setup-node@v4
324
+ with:
325
+ node-version: '20'
326
+ cache: 'yarn'
327
+
328
+ - name: Install dependencies
329
+ run: yarn install --frozen-lockfile
330
+
331
+ - name: Decode keystore
332
+ run: echo "${{ secrets.KEYSTORE_BASE64 }}" | base64 -d > android/app/release.keystore
333
+
334
+ - name: Build release AAB
335
+ run: cd android && ./gradlew bundleRelease
336
+ env:
337
+ KEYSTORE_PASSWORD: ${{ secrets.KEYSTORE_PASSWORD }}
338
+ KEY_ALIAS: ${{ secrets.KEY_ALIAS }}
339
+ KEY_PASSWORD: ${{ secrets.KEY_PASSWORD }}
340
+
341
+ - name: Deploy to Play Store
342
+ uses: r0adkll/upload-google-play@v1
343
+ with:
344
+ serviceAccountJsonPlainText: ${{ secrets.PLAY_STORE_SERVICE_ACCOUNT_JSON }}
345
+ packageName: com.myapp
346
+ releaseFiles: android/app/build/outputs/bundle/release/*.aab
347
+ track: internal
348
+ ```
349
+
350
+ ---
351
+
352
+ ## Required GitHub Secrets
353
+
354
+ ```
355
+ # iOS
356
+ CERTIFICATES_P12 ← base64-encoded .p12 file
357
+ CERTIFICATES_P12_PASSWORD ← password for .p12
358
+ APPSTORE_KEY_ID ← App Store Connect API key ID
359
+ APPSTORE_ISSUER_ID ← App Store Connect issuer ID
360
+ APPSTORE_PRIVATE_KEY ← App Store Connect private key (.p8 contents)
361
+
362
+ # Android
363
+ KEYSTORE_BASE64 ← base64-encoded release.keystore
364
+ KEYSTORE_PASSWORD ← keystore password
365
+ KEY_ALIAS ← key alias
366
+ KEY_PASSWORD ← key password
367
+ PLAY_STORE_SERVICE_ACCOUNT_JSON ← GCP service account JSON
368
+
369
+ # Shared
370
+ CODECOV_TOKEN ← coverage reporting
371
+ MAESTRO_API_KEY ← Maestro Cloud E2E (optional)
372
+ ```
373
+
374
+ ---
375
+
376
+ ## Caching Strategy
377
+
378
+ ```yaml
379
+ # Node modules — hash package-lock or yarn.lock
380
+ - uses: actions/cache@v4
381
+ with:
382
+ path: node_modules
383
+ key: ${{ runner.os }}-node-${{ hashFiles('**/yarn.lock') }}
384
+ restore-keys: ${{ runner.os }}-node-
385
+
386
+ # Gradle — hash .gradle files
387
+ - uses: actions/cache@v4
388
+ with:
389
+ path: |
390
+ ~/.gradle/caches
391
+ ~/.gradle/wrapper
392
+ key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
393
+
394
+ # CocoaPods — hash Podfile.lock
395
+ - uses: actions/cache@v4
396
+ with:
397
+ path: ios/Pods
398
+ key: ${{ runner.os }}-pods-${{ hashFiles('ios/Podfile.lock') }}
399
+
400
+ # Flutter pub — hash pubspec.lock
401
+ - uses: actions/cache@v4
402
+ with:
403
+ path: ~/.pub-cache
404
+ key: ${{ runner.os }}-pub-${{ hashFiles('**/pubspec.lock') }}
405
+ ```
406
+
407
+ ---
408
+
409
+ ## Anti-Patterns
410
+
411
+ ```
412
+ ❌ Committing signing credentials to repo
413
+ ❌ Running E2E on every PR (too slow — run on main only)
414
+ ❌ No caching (3x slower builds)
415
+ ❌ Skipping unit tests before build jobs
416
+ ❌ Building on push to every branch
417
+
418
+ ✅ Store all secrets in GitHub Secrets
419
+ ✅ Cache node_modules + Gradle + CocoaPods + pub-cache
420
+ ✅ Unit tests on PR, E2E on merge to main
421
+ ✅ needs: test before build jobs
422
+ ✅ Upload build artifacts for download/QA
423
+ ```
@@ -0,0 +1,125 @@
1
+ # CLAUDE.md Template for Mobile Projects
2
+
3
+ > Copy this file to your project root as `CLAUDE.md`.
4
+ > Claude Code reads it automatically every session — no invocation needed.
5
+
6
+ ---
7
+
8
+ ## How to use
9
+
10
+ 1. Copy this file to your project: `cp CLAUDE.md.template CLAUDE.md`
11
+ 2. Edit the sections marked with `[FILL IN]`
12
+ 3. Claude will follow these rules automatically in every conversation
13
+
14
+ ---
15
+
16
+ ## Template (copy below this line)
17
+
18
+ ---
19
+
20
+ # Project: [FILL IN: Your App Name]
21
+
22
+ ## Stack
23
+
24
+ - **Framework:** [React Native CLI / Expo SDK XX / Flutter X.X / iOS / Android]
25
+ - **Language:** [TypeScript / JavaScript / Dart / Swift / Kotlin]
26
+ - **State:** [Redux Toolkit / Zustand / Riverpod / BLoC / StateFlow]
27
+ - **Navigation:** [React Navigation v6 / Expo Router / GoRouter / UIKit / Jetpack]
28
+ - **API:** [axios / fetch / Dio / Firebase / GraphQL]
29
+ - **Package Manager:** [yarn / npm / pnpm / bun / flutter pub]
30
+
31
+ ## Project Structure
32
+
33
+ ```
34
+ [FILL IN: paste your src/ or lib/ tree here]
35
+ src/
36
+ ├── features/
37
+ │ ├── auth/
38
+ │ └── home/
39
+ ├── shared/
40
+ │ ├── components/
41
+ │ └── utils/
42
+ ```
43
+
44
+ ## Conventions
45
+
46
+ - **Naming:** [PascalCase screens, camelCase hooks/services]
47
+ - **Imports:** [absolute @/ aliases / relative paths]
48
+ - **Styling:** [StyleSheet / NativeWind / styled-components / Compose / SwiftUI]
49
+
50
+ ## Auto-Check Rules (apply after EVERY code change)
51
+
52
+ Before saying "done" on any task, automatically verify:
53
+
54
+ ```
55
+ □ No console.log / print / NSLog in production code
56
+ □ No hardcoded secrets, API keys, or tokens
57
+ □ No token storage in AsyncStorage / SharedPreferences / UserDefaults
58
+ □ All async operations wrapped in try/catch
59
+ □ All 4 states handled: loading / error / empty / success
60
+ □ useEffect / dispose / viewModelScope has cleanup
61
+ □ FlatList (not ScrollView) for lists > 20 items
62
+ □ No force unwrap (! / !! / as!) without null check
63
+ □ TypeScript: no implicit 'any'
64
+ □ New screens registered in navigator
65
+ □ Imports resolve (no broken paths)
66
+ ```
67
+
68
+ If ANY check fails → fix it before marking done.
69
+
70
+ ## Performance Rules (apply when building lists, animations, heavy screens)
71
+
72
+ ```
73
+ □ FlatList with keyExtractor + getItemLayout (if fixed height)
74
+ □ React.memo on list item components
75
+ □ useCallback on handlers passed to list items
76
+ □ Images: use FastImage / expo-image, specify width+height
77
+ □ Animations: use react-native-reanimated (not Animated API)
78
+ □ No heavy computation on main thread (use InteractionManager)
79
+ ```
80
+
81
+ ## Security Rules (non-negotiable)
82
+
83
+ ```
84
+ □ Tokens → SecureStore / Keychain / EncryptedSharedPreferences ONLY
85
+ □ Deep link params → validate before use
86
+ □ API calls → HTTPS only
87
+ □ Sensitive data → never in logs
88
+ □ User input → sanitize before display (XSS)
89
+ ```
90
+
91
+ ## What NOT to do
92
+
93
+ ```
94
+ □ NEVER suggest migrating to a different framework/architecture
95
+ □ NEVER change state management library
96
+ □ NEVER add packages without checking SDK compatibility first
97
+ □ NEVER mix package managers (yarn + npm)
98
+ □ NEVER create new files for one-off operations
99
+ □ NEVER add comments to code you didn't change
100
+ ```
101
+
102
+ ## Preferred Commands
103
+
104
+ ```bash
105
+ # Install
106
+ [yarn install / npm install / flutter pub get / pod install]
107
+
108
+ # Run
109
+ [yarn ios / yarn android / flutter run / xcodebuild / ./gradlew]
110
+
111
+ # Test
112
+ [yarn test / flutter test / xcodebuild test]
113
+
114
+ # Lint
115
+ [yarn lint / flutter analyze / swiftlint]
116
+ ```
117
+
118
+ ## Notes
119
+
120
+ [FILL IN: any project-specific quirks, known issues, or important context]
121
+
122
+ Example:
123
+ - Auth uses custom JWT refresh logic in src/services/auth/tokenManager.ts
124
+ - Push notifications require manual certificate setup (see docs/push-setup.md)
125
+ - Android flavor: 'staging' points to staging API, 'production' to prod
@@ -0,0 +1,133 @@
1
+ # Code Review — Senior Protocol
2
+
3
+ > 🔴 Always loaded. All platforms.
4
+
5
+ ---
6
+
7
+ ## Checklist
8
+
9
+ ### Architecture
10
+ - [ ] Single responsibility per file (max 300 lines)
11
+ - [ ] Dependencies flow inward (UI → Domain → Data)
12
+ - [ ] Follows existing project patterns
13
+ - [ ] New files in correct directory
14
+
15
+ ### Correctness
16
+ - [ ] All states handled: loading, success, error, empty
17
+ - [ ] Edge cases: null, empty, timeout, concurrent
18
+ - [ ] Async errors caught with meaningful handling
19
+ - [ ] Cleanup on unmount/dispose (listeners, timers, subscriptions)
20
+ - [ ] No race conditions (double-tap, concurrent API calls)
21
+
22
+ ### Performance
23
+ - [ ] Lists virtualized (FlatList / ListView.builder / LazyColumn)
24
+ - [ ] Memoized where needed (memo / const / remember)
25
+ - [ ] No inline functions in render/build
26
+ - [ ] Images cached and resized
27
+ - [ ] No main thread blocking
28
+
29
+ ### Security
30
+ - [ ] No hardcoded secrets
31
+ - [ ] Secure storage for tokens (Keychain / EncryptedSharedPreferences)
32
+ - [ ] Input validated and sanitized
33
+ - [ ] Deep links validated before navigation
34
+ - [ ] No sensitive data in logs
35
+
36
+ ### Platform
37
+ - [ ] Both iOS + Android tested (if cross-platform)
38
+ - [ ] Safe areas / notch handled
39
+ - [ ] Keyboard handled (dismiss, avoidance)
40
+ - [ ] Back button handled (Android)
41
+ - [ ] Accessibility labels on interactive elements
42
+
43
+ ---
44
+
45
+ ## Severity
46
+
47
+ | Level | Action | Example |
48
+ |-------|--------|---------|
49
+ | 🔴 CRITICAL | Must fix before merge | Crash, security hole, data loss |
50
+ | 🟠 HIGH | Should fix before merge | Memory leak, missing error state, race condition |
51
+ | 🟡 MEDIUM | Fix in follow-up | Naming inconsistency, missing memoization |
52
+ | 🔵 LOW | Nice to have | Minor style, comment improvement |
53
+
54
+ ---
55
+
56
+ ## Auto-Fail
57
+
58
+ **Any of these → block merge immediately:**
59
+
60
+ ```
61
+ ❌ console.log / print in production code
62
+ ❌ Hardcoded secrets or API keys
63
+ ❌ Force unwrap without null check (! / !! / as!)
64
+ ❌ Empty catch blocks (error silently swallowed)
65
+ ❌ 500+ line files
66
+ ❌ Network call in render / build / Composable
67
+ ❌ Index as list key
68
+ ❌ Missing loading / error / empty state (blank screen)
69
+ ```
70
+
71
+ ### Grounding Auto-Fail (AI-generated code)
72
+
73
+ **If the code was generated by AI, also check:**
74
+
75
+ ```
76
+ ❌ Import from a package NOT in package.json / pubspec.yaml
77
+ ❌ Function/method call that doesn't exist in the codebase
78
+ ❌ API endpoint or response shape not verified from actual service code
79
+ ❌ Library version syntax that doesn't match installed version
80
+ ❌ Platform API that doesn't exist in the project's min SDK
81
+ ```
82
+
83
+ ---
84
+
85
+ ## Review Comment Templates
86
+
87
+ ```
88
+ 🔴 CRITICAL — [file:line]
89
+ Issue: [description]
90
+ Impact: [what breaks]
91
+ Fix: [specific code change]
92
+
93
+ 🟠 HIGH — [file:line]
94
+ Issue: [description]
95
+ Fix: [suggestion]
96
+
97
+ 🟡 MEDIUM — [file:line]
98
+ Suggestion: [improvement]
99
+ ```
100
+
101
+ ---
102
+
103
+ ## Example Issues
104
+
105
+ ### Before (Bad)
106
+ ```typescript
107
+ // ❌ No error handling, no loading state, index as key
108
+ function ProductList() {
109
+ const [data, setData] = useState([]);
110
+ useEffect(() => { api.get('/products').then(r => setData(r.data)); }, []);
111
+ return data.map((item, i) => <ProductCard key={i} item={item} />);
112
+ }
113
+ ```
114
+
115
+ ### After (Good)
116
+ ```typescript
117
+ // ✅ All states, cleanup, stable key, error handling
118
+ function ProductList() {
119
+ const [state, setState] = useState({ data: [], loading: true, error: null });
120
+ useEffect(() => {
121
+ let cancelled = false;
122
+ api.get('/products')
123
+ .then(r => { if (!cancelled) setState({ data: r.data, loading: false, error: null }); })
124
+ .catch(e => { if (!cancelled) setState({ data: [], loading: false, error: e.message }); });
125
+ return () => { cancelled = true; };
126
+ }, []);
127
+
128
+ if (state.loading) return <LoadingSkeleton />;
129
+ if (state.error) return <ErrorView message={state.error} onRetry={refresh} />;
130
+ if (!state.data.length) return <EmptyState />;
131
+ return <FlatList data={state.data} keyExtractor={item => item.id} renderItem={...} />;
132
+ }
133
+ ```