Skip to content

Commit 5f332ba

Browse files
maximcodingclaude
andcommitted
Navigation dynamic config, theme cleanup, agent/rule updates
Navigation: - Revert root-navigator to dynamic JSX config (Stack.Navigator/Screen) with typed generic params; useInitialRoute() hook in component body - Add HomeTabParamList to root-param-list.ts; export from index.ts - Update NavigationRoot.tsx and AnimatedTabBar.tsx accordingly Theme: - Remove unused italic font variant from fonts.ts - Add brand.ts token file; export from theme index - Sync dark/light theme with new token Auth / User: - Export AUTH_SESSION_TAGS from auth/api/keys.ts (satisfies AuthTag[]) - Export USER_UPDATE_TAGS from user/api/keys.ts - Remove dead oauth-brand-colors.ts constant file - Update useLoginMutation and useUpdateProfile to import named tag arrays Docs / rules: - Update navigation.md to reflect dynamic config (not static) - Minor fixes in CLAUDE.md, react-query.md, shared-services.md, development.md - Remove rn-architect agent (superseded by rn-code-reviewer) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent ee3dc54 commit 5f332ba

24 files changed

Lines changed: 353 additions & 395 deletions

.claude/CLAUDE.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ src/
2929
├── shared/ # Cross-cutting code — must NOT import from features
3030
│ ├── components/ui/ # Button, Text, ScreenWrapper, …
3131
│ ├── hooks/
32-
│ ├── constants/ # shared non-config constants (not storage keys)
32+
│ ├── constants/ # shared non-config constants (not storage keys; tag arrays belong in feature api/keys.ts)
3333
│ ├── services/api|storage/
3434
│ ├── stores/
3535
│ ├── theme/

.claude/agents/code-reviewer.md

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,20 +33,28 @@ You are a senior code reviewer for this React Native TypeScript project. Your st
3333
- [ ] Strict mode compliance — no implicit `any`, no untyped function returns on exported APIs
3434
- [ ] Zod schemas validate every API response in feature services before returning domain models
3535

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+
3642
### UI & Styling
3743
- [ ] 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
4047
- [ ] Shared UI components accept strings as props — no hardcoded user-facing copy
4148

4249
### 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)
4552

4653
### State & Data
4754
- [ ] Server state via React Query; local UI state via `useState`; global UI state via Zustand in `src/shared/stores/`
4855
- [ ] 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
5058
- [ ] MMKV key strings imported from `src/config/constants.ts`, not hardcoded
5159

5260
### React Native Specifics

.claude/agents/rn-architect.md

Lines changed: 0 additions & 229 deletions
This file was deleted.

