erne-universal 0.1.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.
Files changed (122) hide show
  1. package/.claude-plugin/plugin.json +92 -0
  2. package/LICENSE +21 -0
  3. package/README.md +73 -0
  4. package/agents/architect.md +64 -0
  5. package/agents/code-reviewer.md +72 -0
  6. package/agents/expo-config-resolver.md +77 -0
  7. package/agents/native-bridge-builder.md +98 -0
  8. package/agents/performance-profiler.md +89 -0
  9. package/agents/tdd-guide.md +86 -0
  10. package/agents/ui-designer.md +100 -0
  11. package/agents/upgrade-assistant.md +106 -0
  12. package/bin/cli.js +55 -0
  13. package/commands/animate.md +70 -0
  14. package/commands/build-fix.md +57 -0
  15. package/commands/code-review.md +51 -0
  16. package/commands/component.md +93 -0
  17. package/commands/debug.md +74 -0
  18. package/commands/deploy.md +82 -0
  19. package/commands/learn.md +56 -0
  20. package/commands/native-module.md +51 -0
  21. package/commands/navigate.md +69 -0
  22. package/commands/perf.md +68 -0
  23. package/commands/plan.md +49 -0
  24. package/commands/quality-gate.md +80 -0
  25. package/commands/retrospective.md +70 -0
  26. package/commands/setup-device.md +99 -0
  27. package/commands/tdd.md +51 -0
  28. package/commands/upgrade.md +78 -0
  29. package/contexts/dev.md +29 -0
  30. package/contexts/review.md +32 -0
  31. package/contexts/vibe.md +44 -0
  32. package/docs/agents.md +41 -0
  33. package/docs/commands.md +53 -0
  34. package/docs/creating-skills.md +63 -0
  35. package/docs/getting-started.md +60 -0
  36. package/docs/hooks-profiles.md +73 -0
  37. package/docs/superpowers/plans/2026-03-10-erne-plan-1-infrastructure-hooks.md +3973 -0
  38. package/docs/superpowers/plans/2026-03-10-erne-plan-2-content-layer.md +4496 -0
  39. package/docs/superpowers/plans/2026-03-10-erne-plan-3-skills-knowledge-base.md +1952 -0
  40. package/docs/superpowers/plans/2026-03-10-erne-plan-4-install-cli-distribution.md +1624 -0
  41. package/docs/superpowers/specs/2026-03-10-everything-react-native-expo-design.md +581 -0
  42. package/examples/claude-md-bare-rn.md +46 -0
  43. package/examples/claude-md-expo-managed.md +45 -0
  44. package/examples/eas-json-standard.json +41 -0
  45. package/hooks/hooks.json +113 -0
  46. package/hooks/profiles/minimal.json +9 -0
  47. package/hooks/profiles/standard.json +17 -0
  48. package/hooks/profiles/strict.json +22 -0
  49. package/install.sh +50 -0
  50. package/mcp-configs/agent-device.json +10 -0
  51. package/mcp-configs/appstore-connect.json +15 -0
  52. package/mcp-configs/expo-api.json +13 -0
  53. package/mcp-configs/figma.json +13 -0
  54. package/mcp-configs/firebase.json +14 -0
  55. package/mcp-configs/github.json +13 -0
  56. package/mcp-configs/memory.json +13 -0
  57. package/mcp-configs/play-console.json +14 -0
  58. package/mcp-configs/sentry.json +15 -0
  59. package/mcp-configs/supabase.json +14 -0
  60. package/package.json +50 -0
  61. package/rules/bare-rn/coding-style.md +62 -0
  62. package/rules/bare-rn/patterns.md +54 -0
  63. package/rules/bare-rn/security.md +58 -0
  64. package/rules/bare-rn/testing.md +78 -0
  65. package/rules/common/coding-style.md +50 -0
  66. package/rules/common/development-workflow.md +55 -0
  67. package/rules/common/git-workflow.md +40 -0
  68. package/rules/common/navigation.md +56 -0
  69. package/rules/common/patterns.md +59 -0
  70. package/rules/common/performance.md +55 -0
  71. package/rules/common/security.md +64 -0
  72. package/rules/common/state-management.md +86 -0
  73. package/rules/common/testing.md +61 -0
  74. package/rules/expo/coding-style.md +54 -0
  75. package/rules/expo/patterns.md +71 -0
  76. package/rules/expo/security.md +41 -0
  77. package/rules/expo/testing.md +68 -0
  78. package/rules/native-android/coding-style.md +81 -0
  79. package/rules/native-android/patterns.md +77 -0
  80. package/rules/native-android/security.md +80 -0
  81. package/rules/native-android/testing.md +94 -0
  82. package/rules/native-ios/coding-style.md +72 -0
  83. package/rules/native-ios/patterns.md +72 -0
  84. package/rules/native-ios/security.md +59 -0
  85. package/rules/native-ios/testing.md +79 -0
  86. package/schemas/hooks.schema.json +34 -0
  87. package/schemas/plugin.schema.json +55 -0
  88. package/scripts/hooks/accessibility-check.js +117 -0
  89. package/scripts/hooks/bundle-size-check.js +31 -0
  90. package/scripts/hooks/check-console-log.js +37 -0
  91. package/scripts/hooks/check-expo-config.js +40 -0
  92. package/scripts/hooks/check-platform-specific.js +40 -0
  93. package/scripts/hooks/check-reanimated-worklet.js +51 -0
  94. package/scripts/hooks/continuous-learning-observer.js +24 -0
  95. package/scripts/hooks/evaluate-session.js +26 -0
  96. package/scripts/hooks/lib/hook-utils.js +52 -0
  97. package/scripts/hooks/native-compat-check.js +42 -0
  98. package/scripts/hooks/performance-budget.js +57 -0
  99. package/scripts/hooks/post-edit-format.js +38 -0
  100. package/scripts/hooks/post-edit-typecheck.js +31 -0
  101. package/scripts/hooks/pre-commit-lint.js +44 -0
  102. package/scripts/hooks/pre-edit-test-gate.js +68 -0
  103. package/scripts/hooks/run-with-flags.js +93 -0
  104. package/scripts/hooks/security-scan.js +65 -0
  105. package/scripts/hooks/session-start.js +77 -0
  106. package/scripts/lint-content.js +62 -0
  107. package/scripts/validate-all.js +137 -0
  108. package/skills/coding-standards/SKILL.md +88 -0
  109. package/skills/continuous-learning-v2/SKILL.md +61 -0
  110. package/skills/continuous-learning-v2/agent-prompts/pattern-analyzer.md +51 -0
  111. package/skills/continuous-learning-v2/agent-prompts/skill-generator.md +74 -0
  112. package/skills/continuous-learning-v2/config.json +25 -0
  113. package/skills/continuous-learning-v2/hook-templates/evaluate-session.cjs.template +69 -0
  114. package/skills/continuous-learning-v2/hook-templates/observer-hook.cjs.template +54 -0
  115. package/skills/continuous-learning-v2/scripts/analyze-patterns.js +50 -0
  116. package/skills/continuous-learning-v2/scripts/extract-session-patterns.js +54 -0
  117. package/skills/continuous-learning-v2/scripts/validate-content.js +88 -0
  118. package/skills/native-module-scaffold/SKILL.md +118 -0
  119. package/skills/performance-optimization/SKILL.md +103 -0
  120. package/skills/security-review/SKILL.md +99 -0
  121. package/skills/tdd-workflow/SKILL.md +142 -0
  122. package/skills/upgrade-workflow/SKILL.md +140 -0
