# 系统架构

## 核心不变量

`.bean` 文件是唯一事实来源；SQLite 仅为可丢弃的读缓存。

## 数据流

```mermaid
flowchart LR
    subgraph DataSource[数据源]
        A[".bean 文件"]
        B["OCR / 无障碍 / 通知 / 短信"]
        C[“手动录入 / CSV 导入"]
    end

    subgraph Pipeline[处理层]
        D["BillPipeline 串行互斥锁"]
        E[“转账识别"]
        F[“去重"]
        G[“规则分类"]
    end

    subgraph Storage[存储层]
        H["main.bean 追加写入"]
        I["SQLite 缓存"]
        J["Zustand Store 内存索引"]
    end

    subgraph UI[展示层]
        K["Expo Router 页面"]
        L[“报表 / 图表"]
    end

    A -->|parseLedger| J
    B -->|原始事件| D
    C -->|TransactionDraft| D
    D --> E --> F --> G
    G -->|确认写入| H
    H -->|reparse| J
    J --> K
    J --> L
    I -.->|搜索查询| J
```

## 模块分层

```mermaid
graph TB
    subgraph UILayer["UI 层: src/app + src/components"]
        R[“Expo Router 页面"]
        CO[“可复用组件"]
    end

    subgraph StateLayer["状态层: src/store"]
        S[“Zustand Stores"]
    end

    subgraph DomainLayer["领域层: src/domain — 纯 TS 零 RN 依赖"]
        LE["ledger.ts 解析器"]
        P["billPipeline.ts"]
        D2["dedup / transfer / rules"]
        O["ocrProcessor.ts"]
    end

    subgraph Infra[“基础设施"]
        FS["expo-file-system"]
        DB["expo-sqlite"]
        NAT["plugins/ 原生模块"]
    end

    R --> S
    CO --> S
    S --> LE
    S --> P
    P --> D2
    P --> O
    LE --> FS
    D2 --> DB
    O --> NAT
```

## BillPipeline 处理顺序

所有导入渠道（手动、CSV、OCR、无障碍、通知、短信、截图）统一经过 `BillPipeline`，严格按序执行：

1. **转账识别** — 配对收入+支出 → 单笔转账（必须先于去重）
2. **批内去重** — 时间窗口 + 金额 + 交易对手
3. **历史去重** — 按日期索引比对已提交交易
4. **规则分类** — 规则匹配 → 关键词 → `Uncategorized` 兆底

## 原生模块

原生功能以 Expo Config Plugin 形式封装在 `plugins/<name>/`，详见 [plugins/README.md](../plugins/README.md)。

原生服务**不直接写入**数据库或文件，而是通过 `NativeEventEmitter` 将原始事件推送到 JS 层管道。

## OCR 三层级联

```mermaid
flowchart LR
    A[“图像输入"] --> B["Layer 1: 正则规则"]
    B -->|未命中| C["Layer 2: 本地 OCR PP-OCRv6"]
    C -->|未命中| D["Layer 3: AI Vision 付费"]
```

## 双轨映射

Beancount 无原生“分类/预算”概念，应用在本地 SQLite 维护 UI 元数据，写入时映射回 Beancount 语义：

| 概念 | 本地表 | 映射到 `.bean` |
|------|--------|----------------|
| 分类 | `categories` | `linkedAccount` → posting 账户 |
| 标签 | `tags` | narration 中的 `#tag` |
| 预算 | `budgets` | 仅本地，不影响余额 |
| 信用卡 | `credit_cards` | 账户在 `.bean`，UI 字段本地 |