.claude/rules/navigation.md

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@ Global rules: [AGENTS.md](../../AGENTS.md). Claude stack summary: [CLAUDE.md](..
77
# Rules — navigation
88

99
## Structure
10-
- **Static config** (`src/navigation/root/root-navigator.tsx`): `createNativeStackNavigator({screens:{}})` — no JSX navigator wrappers.
11-
- **Root entry** `src/navigation/NavigationRoot.tsx`: `createStaticNavigation(RootStack)` — render exactly once, no second instance.
12-
- **Initial route:** `getInitialRoute()` from `src/session/bootstrap.ts` — sync MMKV read that resolves `ROOT_ONBOARDING | ROOT_AUTH | ROOT_APP`.
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`.
1313
- **Routes:** all constants in `src/navigation/routes.ts` — never inline route string literals anywhere.
14-
- **ParamList:** `RootStackParamList` in `src/navigation/root-param-list.ts`; declared manually (not via `StaticParamList`) to avoid circular deps through feature screens. Declared globally once:
14+
- **ParamLists:** `RootStackParamList` and `HomeTabParamList` in `src/navigation/root-param-list.ts`; declared manually to avoid circular deps. Global augmentation declared once there:
1515
```ts
1616
declare global {
1717
namespace ReactNavigation {
@@ -30,14 +30,15 @@ GestureHandlerRootView
3030
ErrorBoundary
3131
QueryProvider
3232
OfflineBanner
33-
NavigationRoot
33+
NavigationRoot ← contains NavigationContainer + RootNavigator
3434
```
3535

36-
## Static config rules (React Navigation v7)
37-
- Add screens via the `screens` object — each value is a component, a nested static navigator, or `{ screen, options, linking }`.
38-
- Use `groups` to share `screenOptions` across a set of screens — do not create a nested navigator just for code organization.
39-
- Use the `if` property (hook callback) on a screen or group for conditional rendering (auth gate, feature flag). Never call `navigation.navigate()` after auth state changes — React Navigation transitions automatically.
40-
- Attach dynamic logic (runtime `screenOptions`, `screenListeners`) via `.with()` — it shallow-merges with the static config.
36+
## Dynamic navigator rules (React Navigation v7)
37+
- 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.
4142

4243
## Params
4344
- Params must be **JSON-serializable** — required for state persistence and deep linking.
@@ -79,10 +80,10 @@ GestureHandlerRootView
7980
- `InteractionManager.runAfterInteractions` for heavy non-UI work triggered by navigation.
8081

8182
## Must not
82-
- Do not render a second `createStaticNavigation(...)` instance — one root only.
83+
- Do not render a second `<NavigationContainer>` — one root only.
8384
- Do not call `navigation.navigate()` after an auth state change — conditional screen rendering handles it.
8485
- Do not nest navigators of the same type (tabs-in-tabs, stack-in-stack at the same level).
85-
- Do not create a nested navigator solely for code organization — use `groups` instead.
86+
- Do not create a nested navigator solely for code organization — group screens under a shared `screenOptions` prop instead.
8687
- Do not navigate from `src/shared/**` directly — pass callbacks as props or use `navigationRef` helpers.
8788
- Do not add navigation logic inside `src/shared/components/ui/` components.
8889
- Do not pass full data objects as params — pass IDs and fetch data inside the screen.

.claude/rules/react-query.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ Never hardcode numeric stale/gc values — always reference a `Freshness` profil
3838

3939
## Must not
4040
- No React Query keys inline in components — always use `api/keys.ts`.
41+
- No tag arrays (e.g. `['auth:me', 'auth:session']`) inline in hooks — export named arrays from the feature's `api/keys.ts` and import from there.
4142
- No `invalidateQueries()` without a targeted key — use tag-based invalidation.
4243
- No magic `staleTime` / `gcTime` numbers — use `Freshness` profiles.
4344
- No server data duplicated in Zustand.

.claude/rules/shared-services.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ shared/services/
3535
- All HTTP calls must go through `http/http.client.ts` (exported `httpClient`) / `http/api.ts` helpers or a `transport/` adapter — never bare `fetch`.
3636
- Every adapter must pass responses through `src/shared/utils/normalize-error.ts` for consistent error shapes.
3737
- 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`.
3939
- MMKV key strings must be imported from `src/config/constants.ts`.
4040
- Sentry calls (`captureException`, `captureMessage`) must go through `monitoring/sentry.ts` helpers — do not call the Sentry SDK directly in feature code.
4141
- 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`.
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# RN Starter Review Checklist
2+
3+
Use this as a concise pass/fail checklist during reviews.
4+
5+
## Correctness
6+
- [ ] Logic changes handle happy path and edge cases.
7+
- [ ] Async flows handle loading, success, and error states.
8+
- [ ] Errors are not swallowed; context is preserved.
9+
10+
## Architecture and imports
11+
- [ ] `src/shared` does not import feature code.
12+
- [ ] Imports use `@/` aliases, not deep relative paths.
13+
- [ ] New feature code is placed under `src/features/<feature>/...`.
14+
15+
## RN UI and theming
16+
- [ ] No raw colors/spacing/fonts in UI code.
17+
- [ ] Styling uses theme tokens and `StyleSheet.create()`.
18+
- [ ] Platform-specific behavior is handled where required.
19+
20+
## Data and state
21+
- [ ] Server state uses React Query patterns from feature `api/keys.ts`.
22+
- [ ] Mutations include targeted invalidation patterns.
23+
- [ ] No server/domain data is moved into Zustand global stores.
24+
- [ ] No direct `fetch` usage; transport/API layer is used.
25+
26+
## Tests
27+
- [ ] Non-trivial behavior changes include tests.
28+
- [ ] Missing tests are called out with exact suggested scenarios.
29+
- [ ] Residual risk and untested paths are explicitly noted.
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
---
2+
name: rn-code-reviewer
3+
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
16+
17+
## Review priorities
18+
19+
Always prioritize findings in this order:
20+
1. Correctness and behavioral regressions
21+
2. Security/privacy risks and error handling gaps
22+
3. Architecture and boundary violations
23+
4. Performance concerns with real user impact
24+
5. Missing or weak tests
25+
26+
## Required checks
27+
28+
### 1) Correctness and risk
29+
- Verify changed logic matches intended behavior and handles edge cases.
30+
- Flag silent failures, swallowed errors, or lossy error handling.
31+
- Check async flows for loading, success, and error-state handling.
32+
33+
### 2) Repository architecture constraints
34+
- Enforce feature/shared boundaries (`src/shared` must not import from features).
35+
- Enforce alias imports (`@/`); flag deep relative imports.
36+
- Verify feature code stays under `src/features/<feature>/...` with expected folders.
37+
38+
### 3) React Native UI conventions
39+
- Flag raw colors/spacing/fonts in UI; require theme tokens.
40+
- Prefer `StyleSheet.create()` over broad inline styles (except dynamic values).
41+
- Verify platform-specific behavior is handled where needed (`Platform.select`, native differences).
42+
43+
### 4) Data/state conventions
44+
- Server state should use React Query (feature-level `api/keys.ts` key patterns).
45+
- Mutations should use targeted invalidation (`meta.tags` / invalidation paths).
46+
- Flag server data leaking into Zustand stores.
47+
- Flag direct `fetch` usage (project transport layer should be used).
48+
49+
### 5) Tests and verification
50+
- Ensure non-trivial logic changes include tests or justify why not.
51+
- Suggest concrete missing tests (what behavior, where to add).
52+
- Highlight risky untested paths before merge.
53+
54+
## Output format
55+
56+
Return findings first, ordered by severity:
57+
58+
1. `Critical` — must fix before merge
59+
2. `Major` — high-impact issues, should fix
60+
3. `Minor` — quality/maintainability improvements
61+
62+
For each finding include:
63+
- File path
64+
- Why it is a problem (risk/regression)
65+
- Specific fix direction
66+
67+
Then include:
68+
- Open questions/assumptions
69+
- Brief change summary (secondary)
70+
- Residual testing gaps
71+
72+
## Review behavior rules
73+
74+
- Do not lead with a broad summary before findings.
75+
- Be explicit about potential regressions and user impact.
76+
- Prefer actionable, minimal suggestions over large refactors.
77+
- If no issues are found, explicitly state "No findings" and note residual risks or test gaps.
78+
79+
## Additional reference
80+
81+
Use this checklist for quick pass/fail scanning:
82+
- [CHECKLIST.md](CHECKLIST.md)

docs/development.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ src/
1717
├── shared/ # Cross-app code (must NOT import from features)
1818
│ ├── components/ui/ # Button, Text, ScreenWrapper, OfflineBanner, IconSvg, ErrorBoundary, Activity, SuspenseBoundary
1919
│ ├── hooks/ # Shared hooks (useAppState, useToggle, …)
20-
│ ├── constants/ # Shared non-config constants (e.g. query tag lists)
20+
│ ├── constants/ # Shared non-config constants (tag arrays belong in feature api/keys.ts)
2121
│ ├── services/
2222
│ │ ├── api/ # http, transport, query, network, offline
2323
│ │ ├── monitoring/ # Optional Sentry init + boundary reporting (see OPERATIONS.md#sentry)

src/features/auth/api/keys.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,3 +43,8 @@ export const authKeys = {
4343
} as const
4444

4545
export type AuthTag = keyof typeof tagMap
46+
47+
export const AUTH_SESSION_TAGS = [
48+
'auth:me',
49+
'auth:session',
50+
] as const satisfies readonly AuthTag[]

0 commit comments

Comments
 (0)