@coralai/sps-cli 0.42.0 → 0.44.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/README.md +59 -4
- package/dist/commands/consoleCommand.d.ts +2 -0
- package/dist/commands/consoleCommand.d.ts.map +1 -0
- package/dist/commands/consoleCommand.js +129 -0
- package/dist/commands/consoleCommand.js.map +1 -0
- package/dist/commands/projectInit.d.ts.map +1 -1
- package/dist/commands/projectInit.js +40 -53
- package/dist/commands/projectInit.js.map +1 -1
- package/dist/commands/setup.d.ts.map +1 -1
- package/dist/commands/setup.js +14 -2
- package/dist/commands/setup.js.map +1 -1
- package/dist/commands/skillCommand.d.ts +2 -0
- package/dist/commands/skillCommand.d.ts.map +1 -0
- package/dist/commands/skillCommand.js +235 -0
- package/dist/commands/skillCommand.js.map +1 -0
- package/dist/console-assets/assets/index-Bhd2f9AP.js +125 -0
- package/dist/console-assets/assets/index-bsAN2a12.css +1 -0
- package/dist/console-assets/index.html +16 -0
- package/dist/console-server/index.d.ts +29 -0
- package/dist/console-server/index.d.ts.map +1 -0
- package/dist/console-server/index.js +145 -0
- package/dist/console-server/index.js.map +1 -0
- package/dist/console-server/lib/lockFile.d.ts +17 -0
- package/dist/console-server/lib/lockFile.d.ts.map +1 -0
- package/dist/console-server/lib/lockFile.js +61 -0
- package/dist/console-server/lib/lockFile.js.map +1 -0
- package/dist/console-server/lib/portPicker.d.ts +3 -0
- package/dist/console-server/lib/portPicker.d.ts.map +1 -0
- package/dist/console-server/lib/portPicker.js +25 -0
- package/dist/console-server/lib/portPicker.js.map +1 -0
- package/dist/console-server/routes/projects.d.ts +11 -0
- package/dist/console-server/routes/projects.d.ts.map +1 -0
- package/dist/console-server/routes/projects.js +149 -0
- package/dist/console-server/routes/projects.js.map +1 -0
- package/dist/console-server/routes/system.d.ts +7 -0
- package/dist/console-server/routes/system.d.ts.map +1 -0
- package/dist/console-server/routes/system.js +19 -0
- package/dist/console-server/routes/system.js.map +1 -0
- package/dist/console-server/sse/eventBus.d.ts +25 -0
- package/dist/console-server/sse/eventBus.d.ts.map +1 -0
- package/dist/console-server/sse/eventBus.js +32 -0
- package/dist/console-server/sse/eventBus.js.map +1 -0
- package/dist/console-server/watchers/cardWatcher.d.ts +9 -0
- package/dist/console-server/watchers/cardWatcher.d.ts.map +1 -0
- package/dist/console-server/watchers/cardWatcher.js +42 -0
- package/dist/console-server/watchers/cardWatcher.js.map +1 -0
- package/dist/core/skillStore.d.ts +46 -0
- package/dist/core/skillStore.d.ts.map +1 -0
- package/dist/core/skillStore.js +210 -0
- package/dist/core/skillStore.js.map +1 -0
- package/dist/core/skillStore.test.d.ts +2 -0
- package/dist/core/skillStore.test.d.ts.map +1 -0
- package/dist/core/skillStore.test.js +203 -0
- package/dist/core/skillStore.test.js.map +1 -0
- package/dist/main.js +27 -17
- package/dist/main.js.map +1 -1
- package/package.json +8 -2
- package/skills/architecture-decision-records/SKILL.md +207 -0
- package/skills/backend/SKILL.md +62 -0
- package/skills/backend/references/api-design.md +168 -0
- package/skills/backend/references/caching.md +181 -0
- package/skills/backend/references/data-access.md +173 -0
- package/skills/backend/references/layering.md +181 -0
- package/skills/backend/references/observability.md +190 -0
- package/skills/backend/references/resilience.md +201 -0
- package/skills/backend/references/security.md +186 -0
- package/skills/backend-architect/SKILL.md +119 -0
- package/skills/code-reviewer/SKILL.md +143 -0
- package/skills/coding-standards/SKILL.md +60 -0
- package/skills/coding-standards/references/clean-code.md +258 -0
- package/skills/coding-standards/references/code-review.md +192 -0
- package/skills/coding-standards/references/commits-and-prs.md +226 -0
- package/skills/coding-standards/references/error-strategy.md +193 -0
- package/skills/coding-standards/references/naming.md +185 -0
- package/skills/coding-standards/references/tdd.md +171 -0
- package/skills/database/SKILL.md +53 -0
- package/skills/database/references/indexing.md +190 -0
- package/skills/database/references/migrations.md +199 -0
- package/skills/database/references/nosql.md +185 -0
- package/skills/database/references/queries.md +295 -0
- package/skills/database/references/scaling.md +203 -0
- package/skills/database/references/schema.md +191 -0
- package/skills/database-optimizer/SKILL.md +168 -0
- package/skills/debugging-workflow/SKILL.md +244 -0
- package/skills/devops/SKILL.md +55 -0
- package/skills/devops/references/ci-cd.md +204 -0
- package/skills/devops/references/containers.md +272 -0
- package/skills/devops/references/deploy.md +201 -0
- package/skills/devops/references/iac.md +252 -0
- package/skills/devops/references/observability.md +228 -0
- package/skills/devops/references/secrets.md +178 -0
- package/skills/devops-automator/SKILL.md +164 -0
- package/skills/frontend/SKILL.md +52 -0
- package/skills/frontend/references/accessibility.md +222 -0
- package/skills/frontend/references/components.md +206 -0
- package/skills/frontend/references/performance.md +219 -0
- package/skills/frontend/references/routing.md +209 -0
- package/skills/frontend/references/state.md +190 -0
- package/skills/frontend/references/testing.md +216 -0
- package/skills/frontend-developer/SKILL.md +115 -0
- package/skills/git-workflow/SKILL.md +355 -0
- package/skills/golang/SKILL.md +49 -0
- package/skills/golang/references/concurrency.md +284 -0
- package/skills/golang/references/errors.md +241 -0
- package/skills/golang/references/idioms.md +285 -0
- package/skills/golang/references/testing.md +238 -0
- package/skills/java/SKILL.md +50 -0
- package/skills/java/references/concurrency.md +194 -0
- package/skills/java/references/idioms.md +283 -0
- package/skills/java/references/testing.md +228 -0
- package/skills/kotlin/SKILL.md +47 -0
- package/skills/kotlin/references/coroutines.md +240 -0
- package/skills/kotlin/references/idioms.md +268 -0
- package/skills/kotlin/references/testing.md +219 -0
- package/skills/mobile/SKILL.md +50 -0
- package/skills/mobile/references/architecture.md +204 -0
- package/skills/mobile/references/navigation.md +158 -0
- package/skills/mobile/references/performance.md +152 -0
- package/skills/mobile/references/platform.md +166 -0
- package/skills/mobile/references/state-and-data.md +174 -0
- package/skills/python/SKILL.md +51 -0
- package/skills/python/THIRD_PARTY.md +14 -0
- package/skills/python/references/async.md +218 -0
- package/skills/python/references/error-handling.md +254 -0
- package/skills/python/references/idioms.md +279 -0
- package/skills/python/references/packaging.md +233 -0
- package/skills/python/references/testing.md +269 -0
- package/skills/python/references/typing.md +292 -0
- package/skills/qa-tester/SKILL.md +186 -0
- package/skills/rust/SKILL.md +50 -0
- package/skills/rust/references/async.md +224 -0
- package/skills/rust/references/errors.md +240 -0
- package/skills/rust/references/ownership.md +263 -0
- package/skills/rust/references/testing.md +274 -0
- package/skills/rust/references/traits.md +250 -0
- package/skills/security-engineer/SKILL.md +157 -0
- package/skills/swift/SKILL.md +48 -0
- package/skills/swift/references/concurrency.md +280 -0
- package/skills/swift/references/idioms.md +334 -0
- package/skills/swift/references/testing.md +229 -0
- package/skills/typescript/SKILL.md +51 -0
- package/skills/typescript/references/async.md +241 -0
- package/skills/typescript/references/errors.md +208 -0
- package/skills/typescript/references/idioms.md +246 -0
- package/skills/typescript/references/testing.md +225 -0
- package/skills/typescript/references/tooling.md +208 -0
- package/skills/typescript/references/types.md +259 -0
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
# Mobile — Performance
|
|
2
|
+
|
|
3
|
+
Startup, frame rate, memory, battery, app size.
|
|
4
|
+
|
|
5
|
+
## Measure first
|
|
6
|
+
|
|
7
|
+
- **iOS**: Xcode Instruments — Time Profiler, Allocations, Energy Log, App Launch template.
|
|
8
|
+
- **Android**: Android Studio Profiler, Macrobenchmark, Perfetto, Battery Historian.
|
|
9
|
+
- **Cross-platform**: framework-specific profilers (React Native Flipper, Flutter DevTools).
|
|
10
|
+
|
|
11
|
+
No optimization without a profile. Anecdotes lie; flame graphs don't.
|
|
12
|
+
|
|
13
|
+
## Startup
|
|
14
|
+
|
|
15
|
+
Cold start = process launch → first meaningful screen. Budget:
|
|
16
|
+
- iOS: < 400 ms to first frame (Apple's guideline).
|
|
17
|
+
- Android: < 5 s for cold start acceptable; < 2 s is good.
|
|
18
|
+
|
|
19
|
+
Common startup killers:
|
|
20
|
+
- Synchronous work in `Application` / `AppDelegate` init (SDK init, network pings).
|
|
21
|
+
- Excessive DI graph construction at cold start.
|
|
22
|
+
- Loading a huge JSON on the main thread.
|
|
23
|
+
- First screen fetching data sequentially.
|
|
24
|
+
|
|
25
|
+
Strategy:
|
|
26
|
+
1. **Do nothing on launch** that isn't required to render the first screen.
|
|
27
|
+
2. **Defer SDK init** (analytics, crash reporter) using platform idle callbacks.
|
|
28
|
+
3. **Show a real UI fast** — skeleton, cached content, progressive hydration.
|
|
29
|
+
4. **Parallelize first-screen data fetches.**
|
|
30
|
+
|
|
31
|
+
## Frame rate — 60 fps / 120 fps
|
|
32
|
+
|
|
33
|
+
16.67 ms per frame at 60 Hz; 8.33 ms at 120 Hz. A frame budget missed = visible jank.
|
|
34
|
+
|
|
35
|
+
- **Never block the UI thread** with disk, network, JSON parsing, or big computations.
|
|
36
|
+
- **Measure jank** with the platform tool (Choreographer on Android, Core Animation FPS on iOS).
|
|
37
|
+
- **Move work off-main**:
|
|
38
|
+
- Android: coroutines on `Dispatchers.Default` / `IO`; Compose's `LaunchedEffect`.
|
|
39
|
+
- iOS: `Task.detached(priority: .utility)` / async functions.
|
|
40
|
+
- Cross-platform: web workers, Dart isolates.
|
|
41
|
+
|
|
42
|
+
## Lists — virtualize
|
|
43
|
+
|
|
44
|
+
Any list with > ~50 items should virtualize (render only what's visible).
|
|
45
|
+
|
|
46
|
+
- **iOS**: `UITableView` / `UICollectionView` already do; `LazyVStack` in SwiftUI; avoid mapping huge arrays into `ForEach` inside `ScrollView`.
|
|
47
|
+
- **Android**: `RecyclerView` / `LazyColumn` (Compose). Set `contentType` / `key` for recycling.
|
|
48
|
+
- **React Native**: `FlatList` / `SectionList` with `keyExtractor` and `getItemLayout`.
|
|
49
|
+
- **Flutter**: `ListView.builder` / `SliverList`.
|
|
50
|
+
|
|
51
|
+
Rules:
|
|
52
|
+
- Every row has a stable key.
|
|
53
|
+
- `shouldRecompose` / `areItemsTheSame` return correctly.
|
|
54
|
+
- Avoid inline lambdas that change identity every render.
|
|
55
|
+
|
|
56
|
+
## Images
|
|
57
|
+
|
|
58
|
+
Biggest single memory user in typical apps.
|
|
59
|
+
|
|
60
|
+
- Use a cached image loader (Coil, Glide, SDWebImage, Kingfisher, FastImage for RN).
|
|
61
|
+
- Decode to the display size, not the source size. A 4000 × 3000 photo in a 300-pt avatar is a memory bomb.
|
|
62
|
+
- Cache policies: memory (tight), disk (generous, bounded), TTL for dynamic URLs.
|
|
63
|
+
- Placeholders + fade-in; avoid layout shift.
|
|
64
|
+
|
|
65
|
+
## Memory
|
|
66
|
+
|
|
67
|
+
- Hold what you're rendering. Let the rest evict.
|
|
68
|
+
- Bitmap-heavy screens (photo grids, video thumbnails) need aggressive recycling.
|
|
69
|
+
- Watch for retain cycles (iOS) / context leaks (Android). A ViewModel holding a View, a Handler with an activity reference — standard leaks.
|
|
70
|
+
- Detekt / leak-detection tools: LeakCanary (Android), Instruments Leaks (iOS), profile before release.
|
|
71
|
+
|
|
72
|
+
## Battery
|
|
73
|
+
|
|
74
|
+
Users notice battery drain. What costs most:
|
|
75
|
+
- **Network chatter** (small requests often > big requests rarely).
|
|
76
|
+
- **Wakeups** (alarms, background fetches, location).
|
|
77
|
+
- **Sensors** (GPS, accelerometer, BT scan) when used continuously.
|
|
78
|
+
- **Bad CPU loops** (unnecessary re-renders, background polling).
|
|
79
|
+
|
|
80
|
+
Rules:
|
|
81
|
+
- Batch network calls where you can.
|
|
82
|
+
- Use platform background scheduler (`WorkManager`, `BGTaskScheduler`) — they batch across apps.
|
|
83
|
+
- Respect Doze / Low Power Mode signals.
|
|
84
|
+
- Don't hold wake locks or background location without a visible reason.
|
|
85
|
+
|
|
86
|
+
## App size
|
|
87
|
+
|
|
88
|
+
Each MB costs downloads, installs, abandonment. Rough targets:
|
|
89
|
+
- < 50 MB initial download is great.
|
|
90
|
+
- Over 100 MB, users on cellular are warned.
|
|
91
|
+
|
|
92
|
+
Tools:
|
|
93
|
+
- Android App Bundle splits by ABI / language / density.
|
|
94
|
+
- iOS: App Thinning, on-demand resources.
|
|
95
|
+
- Strip debug symbols in release.
|
|
96
|
+
- Audit deps — one chart library can add 5 MB of unused code.
|
|
97
|
+
|
|
98
|
+
## Package size audit
|
|
99
|
+
|
|
100
|
+
Largest offenders, in order:
|
|
101
|
+
1. Unstripped native libraries (x86 + arm + arm64 + armv7).
|
|
102
|
+
2. Bundled fonts / images / videos.
|
|
103
|
+
3. Heavy SDKs (ads, analytics) that ship more than they use.
|
|
104
|
+
4. Translations (if your app ships without user-language stripping).
|
|
105
|
+
5. Debug info left in release.
|
|
106
|
+
|
|
107
|
+
## Launch / anim / transition perf
|
|
108
|
+
|
|
109
|
+
- Launch screen: show the UI immediately (Asset catalog on iOS, splash theme on Android). Don't build your own splash from a UIKit / Activity — it's slower.
|
|
110
|
+
- Transitions: use platform defaults; they're hardware-accelerated. Custom animations often miss frames on low-end devices.
|
|
111
|
+
- Prefer `transform` / `opacity` equivalents over layout-triggering properties.
|
|
112
|
+
|
|
113
|
+
## Network
|
|
114
|
+
|
|
115
|
+
- HTTP/2 or HTTP/3 → multiplexing reduces handshake cost.
|
|
116
|
+
- Response compression (gzip / brotli) on.
|
|
117
|
+
- Cache-Control on static assets; ETag for dynamic.
|
|
118
|
+
- Retry with backoff on failures.
|
|
119
|
+
- Consider **delta** payloads for large lists (send only what changed).
|
|
120
|
+
|
|
121
|
+
## Ahead-of-time vs JIT
|
|
122
|
+
|
|
123
|
+
- Android R8 / ProGuard: enable in release. Strips unused code and shrinks bundles.
|
|
124
|
+
- iOS: always AOT; no JIT. Focus on link-time optimization (`-Os`, whole-module).
|
|
125
|
+
- Cross-platform: Hermes (RN), Flutter AOT — verify you're in release mode.
|
|
126
|
+
|
|
127
|
+
## Benchmarks in CI
|
|
128
|
+
|
|
129
|
+
Macrobenchmark (Android) or Instruments via XCTest (iOS) can run critical-flow timing on every merge. Fail builds on regression beyond threshold.
|
|
130
|
+
|
|
131
|
+
```
|
|
132
|
+
@Test
|
|
133
|
+
fun startup() = benchmarkRule.measureRepeated(
|
|
134
|
+
packageName = PACKAGE,
|
|
135
|
+
metrics = listOf(StartupTimingMetric()),
|
|
136
|
+
) { pressHome(); startActivityAndWait() }
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## Anti-patterns
|
|
140
|
+
|
|
141
|
+
| Anti-pattern | Fix |
|
|
142
|
+
|---|---|
|
|
143
|
+
| Loading full profile on every screen | Cache; invalidate on change |
|
|
144
|
+
| Images served at 4K for 400 px displays | Server-side resizing or loader |
|
|
145
|
+
| Launch SDK initialization chain takes 2 seconds | Defer; init on first use |
|
|
146
|
+
| Rendering a grid without virtualization | Use the platform list |
|
|
147
|
+
| Polling for notifications every 10 seconds | Push / long-poll |
|
|
148
|
+
| JSON parse on main thread for big payloads | Background + stream |
|
|
149
|
+
| Keeping full Log / PDF in memory | Stream; flush |
|
|
150
|
+
| Shipping debug logs in release | Strip |
|
|
151
|
+
| Background location for features that don't need it | Request only when needed |
|
|
152
|
+
| Running animations during heavy scroll | Throttle or pause |
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
# Mobile — Platform
|
|
2
|
+
|
|
3
|
+
Permissions, notifications, background tasks, biometrics, secure storage.
|
|
4
|
+
|
|
5
|
+
## Permissions
|
|
6
|
+
|
|
7
|
+
Request at the moment of need, not upfront.
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
User taps "Add photo" → now request camera / library permission.
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Flow:
|
|
14
|
+
1. Check current status.
|
|
15
|
+
2. If not determined: show an in-app primer ("to attach photos we need access to…"), then prompt.
|
|
16
|
+
3. If denied: show clear "open Settings" guidance; don't re-prompt (iOS won't show the sheet again anyway).
|
|
17
|
+
|
|
18
|
+
Never:
|
|
19
|
+
- Ask for all permissions on first launch.
|
|
20
|
+
- Block the app on denied permissions (degrade gracefully).
|
|
21
|
+
- Auto-grant — users must choose.
|
|
22
|
+
|
|
23
|
+
Required: `NSUsageDescription` (iOS) / permission declarations (Android) with accurate copy. App stores reject vague ones.
|
|
24
|
+
|
|
25
|
+
## Sensitive permissions
|
|
26
|
+
|
|
27
|
+
| Permission | Treat as |
|
|
28
|
+
|---|---|
|
|
29
|
+
| Location (especially background) | Justify prominently, explain precisely how it's used |
|
|
30
|
+
| Camera / microphone | Visible indicator while active (OS usually does this) |
|
|
31
|
+
| Contacts / Photos / Calendar | Scoped access preferred (iOS 14+, Android 13+) |
|
|
32
|
+
| Notifications (iOS) | Explicit opt-in; user deciding = one chance on iOS |
|
|
33
|
+
| Accessibility services (Android) | High review bar; stores scrutinize |
|
|
34
|
+
|
|
35
|
+
## Notifications
|
|
36
|
+
|
|
37
|
+
### Local
|
|
38
|
+
|
|
39
|
+
For time / event reminders the device can schedule.
|
|
40
|
+
|
|
41
|
+
```
|
|
42
|
+
schedule(id, triggerDate, contentTitle, contentBody)
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Rules:
|
|
46
|
+
- Idempotent id — rescheduling replaces.
|
|
47
|
+
- Cancel stale notifications on state change (task done → remove reminder).
|
|
48
|
+
- Respect quiet hours / Focus / DND.
|
|
49
|
+
|
|
50
|
+
### Push
|
|
51
|
+
|
|
52
|
+
Server-driven. Flow:
|
|
53
|
+
1. App requests token (APNs on iOS, FCM on Android).
|
|
54
|
+
2. Token sent to server, associated with user.
|
|
55
|
+
3. Server delivers payloads via APNs / FCM.
|
|
56
|
+
|
|
57
|
+
Content types:
|
|
58
|
+
- **Alert / default** — visible to user.
|
|
59
|
+
- **Silent / data-only** — wakes app to sync; no UI. Limited budget; iOS throttles.
|
|
60
|
+
|
|
61
|
+
Handle:
|
|
62
|
+
- Token rotation (OS may refresh; always sync to server).
|
|
63
|
+
- Logout: unregister token.
|
|
64
|
+
- Quiet / opt-out preferences server-side.
|
|
65
|
+
|
|
66
|
+
## Background tasks
|
|
67
|
+
|
|
68
|
+
Apps don't run in the background forever. Platforms give scheduled, constrained windows.
|
|
69
|
+
|
|
70
|
+
- **iOS**: `BGAppRefreshTask`, `BGProcessingTask` via `BGTaskScheduler`. Short windows, system-decided.
|
|
71
|
+
- **Android**: `WorkManager` — one API, handles Doze / idle batching. Avoid `AlarmManager` for modern apps.
|
|
72
|
+
- **Cross-platform**: framework wrappers around the above.
|
|
73
|
+
|
|
74
|
+
Rules:
|
|
75
|
+
- Keep work short and idempotent.
|
|
76
|
+
- Don't assume a window will run at a specific time.
|
|
77
|
+
- Don't rely on background work for correctness — network may be off.
|
|
78
|
+
|
|
79
|
+
## Biometrics
|
|
80
|
+
|
|
81
|
+
```
|
|
82
|
+
if canAuth(.biometrics):
|
|
83
|
+
await authenticate(reason: "Unlock your vault")
|
|
84
|
+
else:
|
|
85
|
+
await authenticate(.passcode) // fallback
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
- iOS: `LocalAuthentication` / `LAContext`.
|
|
89
|
+
- Android: `BiometricPrompt`.
|
|
90
|
+
|
|
91
|
+
Never store actual biometric data. Use it to gate access to a key in Keychain / Keystore.
|
|
92
|
+
|
|
93
|
+
## Secure storage
|
|
94
|
+
|
|
95
|
+
| Need | Store |
|
|
96
|
+
|---|---|
|
|
97
|
+
| API tokens, refresh tokens | Keychain (iOS) / EncryptedSharedPreferences / DataStore with a master key (Android) |
|
|
98
|
+
| Encryption keys | Keychain / Keystore, hardware-backed where available |
|
|
99
|
+
| User preferences (non-sensitive) | UserDefaults / DataStore |
|
|
100
|
+
| Caches | App sandbox directory; wipe on logout |
|
|
101
|
+
|
|
102
|
+
Never:
|
|
103
|
+
- Tokens in `UserDefaults` / `SharedPreferences`.
|
|
104
|
+
- Plain-text credentials anywhere.
|
|
105
|
+
- Logging full tokens (even at DEBUG).
|
|
106
|
+
|
|
107
|
+
## Network security
|
|
108
|
+
|
|
109
|
+
- HTTPS with modern TLS (1.2 minimum, 1.3 preferred).
|
|
110
|
+
- **ATS** on iOS — use default settings; exceptions require justification.
|
|
111
|
+
- **Network Security Config** on Android — restrict cleartext.
|
|
112
|
+
- **Certificate pinning** for high-value endpoints. Pin the intermediate or leaf; plan the rotation.
|
|
113
|
+
|
|
114
|
+
## App Transport / Deep Link security
|
|
115
|
+
|
|
116
|
+
- Validate deep-link parameters; treat them as user input.
|
|
117
|
+
- Never execute code based on query string (e.g., "open this URL in WebView" without allow-list).
|
|
118
|
+
- For login-via-deep-link, verify signature; intermediaries may tamper.
|
|
119
|
+
|
|
120
|
+
## Web views
|
|
121
|
+
|
|
122
|
+
Minimize them. When unavoidable:
|
|
123
|
+
- Use `WKWebView` (iOS) / `WebView` with hardened settings (Android).
|
|
124
|
+
- Disable `allowFileAccess`, `javascriptEnabled` unless required.
|
|
125
|
+
- Never inject tokens into URLs loaded in web views.
|
|
126
|
+
|
|
127
|
+
For OAuth / in-app browser tabs (SFSafariViewController / Chrome Custom Tabs) — safer than a generic WebView because cookies and saved passwords work.
|
|
128
|
+
|
|
129
|
+
## Hardware surveys
|
|
130
|
+
|
|
131
|
+
When using camera / sensors / Bluetooth:
|
|
132
|
+
- Check availability (`AVCaptureDevice`, hardware feature on Android).
|
|
133
|
+
- Fail gracefully on missing hardware.
|
|
134
|
+
- Release resources on background / pause.
|
|
135
|
+
- Don't leave LEDs on or Bluetooth scanning when the feature is closed.
|
|
136
|
+
|
|
137
|
+
## Accessibility at the platform level
|
|
138
|
+
|
|
139
|
+
- iOS: VoiceOver, Dynamic Type, Reduce Motion, Bold Text, Smart Invert.
|
|
140
|
+
- Android: TalkBack, font scale, color correction, reduce animations.
|
|
141
|
+
|
|
142
|
+
Use the platform's semantic accessibility APIs, not custom text-to-speech.
|
|
143
|
+
|
|
144
|
+
Test at 200% font scale. Layout should expand gracefully, not truncate.
|
|
145
|
+
|
|
146
|
+
## Crash reporting
|
|
147
|
+
|
|
148
|
+
- Firebase Crashlytics, Sentry, BugSnag, custom — pick one.
|
|
149
|
+
- Capture: stack trace, device, OS version, app version, user id (hashed or opt-in).
|
|
150
|
+
- Log breadcrumbs — screen views, key user actions — to reconstruct what happened.
|
|
151
|
+
- De-symbolicate iOS crashes with dSYMs uploaded in CI. Android: ProGuard mapping files.
|
|
152
|
+
|
|
153
|
+
## Anti-patterns
|
|
154
|
+
|
|
155
|
+
| Anti-pattern | Fix |
|
|
156
|
+
|---|---|
|
|
157
|
+
| Requesting all permissions upfront | Ask at point of need |
|
|
158
|
+
| Tokens in UserDefaults / SharedPreferences | Keychain / Keystore |
|
|
159
|
+
| Background location without clear benefit | Foreground only |
|
|
160
|
+
| Polling in the background for "real-time" | Push notifications / WebSockets (when foreground) |
|
|
161
|
+
| Running as foreground service to bypass Doze | Violates Play Store policy |
|
|
162
|
+
| Opening external URLs in an in-app WebView with cookies | Use in-app browser tab |
|
|
163
|
+
| Using the older / deprecated `AlarmManager` for everything | WorkManager on modern Android |
|
|
164
|
+
| Stripping ATS / NSC to "make it easier" | Fix the server; don't open cleartext in prod |
|
|
165
|
+
| Hard-coded production API keys | Environment-specific config; rotate on leak |
|
|
166
|
+
| Silent push used for analytics (abuses the privilege) | Real notification or in-app event |
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
# Mobile — State & Data
|
|
2
|
+
|
|
3
|
+
Local store, sync, offline-first, optimistic updates, reactive streams.
|
|
4
|
+
|
|
5
|
+
## Offline-first
|
|
6
|
+
|
|
7
|
+
Network is the slow, unreliable layer. Design the app so the local store is the fast path; the network syncs in the background.
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
UI ──reads──▶ Local Store ◀──writes sync── API
|
|
11
|
+
──writes──▶ Local Store + Outbox ──drain──▶ API
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Benefits:
|
|
15
|
+
- Cold start without network → user still sees cached content.
|
|
16
|
+
- Actions feel instant (optimistic + outbox).
|
|
17
|
+
- Seamless reconnection; app doesn't die on Wi-Fi flip.
|
|
18
|
+
|
|
19
|
+
## Local storage choices
|
|
20
|
+
|
|
21
|
+
| Store | Platform / Cross | Shape |
|
|
22
|
+
|---|---|---|
|
|
23
|
+
| SQLite (direct) | All | Relational, battle-tested |
|
|
24
|
+
| Room | Android | SQLite ORM; compile-time query checking |
|
|
25
|
+
| Core Data / SwiftData | iOS | Object graph |
|
|
26
|
+
| Realm | Cross | Object DB, live objects |
|
|
27
|
+
| SQLDelight | KMP / cross | SQL-first, multiplatform |
|
|
28
|
+
| MMKV / DataStore | Key-value | Simple prefs, fast, typed |
|
|
29
|
+
| Keychain / Keystore | All | Secrets |
|
|
30
|
+
|
|
31
|
+
Rule: one primary store per domain. Mixing Room + Realm + a JSON cache for the same data creates reconciliation hell.
|
|
32
|
+
|
|
33
|
+
## Cache + network reconcile
|
|
34
|
+
|
|
35
|
+
### Stale-while-revalidate
|
|
36
|
+
|
|
37
|
+
Return cached data immediately; refresh in the background.
|
|
38
|
+
|
|
39
|
+
```
|
|
40
|
+
suspend fun getUser(id: String): Flow<User> = flow {
|
|
41
|
+
emit(cache.get(id)) // instant
|
|
42
|
+
try {
|
|
43
|
+
val fresh = api.getUser(id)
|
|
44
|
+
cache.put(id, fresh)
|
|
45
|
+
emit(fresh) // update UI
|
|
46
|
+
} catch (_: IOException) {
|
|
47
|
+
// offline; keep showing cached
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Freshness policy
|
|
53
|
+
|
|
54
|
+
Some data is OK to show even if hours old (product catalog); some must be current (bank balance). Per-type policy:
|
|
55
|
+
|
|
56
|
+
```
|
|
57
|
+
policy[User] = staleAfter(5.minutes)
|
|
58
|
+
policy[ProductList] = staleAfter(24.hours)
|
|
59
|
+
policy[Balance] = alwaysRefresh
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Optimistic updates + outbox
|
|
63
|
+
|
|
64
|
+
For user-driven writes, show the expected result immediately; queue the server call; reconcile.
|
|
65
|
+
|
|
66
|
+
```
|
|
67
|
+
place_order(order):
|
|
68
|
+
local.insert(order.copy(status=PENDING))
|
|
69
|
+
outbox.enqueue(PostOrder(order.id))
|
|
70
|
+
return order.id # UI navigates away instantly
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
The outbox worker:
|
|
74
|
+
1. Reads next job.
|
|
75
|
+
2. Calls the server (with retry + backoff).
|
|
76
|
+
3. On success: update local row (`status=CONFIRMED`), remove job.
|
|
77
|
+
4. On permanent failure: mark local row (`status=FAILED`), notify user, drop job.
|
|
78
|
+
|
|
79
|
+
Conflict strategy when the server returns a different truth (e.g., order replaced due to out-of-stock): domain decides — replace, merge, prompt user.
|
|
80
|
+
|
|
81
|
+
## Queue vs. sync protocol
|
|
82
|
+
|
|
83
|
+
Simple apps: an outbox table with next-id, retry count, last-error. Good enough.
|
|
84
|
+
|
|
85
|
+
Complex sync (collaborative editing, multi-device): use a sync framework (CRDTs, Yjs, Automerge, Firebase, CouchDB). Implementing one by hand is a trap.
|
|
86
|
+
|
|
87
|
+
## Reactive streams everywhere
|
|
88
|
+
|
|
89
|
+
Mobile UIs love reactivity because the underlying data changes often.
|
|
90
|
+
|
|
91
|
+
| Tech | Stream type |
|
|
92
|
+
|---|---|
|
|
93
|
+
| Kotlin | `Flow`, `StateFlow`, `SharedFlow` |
|
|
94
|
+
| Swift (Apple) | `Publisher` (Combine), `AsyncStream`, `Observable` |
|
|
95
|
+
| RxJava / RxSwift | `Observable`, `Flowable` |
|
|
96
|
+
| React Native | Hooks + state libs |
|
|
97
|
+
|
|
98
|
+
Your repository exposes a stream. The ViewModel transforms. The view collects.
|
|
99
|
+
|
|
100
|
+
```
|
|
101
|
+
// Kotlin
|
|
102
|
+
val user: StateFlow<User?> = userRepo.observe(id)
|
|
103
|
+
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5_000), null)
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
`WhileSubscribed(5_000)`: keeps the upstream alive 5s after the last subscriber — survives rotation without a cold re-fetch.
|
|
107
|
+
|
|
108
|
+
## Pagination
|
|
109
|
+
|
|
110
|
+
Two patterns:
|
|
111
|
+
|
|
112
|
+
### Offset / page
|
|
113
|
+
|
|
114
|
+
Simple but breaks when rows are inserted during paging. OK for static lists.
|
|
115
|
+
|
|
116
|
+
### Cursor / keyset
|
|
117
|
+
|
|
118
|
+
Opaque cursor that points to the last-seen item. Stable across inserts.
|
|
119
|
+
|
|
120
|
+
```
|
|
121
|
+
interface OrderApi {
|
|
122
|
+
suspend fun list(cursor: String?, limit: Int): Page<Order>
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
data class Page<T>(val data: List<T>, val nextCursor: String?)
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
Platform paging libs (Jetpack Paging, TCA Pagination) handle prefetch, retry, error states. Use them; rolling your own is a maintenance burden.
|
|
129
|
+
|
|
130
|
+
## Forms & input
|
|
131
|
+
|
|
132
|
+
- **Draft persistence**: save form input to local store keyed by form id. Survive process death.
|
|
133
|
+
- **Validation**: same schema on client and server (share via contract or mirror carefully).
|
|
134
|
+
- **Submit**: optimistic + outbox if idempotent; otherwise show submitting state.
|
|
135
|
+
|
|
136
|
+
## Images
|
|
137
|
+
|
|
138
|
+
The single biggest memory user and jank source in mobile.
|
|
139
|
+
|
|
140
|
+
- Use the platform image loader (Coil / Glide on Android, SDWebImage / Kingfisher on iOS).
|
|
141
|
+
- Resize to the display size **on the server** (API returns `url?w=400`) or via the loader.
|
|
142
|
+
- Cache aggressively; size the cache (e.g. 100 MB disk, 50 MB memory).
|
|
143
|
+
- Placeholders + cross-fade; never show a flash of broken image.
|
|
144
|
+
|
|
145
|
+
## Real-time updates
|
|
146
|
+
|
|
147
|
+
- **Polling**: simple, works offline, battery-expensive. OK for low-urgency data.
|
|
148
|
+
- **WebSockets / SSE**: real-time, drains battery if poorly scoped. Tear down in background.
|
|
149
|
+
- **Push notifications**: for out-of-app updates. Use silent push to wake and sync.
|
|
150
|
+
|
|
151
|
+
Rule: subscribe only when the user is looking. Unsubscribe on background / detached views.
|
|
152
|
+
|
|
153
|
+
## Data security
|
|
154
|
+
|
|
155
|
+
See `security.md` for the big picture. Quick must-dos:
|
|
156
|
+
|
|
157
|
+
- Tokens / secrets → Keychain (iOS) or EncryptedSharedPreferences / Keystore (Android).
|
|
158
|
+
- Never log full tokens.
|
|
159
|
+
- HTTPS only. Pin certificates for critical endpoints where your threat model warrants.
|
|
160
|
+
- Wipe sensitive caches on logout.
|
|
161
|
+
|
|
162
|
+
## Anti-patterns
|
|
163
|
+
|
|
164
|
+
| Anti-pattern | Fix |
|
|
165
|
+
|---|---|
|
|
166
|
+
| Fetching on every screen entry | Cache + observe; fetch only when stale |
|
|
167
|
+
| Syncing all data up-front on login | Lazy load; fetch on demand |
|
|
168
|
+
| Outbox without retry / backoff | Loop; drain with exponential backoff |
|
|
169
|
+
| Showing "please wait, syncing…" for every write | Optimistic + outbox |
|
|
170
|
+
| Global mutable store for server data | Repository + reactive stream |
|
|
171
|
+
| Ignoring background / killed state | Persist enough state to resume |
|
|
172
|
+
| Unbounded memory caches | Set a size cap with LRU eviction |
|
|
173
|
+
| Network-only fallback for offline | Degrade: cached data + "offline" banner |
|
|
174
|
+
| Duplicate local schemas (Room + SwiftData with different shapes on same domain) | One domain model; platform stores map to it |
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: python
|
|
3
|
+
description: Python language skill — idioms, type hints, error handling, testing, async, packaging. Language-focused. Combine with end skills (`backend`, `frontend`, `mobile`) for architecture, and with persona skills (`backend-architect`, `code-reviewer`) for mindset.
|
|
4
|
+
origin: ecc-fork (https://github.com/affaan-m/everything-claude-code, MIT)
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Python
|
|
8
|
+
|
|
9
|
+
Pythonic idioms, typing, error handling, async, testing, packaging. **Language-focused only**. Architecture decisions belong to end skills (`backend`, `frontend`, `mobile`); general principles (TDD cycle, "specific exceptions only", "tests before code") live in `coding-standards`.
|
|
10
|
+
|
|
11
|
+
## When to load
|
|
12
|
+
|
|
13
|
+
- Task is a Python project (primary language)
|
|
14
|
+
- Reviewing Python code
|
|
15
|
+
- Setting up Python project structure, packaging, or tests
|
|
16
|
+
- Writing Python-specific logic (generators, decorators, context managers, type hints, async)
|
|
17
|
+
|
|
18
|
+
## Core principles (The Zen of Python, abridged)
|
|
19
|
+
|
|
20
|
+
1. **Readability counts** — clear > clever
|
|
21
|
+
2. **Explicit over implicit** — no hidden side effects
|
|
22
|
+
3. **EAFP** (Easier to Ask Forgiveness Than Permission) — prefer `try/except` over pre-checks
|
|
23
|
+
4. **Type hints on public APIs** — modern 3.9+ syntax (`list[str]` not `List[str]`); 3.12+ PEP 695 where available
|
|
24
|
+
5. **Immutable defaults** — never `def f(x=[])`; use `None` + `x or []` or `frozenset` / `tuple`
|
|
25
|
+
6. **Pathlib over os.path** — modern filesystem access
|
|
26
|
+
7. **f-strings** over `.format()` / `%` formatting
|
|
27
|
+
8. **`pyproject.toml` only** — no `setup.py`, no `requirements.txt` for libraries
|
|
28
|
+
|
|
29
|
+
## How to use references
|
|
30
|
+
|
|
31
|
+
Load detailed references on demand based on the task:
|
|
32
|
+
|
|
33
|
+
| Reference | When to load |
|
|
34
|
+
|---|---|
|
|
35
|
+
| [`references/idioms.md`](references/idioms.md) | Core language idioms: EAFP, comprehensions, generators, decorators, context managers, match/case, walrus |
|
|
36
|
+
| [`references/typing.md`](references/typing.md) | Type hints, generics (PEP 695), protocols, type aliases, `Self`, `@override`, `ParamSpec` |
|
|
37
|
+
| [`references/error-handling.md`](references/error-handling.md) | Exception hierarchy, chaining, custom exceptions, exception groups / `except*` |
|
|
38
|
+
| [`references/async.md`](references/async.md) | `asyncio`, `TaskGroup`, timeouts, cancellation, offloading blocking code |
|
|
39
|
+
| [`references/testing.md`](references/testing.md) | pytest, fixtures, parametrization, mocking, coverage, `hypothesis` |
|
|
40
|
+
| [`references/packaging.md`](references/packaging.md) | `pyproject.toml`, `uv`, `venv`, project layout, publishing |
|
|
41
|
+
|
|
42
|
+
## Forbidden patterns (auto-reject)
|
|
43
|
+
|
|
44
|
+
- Mutable default arguments (`def f(x=[])`) — use `None` sentinel
|
|
45
|
+
- `except:` without exception type — always name it
|
|
46
|
+
- `import *` — explicit imports only
|
|
47
|
+
- `time.sleep()` / blocking calls inside `async def` — use `await asyncio.sleep()` or `asyncio.to_thread`
|
|
48
|
+
- Swallowing `asyncio.CancelledError` without re-raising
|
|
49
|
+
- `setup.py` in new projects — use `pyproject.toml`
|
|
50
|
+
- Committing `.venv/` or mixing envs with system Python
|
|
51
|
+
- Dynamic typing in public APIs without type hints
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Third-Party Attribution
|
|
2
|
+
|
|
3
|
+
This skill integrates content from:
|
|
4
|
+
|
|
5
|
+
## everything-claude-code (Affaan Mustafa)
|
|
6
|
+
|
|
7
|
+
- URL: https://github.com/affaan-m/everything-claude-code
|
|
8
|
+
- License: MIT
|
|
9
|
+
- Files used:
|
|
10
|
+
- `skills/python-patterns/SKILL.md` → split into `references/idioms.md`, `references/typing.md`, `references/error-handling.md`
|
|
11
|
+
- `skills/python-testing/SKILL.md` → `references/testing.md`
|
|
12
|
+
- Adaptation: content restructured into multiple reference files (thin SKILL.md entry + topic-specific references), some sections condensed, Pythonic/language-neutral line drawn (language-specific content stays here, architecture moves to `backend` / `frontend` skills).
|
|
13
|
+
|
|
14
|
+
The MIT license notice is preserved in [LICENSE-MIT-everything-claude-code](https://github.com/affaan-m/everything-claude-code/blob/main/LICENSE).
|