@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.
- package/AGENTS.md +482 -0
- package/README.md +528 -0
- package/SKILL.md +1399 -0
- package/android/android-native.md +480 -0
- package/bin/install.mjs +976 -0
- package/flutter/flutter.md +304 -0
- package/humanizer/humanizer-mobile.md +295 -0
- package/ios/ios-native.md +182 -0
- package/package.json +56 -0
- package/react-native/react-native.md +743 -0
- package/shared/agent-rules-template.md +343 -0
- package/shared/ai-dlc-workflow.md +237 -0
- package/shared/anti-patterns.md +407 -0
- package/shared/architecture-intelligence.md +416 -0
- package/shared/bug-detection.md +71 -0
- package/shared/ci-cd.md +423 -0
- package/shared/claude-md-template.md +125 -0
- package/shared/code-review.md +133 -0
- package/shared/common-pitfalls.md +117 -0
- package/shared/document-analysis.md +167 -0
- package/shared/error-recovery.md +467 -0
- package/shared/observability.md +688 -0
- package/shared/offline-first.md +377 -0
- package/shared/performance-prediction.md +210 -0
- package/shared/platform-excellence.md +244 -0
- package/shared/prompt-engineering.md +705 -0
- package/shared/release-checklist.md +82 -0
- package/shared/testing-strategy.md +332 -0
- package/shared/ui-ux-mobile.md +667 -0
- package/shared/version-management.md +526 -0
|
@@ -0,0 +1,407 @@
|
|
|
1
|
+
# Anti-Pattern Detection — Scan for Common Mistakes
|
|
2
|
+
|
|
3
|
+
> Auto-detect patterns that cause crashes, leaks, or store rejections.
|
|
4
|
+
|
|
5
|
+
## When to Use
|
|
6
|
+
|
|
7
|
+
- Before committing code
|
|
8
|
+
- During code review
|
|
9
|
+
- When instrumentation/observability code is added
|
|
10
|
+
- Before PR submission
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Detection Categories
|
|
15
|
+
|
|
16
|
+
### 1. PII (Personally Identifiable Information) Leaks
|
|
17
|
+
|
|
18
|
+
**CRITICAL** - Compliance risk (GDPR, CCPA, HIPAA)
|
|
19
|
+
|
|
20
|
+
```
|
|
21
|
+
PATTERNS TO DETECT:
|
|
22
|
+
❌ email / phone / ssn / credit_card / address / dob (date of birth)
|
|
23
|
+
❌ properties: ["user_email": user.email]
|
|
24
|
+
❌ tags: ["phone": user.phone]
|
|
25
|
+
❌ trackEvent("login", ["ssn": ssn])
|
|
26
|
+
❌ console.log("User: ${user.email}")
|
|
27
|
+
|
|
28
|
+
✅ SAFE ALTERNATIVES:
|
|
29
|
+
✓ properties: ["has_email": user.email != nil]
|
|
30
|
+
✓ tags: ["user_tier": "premium"] // Enum, not PII
|
|
31
|
+
✓ trackEvent("login", ["user_type": userType])
|
|
32
|
+
✓ console.log("User: ${user.id}") // UUID, not PII
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
**Auto-Fix Suggestion:**
|
|
36
|
+
```
|
|
37
|
+
Found: properties: ["email": user.email]
|
|
38
|
+
Fix → properties: ["has_email": user.email != nil]
|
|
39
|
+
|
|
40
|
+
Found: tags: ["user_id": userId]
|
|
41
|
+
Fix → tags: ["user_tier": user.subscription.tier]
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
### 2. High Cardinality
|
|
47
|
+
|
|
48
|
+
**CRITICAL** - Explodes storage, kills query performance
|
|
49
|
+
|
|
50
|
+
```
|
|
51
|
+
PATTERNS TO DETECT:
|
|
52
|
+
❌ user_id / session_id / uuid / timestamp / device_id as TAG values
|
|
53
|
+
❌ tags: ["user_id": "uuid-123"] // Unlimited unique values
|
|
54
|
+
❌ tags: ["timestamp": Date.now()] // Unbounded
|
|
55
|
+
❌ dimensions: ["request_id": requestId] // High cardinality
|
|
56
|
+
|
|
57
|
+
✅ SAFE ALTERNATIVES:
|
|
58
|
+
✓ tags: ["user_tier": "free|premium|enterprise"] // Low cardinality (3 values)
|
|
59
|
+
✓ tags: ["hour": date.getHours()] // Low cardinality (0-23)
|
|
60
|
+
✓ dimensions: ["status_code": "200|404|500"] // Low cardinality
|
|
61
|
+
|
|
62
|
+
RULE: Tags should have < 100 unique values over 30 days
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
**Auto-Fix Suggestion:**
|
|
66
|
+
```
|
|
67
|
+
Found: tags: ["user_id": userId]
|
|
68
|
+
Why bad: user_id has unlimited unique values → storage explosion
|
|
69
|
+
Fix →
|
|
70
|
+
Option 1: Remove tag (use session correlation instead)
|
|
71
|
+
Option 2: tags: ["user_tier": user.tier] // Categorize
|
|
72
|
+
Option 3: Move to context field (not a tag)
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
### 3. Unbounded Payloads
|
|
78
|
+
|
|
79
|
+
**HIGH** - Hits size limits, network cost
|
|
80
|
+
|
|
81
|
+
```
|
|
82
|
+
PATTERNS TO DETECT:
|
|
83
|
+
❌ Entire objects: extras: ["state": appState]
|
|
84
|
+
❌ Large arrays: extras: ["cart": cart.items] // If items can be 1000+
|
|
85
|
+
❌ Unfiltered user input: extras: ["search_query": query] // No length limit
|
|
86
|
+
❌ Nested objects: extras: ["user": user] // Can be recursive
|
|
87
|
+
|
|
88
|
+
✅ SAFE ALTERNATIVES:
|
|
89
|
+
✓ extras: ["cart_item_count": cart.items.count] // Aggregate
|
|
90
|
+
✓ extras: ["has_state": appState != nil] // Boolean
|
|
91
|
+
✓ extras: ["search_query_length": query.length] // Derived
|
|
92
|
+
✓ extras: ["user_tier": user.tier] // Extract specific field
|
|
93
|
+
|
|
94
|
+
RULE: Extras should be < 10KB total per event
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
**Auto-Fix Suggestion:**
|
|
98
|
+
```
|
|
99
|
+
Found: extras: ["cart": cart]
|
|
100
|
+
Why bad: cart can be 1000+ items → 100KB+
|
|
101
|
+
Fix →
|
|
102
|
+
extras: [
|
|
103
|
+
"cart_item_count": cart.items.count,
|
|
104
|
+
"cart_total": cart.total,
|
|
105
|
+
"cart_has_promo": cart.promo != nil
|
|
106
|
+
]
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
### 4. Unstructured Logs
|
|
112
|
+
|
|
113
|
+
**MEDIUM** - Can't query or aggregate
|
|
114
|
+
|
|
115
|
+
```
|
|
116
|
+
PATTERNS TO DETECT:
|
|
117
|
+
❌ String interpolation: console.log(`User ${userId} failed`)
|
|
118
|
+
❌ Free-form text: log("Something went wrong")
|
|
119
|
+
❌ Mixed formats: log("Error: code=500, user=123")
|
|
120
|
+
|
|
121
|
+
✅ STRUCTURED ALTERNATIVES:
|
|
122
|
+
✓ logger.error("user_login_failed", { user_id: userId, reason: "timeout" })
|
|
123
|
+
✓ trackEvent("error", {
|
|
124
|
+
error_type: "login_failed",
|
|
125
|
+
user_id: userId,
|
|
126
|
+
reason: "timeout"
|
|
127
|
+
})
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
### 5. Sync Telemetry on Main Thread
|
|
133
|
+
|
|
134
|
+
**HIGH** - UI freezes
|
|
135
|
+
|
|
136
|
+
```
|
|
137
|
+
PATTERNS TO DETECT:
|
|
138
|
+
❌ trackEvent(...) in render / build / Composable
|
|
139
|
+
❌ captureError(...) without async / background
|
|
140
|
+
❌ flush() on main thread
|
|
141
|
+
❌ Network call inside instrumentation without queue
|
|
142
|
+
|
|
143
|
+
✅ SAFE ALTERNATIVES:
|
|
144
|
+
✓ trackEvent(...) → batches automatically (Sentry, Amplitude)
|
|
145
|
+
✓ captureError(...) → sends async (Firebase Crashlytics)
|
|
146
|
+
✓ Use background queue: DispatchQueue.global().async { ... }
|
|
147
|
+
✓ InteractionManager.runAfterInteractions(() => { ... })
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
---
|
|
151
|
+
|
|
152
|
+
### 6. Missing Context
|
|
153
|
+
|
|
154
|
+
**MEDIUM** - Events without correlation
|
|
155
|
+
|
|
156
|
+
```
|
|
157
|
+
REQUIRED CONTEXT FOR EVERY EVENT:
|
|
158
|
+
□ session_id (correlation)
|
|
159
|
+
□ screen (where it happened)
|
|
160
|
+
□ job_name (business goal: "checkout", "onboarding")
|
|
161
|
+
□ job_step (which step: "cart_review", "payment")
|
|
162
|
+
□ app_version (which release)
|
|
163
|
+
|
|
164
|
+
PATTERNS TO DETECT:
|
|
165
|
+
❌ trackEvent("button_tapped") // What button? Which screen?
|
|
166
|
+
❌ captureError(error) // No context
|
|
167
|
+
|
|
168
|
+
✅ COMPLETE EXAMPLES:
|
|
169
|
+
✓ trackEvent("button_tapped", {
|
|
170
|
+
button: "checkout_submit",
|
|
171
|
+
screen: "CartScreen",
|
|
172
|
+
job_name: "checkout",
|
|
173
|
+
job_step: "cart_review",
|
|
174
|
+
session_id: sessionId,
|
|
175
|
+
app_version: "1.2.3"
|
|
176
|
+
})
|
|
177
|
+
|
|
178
|
+
✓ captureError(error, {
|
|
179
|
+
screen: "PaymentScreen",
|
|
180
|
+
job_name: "checkout",
|
|
181
|
+
job_step: "payment",
|
|
182
|
+
session_id: sessionId
|
|
183
|
+
})
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
---
|
|
187
|
+
|
|
188
|
+
### 7. Mobile-Specific Anti-Patterns
|
|
189
|
+
|
|
190
|
+
#### React Native
|
|
191
|
+
|
|
192
|
+
```
|
|
193
|
+
❌ console.log in production (massive bottleneck)
|
|
194
|
+
❌ require() in render (re-executes every frame)
|
|
195
|
+
❌ Anonymous functions in FlatList renderItem
|
|
196
|
+
❌ Inline styles in render
|
|
197
|
+
❌ AsyncStorage for tokens (use SecureStore)
|
|
198
|
+
|
|
199
|
+
✅ CORRECT:
|
|
200
|
+
✓ __DEV__ && console.log(...)
|
|
201
|
+
✓ const Component = React.lazy(() => import(...))
|
|
202
|
+
✓ const renderItem = useCallback((item) => ..., [])
|
|
203
|
+
✓ const styles = StyleSheet.create({ ... })
|
|
204
|
+
✓ SecureStore.setItemAsync('token', token)
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
#### Flutter
|
|
208
|
+
|
|
209
|
+
```
|
|
210
|
+
❌ print() in production
|
|
211
|
+
❌ setState in build()
|
|
212
|
+
❌ Unbounded ListView (use ListView.builder)
|
|
213
|
+
❌ SharedPreferences for tokens (use flutter_secure_storage)
|
|
214
|
+
|
|
215
|
+
✅ CORRECT:
|
|
216
|
+
✓ kDebugMode && print(...)
|
|
217
|
+
✓ setState in event handlers, not build
|
|
218
|
+
✓ ListView.builder(itemCount: items.length, ...)
|
|
219
|
+
✓ await secureStorage.write(key: 'token', value: token)
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
#### iOS
|
|
223
|
+
|
|
224
|
+
```
|
|
225
|
+
❌ Force unwrap (!) without nil check
|
|
226
|
+
❌ Retain cycles ([self] in closures)
|
|
227
|
+
❌ UserDefaults for tokens (use Keychain)
|
|
228
|
+
❌ Heavy work on main thread
|
|
229
|
+
|
|
230
|
+
✅ CORRECT:
|
|
231
|
+
✓ guard let value = optional else { return }
|
|
232
|
+
✓ Capture [weak self] or [unowned self]
|
|
233
|
+
✓ KeychainWrapper.standard.set(token, forKey: "token")
|
|
234
|
+
✓ DispatchQueue.global().async { ... }
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
#### Android
|
|
238
|
+
|
|
239
|
+
```
|
|
240
|
+
❌ !! (force unwrap) without null check
|
|
241
|
+
❌ Memory leaks (Activity/Context references)
|
|
242
|
+
❌ SharedPreferences for tokens (use EncryptedSharedPreferences)
|
|
243
|
+
❌ AsyncTask (deprecated, use WorkManager)
|
|
244
|
+
|
|
245
|
+
✅ CORRECT:
|
|
246
|
+
✓ val value = optional ?: return
|
|
247
|
+
✓ Use ViewModel, avoid Activity refs in background
|
|
248
|
+
✓ EncryptedSharedPreferences for sensitive data
|
|
249
|
+
✓ WorkManager for background tasks
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
---
|
|
253
|
+
|
|
254
|
+
## Detection Workflow
|
|
255
|
+
|
|
256
|
+
```
|
|
257
|
+
PRE-COMMIT HOOK:
|
|
258
|
+
1. Scan all changed files for anti-patterns
|
|
259
|
+
2. Flag CRITICAL (block commit) vs HIGH (warn) vs MEDIUM (suggest)
|
|
260
|
+
3. Provide auto-fix suggestions
|
|
261
|
+
4. Run again after fix
|
|
262
|
+
|
|
263
|
+
DURING CODE REVIEW:
|
|
264
|
+
1. Agent scans PR diff
|
|
265
|
+
2. Comments on lines with anti-patterns
|
|
266
|
+
3. Suggests fixes inline
|
|
267
|
+
4. Links to this doc for explanation
|
|
268
|
+
|
|
269
|
+
CONTINUOUS:
|
|
270
|
+
1. Periodic full codebase scan
|
|
271
|
+
2. Generate report: violations by severity
|
|
272
|
+
3. Track trends (increasing/decreasing)
|
|
273
|
+
4. Alert if CRITICAL violations increase
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
---
|
|
277
|
+
|
|
278
|
+
## Severity Levels
|
|
279
|
+
|
|
280
|
+
| Severity | Impact | Action |
|
|
281
|
+
|----------|--------|--------|
|
|
282
|
+
| **CRITICAL** | PII leak, compliance risk | Block commit/PR |
|
|
283
|
+
| **HIGH** | Performance issue, crashes | Block commit, allow override |
|
|
284
|
+
| **MEDIUM** | Code smell, maintainability | Warn, suggest fix |
|
|
285
|
+
| **LOW** | Style, best practice | Suggest, don't block |
|
|
286
|
+
|
|
287
|
+
---
|
|
288
|
+
|
|
289
|
+
## Example: Full Detection Report
|
|
290
|
+
|
|
291
|
+
```
|
|
292
|
+
FILE: src/features/auth/LoginScreen.tsx
|
|
293
|
+
LINE 45: ❌ CRITICAL - PII Leak
|
|
294
|
+
Found: trackEvent("login", { email: user.email })
|
|
295
|
+
Fix: trackEvent("login", { has_email: user.email != nil })
|
|
296
|
+
Why: Email is PII → GDPR/CCPA violation
|
|
297
|
+
|
|
298
|
+
LINE 67: ❌ HIGH - High Cardinality
|
|
299
|
+
Found: tags: ["user_id": userId]
|
|
300
|
+
Fix: tags: ["user_tier": user.tier]
|
|
301
|
+
Why: user_id unbounded → storage explosion
|
|
302
|
+
|
|
303
|
+
LINE 89: ❌ MEDIUM - Missing Context
|
|
304
|
+
Found: captureError(error)
|
|
305
|
+
Fix: captureError(error, { screen: "LoginScreen", job_name: "auth" })
|
|
306
|
+
Why: Can't correlate error without context
|
|
307
|
+
|
|
308
|
+
FILE: src/services/analytics.ts
|
|
309
|
+
LINE 23: ❌ CRITICAL - Sync Telemetry on Main Thread
|
|
310
|
+
Found: trackEvent(...) in render()
|
|
311
|
+
Fix: Move to useEffect or InteractionManager.runAfterInteractions
|
|
312
|
+
Why: Blocks UI rendering → janky experience
|
|
313
|
+
|
|
314
|
+
Summary:
|
|
315
|
+
2 CRITICAL (block)
|
|
316
|
+
1 HIGH (warn)
|
|
317
|
+
1 MEDIUM (suggest)
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
---
|
|
321
|
+
|
|
322
|
+
## Auto-Fix Templates
|
|
323
|
+
|
|
324
|
+
### PII → Boolean
|
|
325
|
+
```typescript
|
|
326
|
+
// Before
|
|
327
|
+
trackEvent("signup", { email: user.email })
|
|
328
|
+
|
|
329
|
+
// After
|
|
330
|
+
trackEvent("signup", { has_email: user.email !== undefined })
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
### High Cardinality → Enum
|
|
334
|
+
```typescript
|
|
335
|
+
// Before
|
|
336
|
+
tags: ["user_id": userId]
|
|
337
|
+
|
|
338
|
+
// After
|
|
339
|
+
tags: ["user_tier": user.subscription.tier] // "free" | "premium" | "enterprise"
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
### Unbounded → Aggregate
|
|
343
|
+
```typescript
|
|
344
|
+
// Before
|
|
345
|
+
extras: ["cart": cart]
|
|
346
|
+
|
|
347
|
+
// After
|
|
348
|
+
extras: [
|
|
349
|
+
"cart_item_count": cart.items.length,
|
|
350
|
+
"cart_total_cents": cart.totalCents
|
|
351
|
+
]
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
### Missing Context → Complete
|
|
355
|
+
```typescript
|
|
356
|
+
// Before
|
|
357
|
+
trackEvent("button_tapped")
|
|
358
|
+
|
|
359
|
+
// After
|
|
360
|
+
trackEvent("button_tapped", {
|
|
361
|
+
button: "checkout_submit",
|
|
362
|
+
screen: "CartScreen",
|
|
363
|
+
job_name: "checkout",
|
|
364
|
+
job_step: "cart_review",
|
|
365
|
+
session_id: sessionManager.currentSessionId,
|
|
366
|
+
app_version: Constants.expoConfig?.version
|
|
367
|
+
})
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
---
|
|
371
|
+
|
|
372
|
+
## Integration with CI/CD
|
|
373
|
+
|
|
374
|
+
```bash
|
|
375
|
+
# Pre-commit hook
|
|
376
|
+
.git/hooks/pre-commit:
|
|
377
|
+
npm run detect-anti-patterns -- --severity=critical --block
|
|
378
|
+
|
|
379
|
+
# PR Check
|
|
380
|
+
.github/workflows/pr-check.yml:
|
|
381
|
+
- name: Detect Anti-Patterns
|
|
382
|
+
run: npm run detect-anti-patterns -- --severity=high --report
|
|
383
|
+
|
|
384
|
+
# Weekly Scan
|
|
385
|
+
.github/workflows/weekly-scan.yml:
|
|
386
|
+
schedule: cron('0 0 * * 0') # Every Sunday
|
|
387
|
+
run: npm run detect-anti-patterns -- --full-scan --report
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
---
|
|
391
|
+
|
|
392
|
+
## Learning from AI Tools
|
|
393
|
+
|
|
394
|
+
**Common mistakes AI tools make:**
|
|
395
|
+
|
|
396
|
+
| Tool | Mistake | Why |
|
|
397
|
+
|------|---------|-----|
|
|
398
|
+
| Cursor | Logs PII directly | Doesn't know GDPR/CCPA |
|
|
399
|
+
| Cline | Uses user_id as tag | Doesn't understand cardinality |
|
|
400
|
+
| Windsurf | Passes entire state objects | Doesn't check payload size |
|
|
401
|
+
| Devin | Sync telemetry on main thread | Doesn't profile performance impact |
|
|
402
|
+
|
|
403
|
+
**This skill avoids these by:**
|
|
404
|
+
- Scanning before commit
|
|
405
|
+
- Auto-suggesting fixes
|
|
406
|
+
- Blocking CRITICAL violations
|
|
407
|
+
- Teaching best practices
|