Android client built with Expo SDK 57 (expo-router) + React Native 0.86 + React 19 + TypeScript + NativeWind. Server state via TanStack Query, client state via Zustand, schema validation via Zod, storage via MMKV/SecureStore.
Expo HAS CHANGED. Read the exact versioned docs at https://docs.expo.dev/versions/v57.0.0/ before writing any code.
| Task | Command |
|---|---|
| Dev server | npm start |
| Run on Android | npm run android |
| Lint | npm run lint |
| Format | npm run format / format:check |
| Type check | npm run typecheck |
| Unit tests (watch) | npm run test |
| Unit tests (CI) | npm run test:ci (single run) |
| E2E (Maestro) | npm run e2e:android |
- Node >= 22, path alias
@/*→./src/*(plus@/assets/*→./assets/*) - The pre-commit hook (husky) runs ESLint/Prettier via lint-staged automatically; commit-msg runs commitlint.
src/
├── app/ # expo-router file-based routes (screens live here)
├── components/ # Reusable components (components/ui: generic UI primitives)
├── constants/ # Design tokens, constants (theme.ts)
├── hooks/ # Shared hooks (use-theme, use-color-scheme, ...)
├── lib/ # Core modules (http, i18n, storage, sentry, query-client, env)
├── locales/ # i18n resources (ko/en)
└── types/ # Global type declarations
- Screens are expo-router route files in
src/app/. Keep route files focused on screen composition — extract reusable pieces intocomponents/. - Domain-agnostic UI primitives (button, collapsible, themed text) go to
components/ui/; app-specific composites go tocomponents/. - Cross-cutting logic (API client, storage, i18n) lives in
lib/; never duplicate it inside components. - Platform-specific implementations use file suffixes (
*.web.tsx,*.android.tsx) next to the default file. - Always use the
@/alias for cross-directory imports; relative paths only within the same directory. - Environment variables are read only through
lib/env.ts(Zod-validated) — never accessprocess.envelsewhere.
Format: type: 짧은 한글 설명 — a single short subject line in Korean, nothing else (no body, no trailers). Split changes into logical units.
- Types:
featfixrefactorstyletestdocscichore - Examples:
feat: 로그인 폼 추가,fix: CI 액션 버전 최신화
Never push unless the user explicitly asks. Committing autonomously is fine.
- Branch off
develop, namedtype/short-kebab-description— same types as commits. - Examples:
feat/login-form,fix/splash-hang,ci/setup-github-actions
- Base branch:
develop(fall back tomainif absent) - The PR template is mandatory: always read
.github/PULL_REQUEST_TEMPLATE.mdand follow its structure exactly, written in Korean. Fill every applicable section; delete sections that don't apply. (If the template file doesn't exist yet, use the structure in the/prskill.) - Before opening a PR, verify locally:
npm run lint,npm run format:check,npm run typecheck,npm run test:ci.
- Unit tests live in a colocated
__tests__/directory or next to their target file as*.test.ts(x) - Jest (
jest-expopreset) + React Native Testing Library - E2E flows live in
.maestro/and run with Maestro (npm run e2e:android)
Detailed conventions live in .claude/rules/ and load automatically per file pattern:
typescript.md— strict typing rules (noany, noas, noenum, ...)react-native.md— component structure, expo-router/RN idiomsstyling.md— theme token usage, no hardcoded valuestesting.md— Jest/Testing Library and Maestro conventions