@@ -0,0 +1,78 @@
1
+ ---
2
+ description: Testing patterns for bare React Native projects
3
+ globs: "**/*.test.{ts,tsx}"
4
+ alwaysApply: false
5
+ ---
6
+
7
+ # Bare React Native Testing
8
+
9
+ ## Native Unit Tests
10
+ Run native tests alongside JS tests for full coverage:
11
+
12
+ ### iOS (XCTest)
13
+ ```swift
14
+ // ios/MyAppTests/MyModuleTests.swift
15
+ import XCTest
16
+ @testable import MyApp
17
+
18
+ class MyModuleTests: XCTestCase {
19
+ func testDataProcessing() {
20
+ let module = MyModule()
21
+ let result = module.processData("input")
22
+ XCTAssertEqual(result, "expected_output")
23
+ }
24
+ }
25
+ ```
26
+
27
+ ### Android (JUnit)
28
+ ```kotlin
29
+ // android/app/src/test/java/com/myapp/MyModuleTest.kt
30
+ import org.junit.Test
31
+ import org.junit.Assert.*
32
+
33
+ class MyModuleTest {
34
+ @Test
35
+ fun testDataProcessing() {
36
+ val module = MyModule()
37
+ val result = module.processData("input")
38
+ assertEquals("expected_output", result)
39
+ }
40
+ }
41
+ ```
42
+
43
+ ## E2E with Detox (Bare Setup)
44
+ - Configure Detox directly in project (no EAS Build needed)
45
+ - Build test binaries locally: `detox build --configuration ios.sim.debug`
46
+ - Run: `detox test --configuration ios.sim.debug`
47
+
48
+ ```js
49
+ // .detoxrc.js
50
+ module.exports = {
51
+ testRunner: { args: { config: 'e2e/jest.config.js' } },
52
+ apps: {
53
+ 'ios.debug': {
54
+ type: 'ios.app',
55
+ binaryPath: 'ios/build/Build/Products/Debug-iphonesimulator/MyApp.app',
56
+ build: 'xcodebuild -workspace ios/MyApp.xcworkspace -scheme MyApp -configuration Debug -sdk iphonesimulator -derivedDataPath ios/build',
57
+ },
58
+ 'android.debug': {
59
+ type: 'android.apk',
60
+ binaryPath: 'android/app/build/outputs/apk/debug/app-debug.apk',
61
+ build: 'cd android && ./gradlew assembleDebug assembleAndroidTest -DtestBuildType=debug',
62
+ },
63
+ },
64
+ devices: {
65
+ simulator: { type: 'ios.simulator', device: { type: 'iPhone 16' } },
66
+ emulator: { type: 'android.emulator', device: { avdName: 'Pixel_7' } },
67
+ },
68
+ configurations: {
69
+ 'ios.sim.debug': { device: 'simulator', app: 'ios.debug' },
70
+ 'android.emu.debug': { device: 'emulator', app: 'android.debug' },
71
+ },
72
+ };
73
+ ```
74
+
75
+ ## Integration Testing
76
+ - Test native module bridges with integration tests
77
+ - Verify Turbo Module codegen output matches specs
78
+ - Test platform-specific behavior on both iOS and Android
@@ -0,0 +1,50 @@
1
+ ---
2
+ description: TypeScript and React Native coding style conventions — enforced for all project types
3
+ globs: "**/*.{ts,tsx,js,jsx}"
4
+ alwaysApply: false
5
+ ---
6
+
7
+ # Coding Style
8
+
9
+ ## TypeScript
10
+ - Enable `strict` mode in tsconfig.json
11
+ - No `any` types — use `unknown` + type guards or proper generics
12
+ - Use type inference where possible; annotate function signatures explicitly
13
+ - Prefer `interface` for object shapes, `type` for unions/intersections
14
+ - Use `as const` for literal types instead of enums
15
+
16
+ ## Components
17
+ - Functional components only — no class components
18
+ - Named exports only — no default exports
19
+ - One component per file (colocated helpers are fine)
20
+ - Props interface named `[Component]Props` (e.g., `ButtonProps`)
21
+ - Destructure props in function signature
22
+
23
+ ```tsx
24
+ // GOOD
25
+ export function UserCard({ name, avatar }: UserCardProps) { ... }
26
+
27
+ // BAD
28
+ export default class UserCard extends Component { ... }
29
+ ```
30
+
31
+ ## File Naming
32
+ - Components: `PascalCase.tsx` (e.g., `UserCard.tsx`)
33
+ - Hooks: `camelCase.ts` prefixed with `use` (e.g., `useAuth.ts`)
34
+ - Utils/helpers: `camelCase.ts` (e.g., `formatDate.ts`)
35
+ - Types: `camelCase.ts` or colocated in component file
36
+ - Tests: `[name].test.ts(x)` adjacent to source
37
+ - Platform-specific: `[name].ios.tsx` / `[name].android.tsx`
38
+
39
+ ## Imports
40
+ - Use path aliases (`@/` maps to `src/`)
41
+ - No barrel files (`index.ts` re-exports) — import directly
42
+ - Group imports: react → react-native → expo → third-party → local
43
+ - Use `import type` for type-only imports
44
+
45
+ ## General
46
+ - Max line length: 100 characters (Prettier enforced)
47
+ - Trailing commas in multiline structures
48
+ - Single quotes for strings
49
+ - Semicolons required
50
+ - No `var` — use `const` by default, `let` when reassignment needed
@@ -0,0 +1,55 @@
1
+ ---
2
+ description: Development environment and workflow conventions
3
+ globs: ""
4
+ alwaysApply: true
5
+ ---
6
+
7
+ # Development Workflow
8
+
9
+ ## Development Client
10
+ - Use `expo-dev-client` instead of Expo Go for projects with native modules
11
+ - Expo Go is fine for pure JS/TS projects without custom native code
12
+ - Create development builds: `eas build --profile development`
13
+
14
+ ## Build Profiles
15
+
16
+ | Profile | Use Case | Command |
17
+ |---------|----------|---------|
18
+ | development | Local testing with dev tools | `eas build --profile development` |
19
+ | preview | QA testing, stakeholder review | `eas build --profile preview` |
20
+ | production | App Store / Play Store release | `eas build --profile production` |
21
+
22
+ ## Environment Management
23
+ - `.env.development`, `.env.preview`, `.env.production`
24
+ - Use `expo-constants` to access env vars at runtime
25
+ - Never commit `.env` files (add to `.gitignore`)
26
+ - Use EAS Secrets for CI/CD environment variables
27
+
28
+ ## Local Development
29
+ ```bash
30
+ # Start Metro bundler
31
+ npx expo start
32
+
33
+ # Run on specific platform
34
+ npx expo run:ios
35
+ npx expo run:android
36
+
37
+ # Clear cache when things break
38
+ npx expo start --clear
39
+
40
+ # Regenerate native projects
41
+ npx expo prebuild --clean
42
+ ```
43
+
44
+ ## Debugging
45
+ - Use React Native DevTools (built-in with Expo SDK 50+)
46
+ - Console.log for quick debugging (remove before commit)
47
+ - React DevTools for component inspection
48
+ - Flipper/React Native Debugger for network and performance
49
+ - `LogBox.ignoreLogs()` only for known harmless warnings
50
+
51
+ ## CI/CD
52
+ - EAS Build for cloud builds
53
+ - EAS Submit for store submissions
54
+ - EAS Update for OTA updates (non-native changes)
55
+ - GitHub Actions for lint/test/typecheck on PRs
@@ -0,0 +1,40 @@
1
+ ---
2
+ description: Git workflow and commit conventions
3
+ globs: ""
4
+ alwaysApply: true
5
+ ---
6
+
7
+ # Git Workflow
8
+
9
+ ## Commit Messages
10
+ Follow Conventional Commits:
11
+
12
+ ```
13
+ <type>(<scope>): <description>
14
+
15
+ [optional body]
16
+
17
+ [optional footer(s)]
18
+ ```
19
+
20
+ Types: `feat`, `fix`, `docs`, `style`, `refactor`, `perf`, `test`, `chore`, `ci`
21
+
22
+ Examples:
23
+ - `feat(auth): add biometric login support`
24
+ - `fix(navigation): prevent double-tap on tab bar`
25
+ - `perf(list): switch FlatList to FlashList for feed`
26
+
27
+ ## Branch Naming
28
+ - Feature: `feat/short-description`
29
+ - Fix: `fix/issue-number-description`
30
+ - Chore: `chore/description`
31
+
32
+ ## PR Guidelines
33
+ - Keep PRs under 400 lines when possible
34
+ - One logical change per PR
35
+ - Include screenshots/recordings for UI changes
36
+ - Update tests for changed behavior
37
+ - Run full test suite before requesting review
38
+
39
+ ## Hooks Integration
40
+ The `pre-commit-lint.js` hook runs ESLint + Prettier on staged files before commit.
@@ -0,0 +1,56 @@
1
+ ---
2
+ description: Expo Router navigation conventions and patterns
3
+ globs: "app/**/*.{ts,tsx}"
4
+ alwaysApply: false
5
+ ---
6
+
7
+ # Navigation
8
+
9
+ ## Expo Router File Conventions
10
+ - File-based routing in `app/` directory
11
+ - `_layout.tsx` for layout definitions (Stack, Tabs, Drawer)
12
+ - `[param].tsx` for dynamic routes
13
+ - `[...catchAll].tsx` for catch-all routes
14
+ - `+not-found.tsx` for 404 handling
15
+ - `(group)` parentheses for layout groups (no URL impact)
16
+
17
+ ```
18
+ app/
19
+ _layout.tsx # Root layout (Stack)
20
+ index.tsx # / (home)
21
+ (tabs)/
22
+ _layout.tsx # Tab layout
23
+ home.tsx # /home tab
24
+ profile.tsx # /profile tab
25
+ (auth)/
26
+ _layout.tsx # Auth stack (no tabs)
27
+ login.tsx # /login
28
+ register.tsx # /register
29
+ settings/
30
+ _layout.tsx # Settings stack
31
+ index.tsx # /settings
32
+ [section].tsx # /settings/notifications
33
+ ```
34
+
35
+ ## Typed Routes
36
+ - Use `href` with type-safe route paths
37
+ - Define route params with `useLocalSearchParams<{ id: string }>()`
38
+ - Use `router.push()` / `router.replace()` / `router.back()`
39
+ - Prefer `<Link>` component for declarative navigation
40
+
41
+ ## Deep Linking
42
+ - Define scheme in `app.json` (`expo.scheme`)
43
+ - Map deep links to file routes
44
+ - Validate incoming URLs before navigating
45
+ - Test deep links: `npx uri-scheme open [url] --ios/--android`
46
+
47
+ ## Modal Patterns
48
+ - Use `presentation: 'modal'` in layout options
49
+ - Full-screen modals: separate route in layout group
50
+ - Bottom sheets: `@gorhom/bottom-sheet` (not navigation)
51
+
52
+ ## Best Practices
53
+ - Keep navigation state minimal (pass IDs, not full objects)
54
+ - Prefetch data for likely next screens
55
+ - Use `initialRouteName` for proper back navigation
56
+ - Handle "not found" routes gracefully
@@ -0,0 +1,59 @@
1
+ ---
2
+ description: React Native architectural patterns and best practices
3
+ globs: "**/*.{ts,tsx}"
4
+ alwaysApply: false
5
+ ---
6
+
7
+ # Patterns
8
+
9
+ ## State Management
10
+ - **Client state**: Zustand (simple) or Jotai (atomic) — NOT Redux for new projects
11
+ - **Server state**: TanStack Query (React Query) — handles caching, refetching, optimistic updates
12
+ - **Form state**: React Hook Form or controlled components (small forms)
13
+ - Avoid prop drilling beyond 2 levels — use Zustand store or composition
14
+
15
+ ```tsx
16
+ // GOOD: Zustand store
17
+ const useAuthStore = create<AuthState>((set) => ({
18
+ user: null,
19
+ setUser: (user) => set({ user }),
20
+ logout: () => set({ user: null }),
21
+ }));
22
+
23
+ // BAD: Deep prop drilling
24
+ <App user={user}>
25
+ <Layout user={user}>
26
+ <Header user={user}>
27
+ <Avatar user={user} />
28
+ ```
29
+
30
+ ## Component Patterns
31
+ - **Compound components** for complex UI (Header + Body + Footer)
32
+ - **Custom hooks** for shared logic (extract `useAuth`, `useTheme`)
33
+ - **Colocation**: keep feature files together
34
+
35
+ ```
36
+ features/
37
+ auth/
38
+ LoginScreen.tsx
39
+ useAuth.ts
40
+ auth.store.ts
41
+ auth.test.tsx
42
+ ```
43
+
44
+ - **Render props / children** for flexible containers
45
+ - **forwardRef** for imperative handles (scroll, focus)
46
+
47
+ ## Data Fetching
48
+ - TanStack Query for all API calls
49
+ - Define query keys as constants (`['users', userId]`)
50
+ - Use `queryClient.prefetchQuery` for anticipated navigation
51
+ - Optimistic updates for user-initiated mutations
52
+ - Error boundaries per screen (not global)
53
+
54
+ ## Error Handling
55
+ - Error boundaries at screen level (catch rendering crashes)
56
+ - Try/catch at API call level (handle network errors)
57
+ - Graceful degradation (offline placeholder, retry button)
58
+ - Report errors to monitoring (Sentry/Crashlytics)
59
+ - Never swallow errors silently
@@ -0,0 +1,55 @@
1
+ ---
2
+ description: React Native performance optimization rules
3
+ globs: "**/*.{ts,tsx}"
4
+ alwaysApply: false
5
+ ---
6
+
7
+ # Performance
8
+
9
+ ## Rendering
10
+ - Use `React.memo` on components rendered in lists or receiving stable props
11
+ - Wrap callbacks with `useCallback` when passed to memoized children
12
+ - Use `useMemo` for expensive computations (sorting, filtering large arrays)
13
+ - Never define functions or objects inline in JSX within loops/lists
14
+
15
+ ```tsx
16
+ // GOOD
17
+ const renderItem = useCallback(({ item }: { item: User }) => (
18
+ <UserRow user={item} onPress={handlePress} />
19
+ ), [handlePress]);
20
+
21
+ // BAD — creates new object every render
22
+ <FlatList renderItem={({ item }) => <UserRow user={item} />} />
23
+ ```
24
+
25
+ ## Lists
26
+ - `FlatList` or `FlashList` for lists > 20 items (never ScrollView)
27
+ - Set `keyExtractor` with stable, unique keys
28
+ - Use `getItemLayout` when item heights are fixed
29
+ - Configure `windowSize`, `maxToRenderPerBatch`, `initialNumToRender`
30
+ - `removeClippedSubviews={true}` for long lists on Android
31
+
32
+ ## Images
33
+ - Use `expo-image` (not `<Image>` or react-native-fast-image)
34
+ - Set explicit `width` and `height` (avoid layout shifts)
35
+ - Use `contentFit="cover"` and `placeholder` for loading states
36
+ - Optimize source images (WebP, appropriate resolution)
37
+ - Use `cachePolicy="memory-disk"` for frequently accessed images
38
+
39
+ ## Bundle Size
40
+ - Import specific modules, not entire packages (`lodash/get` not `lodash`)
41
+ - Use `React.lazy` + `Suspense` for code splitting heavy screens
42
+ - Analyze bundle with `npx react-native-bundle-visualizer`
43
+ - Target < 5MB JS bundle for production
44
+
45
+ ## Animations
46
+ - Use `react-native-reanimated` for all animations (not Animated API)
47
+ - Run animations on UI thread via worklets
48
+ - Never read shared values from JS thread in hot paths
49
+ - Use `useAnimatedStyle` instead of inline animated styles
50
+
51
+ ## Startup
52
+ - Use Hermes engine (enabled by default in Expo SDK 50+)
53
+ - Inline requires for heavy modules (`require('heavy-lib')` inside function)
54
+ - Minimize `useEffect` chains on app startup
55
+ - Defer non-critical initialization with `InteractionManager.runAfterInteractions`
@@ -0,0 +1,64 @@
1
+ ---
2
+ description: Mobile security rules for React Native applications
3
+ globs: "**/*.{ts,tsx,js,jsx}"
4
+ alwaysApply: false
5
+ ---
6
+
7
+ # Security
8
+
9
+ ## Secrets Management
10
+ - NEVER hardcode API keys, tokens, or secrets in JS code
11
+ - Use `expo-secure-store` for sensitive data (NOT AsyncStorage)
12
+ - Environment variables via `.env` files (excluded from git)
13
+ - Build-time secrets via EAS Secrets (for CI/CD)
14
+ - Runtime secrets via secure backend API
15
+
16
+ ```tsx
17
+ // GOOD
18
+ import * as SecureStore from 'expo-secure-store';
19
+ const token = await SecureStore.getItemAsync('auth_token');
20
+
21
+ // BAD
22
+ const API_KEY = 'sk-1234567890abcdef';
23
+ await AsyncStorage.setItem('auth_token', token);
24
+ ```
25
+
26
+ ## Deep Linking
27
+ - Validate ALL incoming deep link URLs before navigation
28
+ - Whitelist allowed hosts and paths
29
+ - Never pass deep link params directly to sensitive operations
30
+ - Sanitize query parameters
31
+
32
+ ```tsx
33
+ // GOOD
34
+ function handleDeepLink(url: string) {
35
+ const parsed = Linking.parse(url);
36
+ if (ALLOWED_HOSTS.includes(parsed.hostname)) {
37
+ router.push(parsed.path);
38
+ }
39
+ }
40
+ ```
41
+
42
+ ## Network Security
43
+ - HTTPS only — no HTTP requests
44
+ - Certificate pinning for critical API endpoints
45
+ - Timeout all network requests (15s default)
46
+ - Handle network errors gracefully (offline mode)
47
+
48
+ ## WebView
49
+ - Always set `originWhitelist` (never `['*']` in production)
50
+ - Disable JavaScript if not needed
51
+ - Never load untrusted URLs
52
+ - Use `onShouldStartLoadWithRequest` to filter navigation
53
+
54
+ ## Input Validation
55
+ - Sanitize all user input before display (XSS prevention)
56
+ - Validate form data on client AND server
57
+ - Use parameterized queries (never string concatenation for queries)
58
+ - Limit input lengths to prevent abuse
59
+
60
+ ## Data Storage
61
+ - Sensitive data: `expo-secure-store` (Keychain/Keystore)
62
+ - Non-sensitive preferences: `AsyncStorage` or `expo-file-system`
63
+ - Never store PII in logs or crash reports
64
+ - Clear sensitive data on logout
@@ -0,0 +1,86 @@
1
+ ---
2
+ description: State management guidelines — Zustand for client, TanStack Query for server
3
+ globs: "**/*.{ts,tsx}"
4
+ alwaysApply: false
5
+ ---
6
+
7
+ # State Management
8
+
9
+ ## Architecture
10
+
11
+ | State Type | Tool | When |
12
+ |-----------|------|------|
13
+ | **Client state** | Zustand | UI state, user preferences, app mode |
14
+ | **Server state** | TanStack Query | API data, caching, pagination, optimistic updates |
15
+ | **Form state** | React Hook Form | Complex forms with validation |
16
+ | **Ephemeral state** | useState | Component-local, non-shared |
17
+ | **Derived state** | useMemo | Computed from other state |
18
+
19
+ ## Zustand Patterns
20
+
21
+ ```tsx
22
+ // Store definition — one store per domain
23
+ interface AuthStore {
24
+ user: User | null;
25
+ token: string | null;
26
+ setUser: (user: User) => void;
27
+ logout: () => void;
28
+ }
29
+
30
+ const useAuthStore = create<AuthStore>((set) => ({
31
+ user: null,
32
+ token: null,
33
+ setUser: (user) => set({ user }),
34
+ logout: () => set({ user: null, token: null }),
35
+ }));
36
+
37
+ // Usage — select only what you need
38
+ const userName = useAuthStore((s) => s.user?.name);
39
+ ```
40
+
41
+ ## TanStack Query Patterns
42
+
43
+ ```tsx
44
+ // Query keys as constants
45
+ export const userKeys = {
46
+ all: ['users'] as const,
47
+ detail: (id: string) => ['users', id] as const,
48
+ lists: () => ['users', 'list'] as const,
49
+ };
50
+
51
+ // Query hook
52
+ function useUser(id: string) {
53
+ return useQuery({
54
+ queryKey: userKeys.detail(id),
55
+ queryFn: () => api.getUser(id),
56
+ staleTime: 5 * 60 * 1000,
57
+ });
58
+ }
59
+
60
+ // Mutation with optimistic update
61
+ function useUpdateUser() {
62
+ const queryClient = useQueryClient();
63
+ return useMutation({
64
+ mutationFn: api.updateUser,
65
+ onMutate: async (updated) => {
66
+ await queryClient.cancelQueries({ queryKey: userKeys.detail(updated.id) });
67
+ const previous = queryClient.getQueryData(userKeys.detail(updated.id));
68
+ queryClient.setQueryData(userKeys.detail(updated.id), updated);
69
+ return { previous };
70
+ },
71
+ onError: (err, vars, context) => {
72
+ queryClient.setQueryData(userKeys.detail(vars.id), context?.previous);
73
+ },
74
+ onSettled: (data, err, vars) => {
75
+ queryClient.invalidateQueries({ queryKey: userKeys.detail(vars.id) });
76
+ },
77
+ });
78
+ }
79
+ ```
80
+
81
+ ## Rules
82
+ - Context API only for truly global, rarely-changing values (theme, locale)
83
+ - No prop drilling beyond 2 component levels
84
+ - Keep stores small and domain-focused
85
+ - Never store derived data — compute with `useMemo` or selectors
86
+ - Persist critical state with `zustand/middleware` persist
@@ -0,0 +1,61 @@
1
+ ---
2
+ description: Testing standards for React Native projects
3
+ globs: "**/*.test.{ts,tsx}"
4
+ alwaysApply: false
5
+ ---
6
+
7
+ # Testing
8
+
9
+ ## Stack
10
+ - **Unit/Component**: Jest + React Native Testing Library (RNTL)
11
+ - **E2E**: Detox (with EAS Build for Expo projects)
12
+ - **Coverage**: Jest built-in, target 80% lines, 70% branches
13
+
14
+ ## Principles
15
+ - Test behavior, not implementation
16
+ - Query by role, text, or label — avoid testID unless necessary
17
+ - One logical assertion per test
18
+ - Mock at boundaries (API, native modules), not internals
19
+ - No snapshot tests as primary strategy (smoke checks only)
20
+
21
+ ## Component Tests
22
+ ```tsx
23
+ // GOOD: Tests behavior
24
+ test('disables submit when form is invalid', () => {
25
+ render(<LoginForm />);
26
+ const button = screen.getByRole('button', { name: 'Submit' });
27
+ expect(button).toBeDisabled();
28
+ });
29
+
30
+ // BAD: Tests implementation
31
+ test('sets isValid state to false', () => {
32
+ const { result } = renderHook(() => useForm());
33
+ expect(result.current.isValid).toBe(false);
34
+ });
35
+ ```
36
+
37
+ ## Mocking
38
+ ```tsx
39
+ // Mock native module
40
+ jest.mock('expo-secure-store', () => ({
41
+ getItemAsync: jest.fn().mockResolvedValue('token'),
42
+ setItemAsync: jest.fn(),
43
+ }));
44
+
45
+ // Mock navigation
46
+ jest.mock('expo-router', () => ({
47
+ useRouter: () => ({ push: jest.fn(), back: jest.fn() }),
48
+ useLocalSearchParams: () => ({}),
49
+ }));
50
+
51
+ // Mock API — use MSW or manual mock
52
+ const server = setupServer(
53
+ rest.get('/api/users', (req, res, ctx) => res(ctx.json([]))),
54
+ );
55
+ ```
56
+
57
+ ## File Organization
58
+ - Tests adjacent to source: `UserCard.test.tsx` next to `UserCard.tsx`
59
+ - Or in `__tests__/` directory at feature level
60
+ - Shared test utilities in `tests/helpers/`
61
+ - E2E tests in `e2e/` directory at project root
@@ -0,0 +1,54 @@
1
+ ---
2
+ description: Expo managed workflow coding conventions
3
+ globs: "**/*.{ts,tsx,js,jsx}"
4
+ alwaysApply: false
5
+ ---
6
+
7
+ # Expo Coding Style
8
+
9
+ ## SDK Module Preference
10
+ - Always prefer Expo SDK modules over community alternatives
11
+ - `expo-image` over `react-native-fast-image`
12
+ - `expo-file-system` over `react-native-fs`
13
+ - `expo-camera` over `react-native-camera`
14
+ - `expo-notifications` over `react-native-push-notification`
15
+ - `expo-secure-store` over `react-native-keychain`
16
+
17
+ ```tsx
18
+ // GOOD — Expo SDK module
19
+ import * as FileSystem from 'expo-file-system';
20
+ const content = await FileSystem.readAsStringAsync(uri);
21
+
22
+ // BAD — community alternative in Expo project
23
+ import RNFS from 'react-native-fs';
24
+ const content = await RNFS.readFile(path);
25
+ ```
26
+
27
+ ## Config Plugins Over Manual Native Edits
28
+ - NEVER modify `ios/` or `android/` directories directly in managed workflow
29
+ - Use config plugins for native configuration
30
+ - Run `npx expo prebuild --clean` to regenerate native projects
31
+ - Add native config in `app.config.ts` with plugins array
32
+
33
+ ```ts
34
+ // app.config.ts
35
+ export default ({ config }) => ({
36
+ ...config,
37
+ plugins: [
38
+ ['expo-camera', { cameraPermission: 'Allow camera for scanning' }],
39
+ ['expo-location', { locationAlwaysAndWhenInUsePermission: 'Allow location' }],
40
+ './plugins/custom-splash.js',
41
+ ],
42
+ });
43
+ ```
44
+
45
+ ## Expo Router Conventions
46
+ - Use file-based routing exclusively (no manual route registration)
47
+ - Layout files (`_layout.tsx`) define navigation structure
48
+ - Use typed routes for navigation
49
+ - Group routes with parentheses for logical organization
50
+
51
+ ## Module Resolution
52
+ - Use `expo-modules-core` for creating native modules
53
+ - Prefer `expo-constants` for accessing build-time configuration
54
+ - Use `expo-updates` API for checking/fetching OTA updates