@buivietphi/skill-mobile-mt 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.
- package/AGENTS.md +392 -0
- package/README.md +224 -0
- package/SKILL.md +1048 -0
- package/android/android-native.md +208 -0
- package/bin/install.mjs +199 -0
- package/flutter/flutter.md +246 -0
- package/ios/ios-native.md +182 -0
- package/package.json +50 -0
- package/react-native/react-native.md +743 -0
- package/shared/agent-rules-template.md +343 -0
- package/shared/anti-patterns.md +407 -0
- package/shared/bug-detection.md +71 -0
- package/shared/claude-md-template.md +125 -0
- package/shared/code-review.md +121 -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/performance-prediction.md +210 -0
- package/shared/platform-excellence.md +159 -0
- package/shared/prompt-engineering.md +677 -0
- package/shared/release-checklist.md +82 -0
- package/shared/version-management.md +509 -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
|
|
@@ -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
|
+
```
|
|
@@ -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
|