# Repository Guidelines

## Project Overview

DriftLedger (浮记) is an offline-first mobile client for [Beancount](https://beancount.github.io/) double-entry accounting, built with React Native + Expo (CNG), TypeScript, Zustand, and expo-sqlite. The app treats desktop-maintained `.bean` files as the read-only source of truth and appends new entries to `main.bean`.

## Project Structure & Module Organization

| Directory | Purpose |
|-----------|---------|
| `src/domain/` | Pure business logic (ledger parser, bill pipeline, dedup, rules, OCR processor). No React/RN imports. |
| `src/app/` | Expo Router file-based routes; `(tabs)/` is bottom navigation. |
| `src/components/` | Reusable React Native UI components and charts. |
| `src/store/` | Zustand stores (ledger, import, settings, metadata, automation). |
| `src/services/` | Platform-facing concerns (sync, backup, security, OCR bridge). |
| `src/storage/` | SQLite read-cache with versioned migrations. |
| `src/theme/` | Token-based theming system. |
| `src/i18n/` | zh/en localization dictionaries. |
| `plugins/` | Expo Config Plugins for native modules (ppocr, accessibility, sms-receiver, etc.). |
| `tests/` | Vitest unit tests (mock-backed, domain-focused). |

## Build, Test, and Development Commands

```bash
npm install --legacy-peer-deps   # Install dependencies (legacy-peer-deps required)
npm run start                    # Start Metro dev server
npm run android                  # Build & run on Android device/emulator
npm test                         # Run full Vitest suite
npm run typecheck                # TypeScript strict-mode check (tsc --noEmit)

# Run a single test file:
npx vitest run tests/ledger.test.ts
```

## Coding Style & Naming Conventions

- **TypeScript strict mode** is enabled; path alias `@/*` maps to `src/*`.
- **Money math** uses string decimals (`src/domain/decimal.ts`) — never raw JS floats.
- **Domain layer** (`src/domain/`) must remain pure: no React, RN, or Expo imports. Inject external dependencies via interfaces.
- Code comments and `plan.md` are written in **Chinese**; match that convention.
- New domain modules must be re-exported from `src/domain/index.ts`.
- Native code lives exclusively in `plugins/<name>/` as Expo Config Plugins — never edit generated `android/` files directly.

## Testing Guidelines

- Framework: **Vitest** (no config file; picks up `tests/**/*.test.ts` by default).
- Tests target the domain layer using mock backends (`MemoryBackend`, `MockOcrEngine`).
- Name test files descriptively: `<module-or-feature>.test.ts` (e.g., `decimal.test.ts`, `billPipeline.test.ts`).
- Run `npm run typecheck` after non-trivial changes to catch type regressions.

## Commit & Pull Request Guidelines

- Commit messages follow the pattern: `feat: <concise summary in Chinese>` with a detailed multi-line body listing changes by area.
- Example: `feat: 品牌重命名为浮记(DriftLedger)，全面升级精度安全与架构`
- PRs should describe what changed and why; link related issues. Include screenshots for UI changes.

## Key Architectural Invariants

1. `.bean` files are the source of truth; SQLite is a disposable read-cache.
2. All bill ingestion funnels through `BillPipeline` (`src/domain/billPipeline.ts`) under a serialized mutex.
3. Every Config Plugin function **must `return config`** at the end.
4. IDs/checksums use FNV-1a hashing (`hash()` in `ledger.ts`), not crypto hashes.
