You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: .claude/agents/code-reviewer.md
+13-5Lines changed: 13 additions & 5 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -33,20 +33,28 @@ You are a senior code reviewer for this React Native TypeScript project. Your st
33
33
-[ ] Strict mode compliance — no implicit `any`, no untyped function returns on exported APIs
34
34
-[ ] Zod schemas validate every API response in feature services before returning domain models
35
35
36
+
### Code Quality
37
+
-[ ] No magic numbers in logic — numeric literals with meaning (timeouts, limits, sizes, counts, offsets) must be named constants defined at module or config level
38
+
-[ ] No magic strings in logic — non-i18n string literals used as identifiers, keys, or config values must be named constants (e.g. storage keys from `src/config/constants.ts`, route names from `src/navigation/routes.ts`)
39
+
-[ ] Functions do one thing — no function exceeds ~40 lines or mixes concerns (data fetching + transformation + UI logic); extract helpers when a function grows beyond a single clear responsibility
40
+
-[ ] No deeply nested callbacks or conditionals — flatten with early returns and extracted helpers
41
+
36
42
### UI & Styling
37
43
-[ ] All screens use `ScreenWrapper` as root element
38
-
-[ ] No raw hex colors, numeric spacing, or font sizes — `useTheme()` tokens only
39
-
-[ ]`StyleSheet.create()` used; inline styles only for dynamically computed values
44
+
-[ ] No raw hex colors, numeric spacing, or font sizes — `useTheme()` tokens only; brand colors via `theme.brand.*`
45
+
-[ ]`StyleSheet.create()` used; inline styles only for values that are dynamically computed at render time — not for static overrides
46
+
-[ ] Repeated style patterns extracted into shared `StyleSheet` entries or shared style constants — no copy-pasted style blocks across components
40
47
-[ ] Shared UI components accept strings as props — no hardcoded user-facing copy
41
48
42
49
### i18n
43
-
-[ ] All user-facing strings use `useT('<feature>')`with the correct per-feature namespace
44
-
-[ ]Namespace matches the feature directory name (lowercase)
50
+
-[ ] All user-facing strings use `useT()`(no argument) and access keys via `t('feature.key')`
51
+
-[ ]Key prefix matches the feature directory name (lowercase)
45
52
46
53
### State & Data
47
54
-[ ] Server state via React Query; local UI state via `useState`; global UI state via Zustand in `src/shared/stores/`
48
55
-[ ] Query keys defined in feature `api/keys.ts` using `[feature, entity, id?, params?]` format
49
-
-[ ] Mutations include `meta.tags` for targeted invalidation
56
+
-[ ] Tag arrays (e.g. `AUTH_SESSION_TAGS`) exported from the feature's `api/keys.ts` — not defined inline in hooks or placed in `src/shared/constants/`
57
+
-[ ] Mutations include `meta.tags` for targeted invalidation; invalidation uses `invalidateByTags` with the feature's own `tagMap` only — no cross-feature tagMap references
50
58
-[ ] MMKV key strings imported from `src/config/constants.ts`, not hardcoded
-**Bootstrap:**`src/session/useBootstrapRoute.ts` determines the initial route.
12
-
-**Routes:** all constants in `src/navigation/routes.ts` — never inline route strings.
13
-
-**ParamLists:** per-feature at `src/features/<name>/navigation/param-list.ts`; root shell at `src/navigation/root-param-list.ts`.
14
-
-**`NavigationContainer`** lives inside `src/navigation/NavigationRoot.tsx` — do not add a second one.
10
+
-**Navigator** (`src/navigation/root/root-navigator.tsx`): JSX `<Stack.Navigator>` + `<Stack.Screen>` pattern. Export `RootNavigator` (the root stack component) and `HomeTabs` (tab navigator component). Create navigators at module level: `const Stack = createNativeStackNavigator<RootStackParamList>()`.
11
+
-**Root entry**`src/navigation/NavigationRoot.tsx`: single `<NavigationContainer>` with `ref={navigationRef}` — render exactly once, no second instance.
12
+
-**Initial route:**`useInitialRoute()` from `src/session/useInitialRoute.ts` — sync `useState` initializer that reads MMKV once, resolves `ROOT_ONBOARDING | ROOT_AUTH | ROOT_APP`.
13
+
-**Routes:** all constants in `src/navigation/routes.ts` — never inline route string literals anywhere.
14
+
-**ParamLists:**`RootStackParamList` and `HomeTabParamList` in `src/navigation/root-param-list.ts`; declared manually to avoid circular deps. Global augmentation declared once there:
- Create navigator instances (`const Stack = createNativeStackNavigator<T>()`) at module scope — not inside components.
38
+
- Add new screens as `<Stack.Screen name={ROUTES.X} component={ScreenComponent} />` inside the appropriate navigator JSX.
39
+
- Share `screenOptions` via the `screenOptions` prop on `<Stack.Navigator>` — do not repeat options on individual screens if they apply to all.
40
+
- For auth gating or feature flags: conditionally render `<Stack.Screen>` in JSX — do not call `navigation.navigate()` after auth state changes.
41
+
- Nested navigators (e.g. tabs inside a stack screen): create a dedicated component (e.g. `HomeTabs`) and register it as the screen component.
42
+
43
+
## Params
44
+
- Params must be **JSON-serializable** — required for state persistence and deep linking.
45
+
- Pass **IDs only**, never full data objects. Fetch data from React Query cache using the ID inside the screen.
46
+
- Do not use reserved param keys: `screen`, `params`, `initial`, `state`.
47
+
- To update params from within a screen: `navigation.setParams({...})` (merge) or `navigation.replaceParams({...})` (replace).
48
+
- To pass data back to a previous screen: `navigation.popTo('ScreenName', { result })`.
49
+
- To navigate to a nested screen with params: `navigation.navigate('Parent', { screen: 'Child', params: { id } })`.
50
+
51
+
## Navigation actions
52
+
-`navigate()` — standard transition; no-op if already on that screen (safe, no duplication).
53
+
-`push()` — forces a new instance of the same screen; use when multiple instances are needed.
54
+
-`goBack()` — standard back; hardware back and swipe gestures call this automatically.
55
+
-`popTo('ScreenName')` — jump back to a specific screen, skipping intermediates.
56
+
-`popToTop()` — reset a stack to its root screen.
57
+
58
+
## Screen lifecycle
59
+
- Use `useFocusEffect(useCallback(() => { ... return cleanup }, []))` for side effects that must run on focus (data refresh, analytics). Always return a cleanup function.
60
+
- Use `useIsFocused()` when a component must re-render on focus state change.
61
+
- Use `navigation.addListener('focus' | 'blur', cb)` inside `useEffect` — always return the unsubscribe result.
62
+
- Do not use plain `useEffect` for focus-aware operations without listener subscriptions.
63
+
64
+
## TypeScript
65
+
- ParamList entries must use `type`, never `interface`.
66
+
- Do not annotate `useNavigation<T>()` with a specific type — declare the global `RootParamList` instead.
67
+
- Do not annotate `useRoute<T>()` — use `route` from screen props (`NativeStackScreenProps<RootStackParamList, 'RouteName'>`).
68
+
- Use `CompositeScreenProps` for screens inside nested navigators that need access to parent navigation.
69
+
- Use `NavigatorScreenParams<ChildParamList>` when a parent ParamList entry wraps a nested navigator.
70
+
28
71
## Half-sheet modals
29
-
Use `presentation: 'transparentModal'`, `animation: 'none'`, `gestureEnabled: false` (see `HALF_SHEET_OPTIONS` in `root-navigator.tsx`).
72
+
- Register with `presentation: 'transparentModal'`, `animation: 'none'`, `gestureEnabled: false` (see `HALF_SHEET_OPTIONS` in `root-navigator.tsx`).
73
+
- Use `HalfSheet` from `src/shared/components/ui/HalfSheet.tsx` as the content wrapper.
30
74
31
75
## Must
32
-
- All route constants from `src/navigation/routes.ts` — never use inline string literals for routes.
33
-
- New screens: register in `routes.ts` and add the ParamList entry to the feature's `navigation/param-list.ts`.
34
-
- Use `navigationRef` from `src/navigation/helpers/navigation-helpers.ts` for imperative navigation outside React tree.
76
+
- All route constants from `src/navigation/routes.ts` — never inline strings.
77
+
- New screens: add constant to `routes.ts`, add `ParamList` entry to `root-param-list.ts`, register in `root-navigator.tsx`.
78
+
-`navigationRef` for imperative navigation outside the React tree.
79
+
-`useFocusEffect` + `useCallback` for focus-scoped side effects.
80
+
-`InteractionManager.runAfterInteractions` for heavy non-UI work triggered by navigation.
35
81
36
82
## Must not
37
-
- Do not nest a second `NavigationContainer`.
38
-
- Do not navigate from `src/shared/**` directly — navigate only via helpers or callbacks passed in as props.
83
+
- Do not render a second `<NavigationContainer>` — one root only.
84
+
- Do not call `navigation.navigate()` after an auth state change — conditional screen rendering handles it.
85
+
- Do not nest navigators of the same type (tabs-in-tabs, stack-in-stack at the same level).
86
+
- Do not create a nested navigator solely for code organization — group screens under a shared `screenOptions` prop instead.
87
+
- Do not navigate from `src/shared/**` directly — pass callbacks as props or use `navigationRef` helpers.
39
88
- Do not add navigation logic inside `src/shared/components/ui/` components.
89
+
- Do not pass full data objects as params — pass IDs and fetch data inside the screen.
90
+
- Do not leave empty directories under `src/navigation/` — remove the folder when the last file is deleted.
Copy file name to clipboardExpand all lines: .claude/rules/shared-services.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -35,7 +35,7 @@ shared/services/
35
35
- All HTTP calls must go through `http/http.client.ts` (exported `httpClient`) / `http/api.ts` helpers or a `transport/` adapter — never bare `fetch`.
36
36
- Every adapter must pass responses through `src/shared/utils/normalize-error.ts` for consistent error shapes.
37
37
- React Query client configuration (staleTime, retry, persistence) must live in `query/policy/`, `query/client/`, or `query/persistence/` — not scattered across feature hooks.
38
-
- Tag-based cache invalidation must use `query/helpers/invalidate-by-tags.ts`and tag constants from `query/tags.ts`.
38
+
- Tag-based cache invalidation must use `query/helpers/invalidate-by-tags.ts`. The `Tag`, `TagMap`, and `KeyGetter` types live in `query/tags.ts`; feature tag arrays (e.g. `AUTH_SESSION_TAGS`) and tagMaps belong in each feature's `api/keys.ts`.
39
39
- MMKV key strings must be imported from `src/config/constants.ts`.
40
40
- Sentry calls (`captureException`, `captureMessage`) must go through `monitoring/sentry.ts` helpers — do not call the Sentry SDK directly in feature code.
41
41
- The mock transport adapter (`transport/adapters/mock.adapter.ts`) is dev-only; it must be gated by `flags.USE_MOCK` from `src/config/constants.ts`.
description: Reviews React Native bare-workflow changes in this starter for correctness, regressions, architecture boundaries, React Query usage, theming, and test coverage. Use when reviewing PRs, diffs, or requested code reviews.
4
+
---
5
+
6
+
# RN Code Reviewer
7
+
8
+
Project-specific code review workflow for this React Native starter.
9
+
10
+
## When to apply
11
+
12
+
Use this skill when:
13
+
- Reviewing pull requests or local diffs
14
+
- Asked to "review" code quality, bugs, or regressions
15
+
- Validating RN architecture and repo conventions before merge
Copy file name to clipboardExpand all lines: AGENTS.md
+2-1Lines changed: 2 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -31,7 +31,7 @@ When changing SVGs, run `npm run gen:icons`. When changing i18n keys, run `npm r
31
31
-**src/i18n/** — useT, locales, extraction.
32
32
-**src/shared/components/ui/** — Reusable UI primitives (Button, Text, ScreenWrapper, …). If a component needs sharing, it either belongs here (truly generic) or stays in the feature that owns it — there is no intermediate category.
33
33
-**src/shared/hooks/** — Shared hooks.
34
-
-**src/shared/constants/** — Shared non-config constants (e.g. query invalidation tag lists). Storage key names and env-backed flags stay in **`src/config/`**.
34
+
-**src/shared/constants/** — Shared non-config constants. Storage key names and env-backed flags stay in **`src/config/`**. Tag arrays for cache invalidation (e.g. `AUTH_SESSION_TAGS`) belong in each feature's `api/keys.ts` — not here.
@@ -73,6 +73,7 @@ Use path alias `@/` only (e.g. `@/navigation/`, `@/session/`, `@/config/`, `@/i1
73
73
- No server data in Zustand; no feature logic in `src/shared/components/ui/` or `src/shared/stores/`.
74
74
- No deep relative imports; path aliases only (`check:imports`).
75
75
- When adding/changing SVGs: run `npm run gen:icons` and keep `check:icons` passing.
76
+
- No empty directories in `src/`. When moving or deleting files, remove the containing folder if it becomes empty. Empty folders signal dead code and confuse codebase navigation.
0 commit comments