# AGENTS.md

This is a cross platform mobile app built with Expo, Expo Router, and TypeScript.

## Project

Stack: Expo SDK 52, React Native, TypeScript (strict), Expo Router, React Query, Zustand for local state, EAS Build and EAS Update.

Layout:

- `app/` Expo Router routes, the directory tree is the navigation tree
- `app/(tabs)/` bottom tab navigator, `app/(auth)/` unauthenticated stack
- `app/_layout.tsx` root providers, `app/+not-found.tsx` fallback
- `src/components/` shared presentational components
- `src/features/<feature>/` screens, hooks, and API calls for one feature
- `src/api/` typed fetch clients and React Query hooks
- `src/native/` thin wrappers around Expo modules (camera, notifications, storage)
- `src/theme/` spacing, colors, typography tokens
- `app.config.ts` app identity, plugins, permissions
- `eas.json` build profiles

Entry points: `app/_layout.tsx`, `app.config.ts`, `eas.json`.

## Commands

```bash
pnpm install
pnpm start                       # metro bundler
pnpm ios                         # run on iOS simulator
pnpm android                     # run on Android emulator
pnpm lint
pnpm typecheck                   # tsc --noEmit
pnpm test                        # jest with jest-expo
npx expo install <package>       # install a package at the SDK compatible version
npx expo prebuild --clean        # regenerate native projects, ask first
npx expo-doctor                  # diagnose config and version drift
eas build --profile development --platform ios
eas build --profile production --platform all
eas update --branch preview      # OTA update, JS only
```

Use `npx expo install` for any package with a native component, not `pnpm add`.

A change to `app.config.ts` plugins, permissions, or a new native dependency requires a new development build. JavaScript only changes reload in the existing build.

## Platform notes

- Test every screen on both an iOS simulator and an Android emulator before calling it done.
- Safe areas: use `useSafeAreaInsets` from react-native-safe-area-context. Do not hardcode status bar height.
- Android back button needs explicit handling on any screen with a modal or a multi step flow.
- Permissions are requested at the moment of use, never on app launch. Both platforms need a usage description in `app.config.ts`.
- Keyboard behavior differs: use `KeyboardAvoidingView` with `behavior="padding"` on iOS and `"height"` on Android.
- Shadows need `elevation` on Android and `shadow*` props on iOS. Use the helper in `src/theme/shadows.ts`.
- Fonts and icons load asynchronously, keep the splash screen up until `useFonts` resolves.
- OTA updates cannot ship native changes. If a change touches native code it needs a store build.

## Code style

- Styles go in `StyleSheet.create` at the bottom of the file. No inline style objects inside render.
- Use `FlashList` or `FlatList` for any list that can exceed ten items. Never map an array into a ScrollView.
- Every list item component is memoized and every list has a stable `keyExtractor`.
- Server state belongs to React Query. Local UI state belongs to component state or Zustand. Do not mirror server data in a store.
- Navigation uses typed routes from Expo Router. No string concatenation for hrefs.
- Native APIs are only called through `src/native/`, so permissions and fallbacks live in one place.
- Spacing and color come from `src/theme/`. No raw hex values or magic numbers in components.
- Images use `expo-image` with an explicit width and height.

## Boundaries

Do not touch without explicit instruction:

- `ios/` and `android/` directories. They are generated by prebuild.
- `app.config.ts` bundle identifier, package name, scheme, version, or build number.
- `eas.json` build profiles and any signing credential.
- `pnpm-lock.yaml`, `.env`, store metadata and screenshots.

Needs human review: new native dependencies, permission additions, changes to push notification handling, and anything affecting deep links.

Version numbers are set by the release process, not by a code change.

## Testing

- `pnpm test` runs Jest with the jest-expo preset.
- Required tests: everything in `src/api/` (request shaping, response parsing), pure helpers, and state reducers.
- Component tests use @testing-library/react-native and cover behavior, not layout.
- Native module wrappers are tested with the Expo module mocked.
- Interaction and layout are verified on device, not in the test suite.

## Git workflow

- Branch from `main`: `feat/short-description`, `fix/short-description`.
- Conventional commits: `fix(onboarding): keep keyboard clear of the submit button`.
- PR description includes screenshots or a screen recording from both iOS and Android.
- State in the PR whether the change is OTA safe or requires a new build.
- Never commit to `main`.
