# Phase 5: 联调与集成（W5-W6）

> **目标：** 前后端联调跑通完整流程，配置规则种子数据，确保全链路畅通。  
> **周期：** 第 5 ~ 6 周  
> **任务数：** 2 个  
> **可并行：** 联调和种子数据可由不同人并行  
> **前置依赖：** Phase 3 + Phase 4

---

## 本阶段交付物

| 交付物 | 说明 |
|---|---|
| 完整流程跑通 | 从创建任务到同步成功的端到端流程 |
| 规则种子数据 | 差旅报销制度 + 6 条核心规则 + 城市等级标准 |

---

## 任务清单

### Task 5.1: 前后端联调

**负责人：** 全员参与  
**预计工时：** 3-4 天  
**前置依赖：** Phase 3 + Phase 4

**Files:**
- Modify: 多个前后端文件（修复联调问题）

- [ ] **Step 1: 启动前后端全栈环境**

```bash
# 启动基础设施
docker-compose up -d

# 启动后端
cd backend
alembic upgrade head
uvicorn app.main:app --reload --port 8000

# 启动前端
cd frontend
npm run dev
```

确认：
- PostgreSQL 可连接：`psql -h localhost -U postgres -d x_financial`
- Redis 可连接：`redis-cli ping`
- MinIO 可访问：http://localhost:9001
- 后端健康检查：http://localhost:8000/health
- 前端可访问：http://localhost:5173

- [ ] **Step 2: 跑通完整报销流程（10 步）**

按开发文档 3.1 节的完整流程：

**步骤 1 - 创建任务**
1. 访问首页 http://localhost:5173
2. 在输入框输入"我要报这次北京出差的费用"
3. 点击提交
4. 验证：任务创建成功，跳转到上传页

**步骤 2 - 上传票据**
1. 选择票据类型：增值税发票
2. 上传模拟发票文件（可用任意 PDF/PNG）
3. 选择票据类型：火车票
4. 上传模拟火车票文件
5. 验证：文件列表显示 2 个文件

**步骤 3 - 启动 Agent 识别**
1. 点击"开始识别"
2. 等待 Agent 处理（观察后端日志）
3. 验证：跳转到草稿页，显示识别结果

**步骤 4 - 查看报销草稿**
1. 确认费用明细已自动填充
2. 检查金额、商户、日期等字段
3. 验证：可编辑字段能修改

**步骤 5 - 执行预审**
1. 点击"执行预审"
2. 等待规则引擎执行
3. 验证：跳转到预审结果页

**步骤 6 - 查看预审结果**
1. 检查总体结论
2. 查看风险项（如有）
3. 查看缺件项（如有）
4. 验证：规则命中详情展示正确

**步骤 7 - 补件（如需要）**
1. 点击"一键补件"
2. 在补件页上传缺失附件
3. 提交补件
4. 验证：跳转回预审页，重新预审

**步骤 8 - 确认提交**
1. 确认报销单摘要
2. 点击"确认提交"
3. 等待同步状态更新
4. 验证：同步状态变为 success

**步骤 9 - 查看审计日志**
1. 访问审计日志页
2. 按任务ID筛选
3. 验证：所有操作步骤都有记录

**步骤 10 - 查看后端 Swagger**
1. 访问 http://localhost:8000/docs
2. 验证所有 API 文档正确

- [ ] **Step 3: 修复联调过程中发现的问题**

常见问题检查清单：
- [ ] API 响应格式前后端一致（字段名、嵌套结构）
- [ ] 日期格式统一（ISO 8601）
- [ ] 金额精度（Decimal vs Number）
- [ ] 错误处理（前端能正确显示后端错误信息）
- [ ] 文件上传大小限制（前端 + 后端 + MinIO）
- [ ] 跨域配置正确
- [ ] 路由跳转正常
- [ ] Loading 状态显示
- [ ] 空状态展示

- [ ] **Step 4: 压力测试关键接口**

- `POST /tasks` 创建 100 个任务
- `GET /tasks` 列表查询响应时间 < 500ms
- `POST /tasks/{id}/documents` 上传 10 个文件
- `POST /tasks/{id}/agent/run` Agent 执行时间 < 30s

- [ ] **Step 5: Commit**

```bash
git add .
git commit -m "fix: 前后端联调修复（完整流程跑通）"
```

---

### Task 5.2: 规则配置与种子数据

**负责人：** 全栈/Agent 工程师  
**预计工时：** 2 天  
**前置依赖：** Phase 2（规则引擎）  
**可并行于：** Task 5.1

**Files:**
- Create: `backend/alembic/seed/expense_policies.sql`
- Create: `backend/alembic/seed/expense_rules.sql`
- Create: `backend/alembic/seed/city_levels.sql`
- Create: `backend/alembic/seed/hotel_limits.sql`
- Create: `backend/scripts/seed_data.py`

- [ ] **Step 1: 编写城市等级数据**

`backend/alembic/seed/city_levels.sql`：

按典型企业标准配置：
- **一线城市**：北京、上海、广州、深圳
- **二线城市**：杭州、南京、成都、武汉、重庆、天津、苏州、西安
- **三线城市**：其他城市

```sql
CREATE TABLE IF NOT EXISTS city_level (
    city_name VARCHAR(50) PRIMARY KEY,
    level VARCHAR(10) NOT NULL  -- tier1 / tier2 / tier3
);

INSERT INTO city_level (city_name, level) VALUES
('北京', 'tier1'), ('上海', 'tier1'), ('广州', 'tier1'), ('深圳', 'tier1'),
('杭州', 'tier2'), ('南京', 'tier2'), ('成都', 'tier2'), ('武汉', 'tier2'),
('重庆', 'tier2'), ('天津', 'tier2'), ('苏州', 'tier2'), ('西安', 'tier2');
```

- [ ] **Step 2: 编写住宿标准数据**

`backend/alembic/seed/hotel_limits.sql`：

```sql
CREATE TABLE IF NOT EXISTS hotel_limit (
    city_level VARCHAR(10) NOT NULL,
    job_level VARCHAR(20) NOT NULL,  -- manager / senior / staff
    limit_per_night DECIMAL(10,2) NOT NULL,
    PRIMARY KEY (city_level, job_level)
);

INSERT INTO hotel_limit (city_level, job_level, limit_per_night) VALUES
('tier1', 'manager', 800.00), ('tier1', 'senior', 600.00), ('tier1', 'staff', 500.00),
('tier2', 'manager', 600.00), ('tier2', 'senior', 450.00), ('tier2', 'staff', 350.00),
('tier3', 'manager', 500.00), ('tier3', 'senior', 350.00), ('tier3', 'staff', 300.00);
```

- [ ] **Step 3: 编写规则种子数据**

`backend/alembic/seed/expense_rules.sql` — 预置开发文档 7.2 节的 3 条示例规则 + MVP 需要的 6 条核心规则：

1. `TRAVEL_HOTEL_LIMIT` — 住宿费标准校验（severity: medium, action: require_explanation）
2. `HOTEL_BILL_REQUIRED` — 住宿费必须上传酒店流水（severity: medium, action: require_attachment）
3. `DUPLICATE_INVOICE_CHECK` — 重复发票检查（severity: blocked, action: block）
4. `REQUIRED_FIELDS_CHECK` — 必填字段校验（severity: medium, action: warn）
5. `AMOUNT_ABNORMAL_CHECK` — 金额异常检查（severity: high, action: require_explanation）
6. `DATE_VALIDITY_CHECK` — 日期合理性校验（severity: low, action: warn）
7. `EXPENSE_TYPE_MATCH_CHECK` — 费用类型匹配校验（severity: low, action: warn）
8. `INVOICE_TITLE_CHECK` — 发票抬头校验（severity: high, action: require_explanation）
9. `TRIP_PERIOD_MATCH_CHECK` — 出差期间匹配校验（severity: medium, action: warn）

每条规则包含完整的 condition_json、action、severity、message_template、policy_ref。

- [ ] **Step 4: 编写数据初始化脚本**

`backend/scripts/seed_data.py` — 一键初始化所有种子数据：

```python
"""初始化种子数据"""
import asyncio
from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession
from app.core.config import settings
# ... 读取 SQL 文件并执行

async def main():
    engine = create_async_engine(settings.DATABASE_URL)
    async with engine.begin() as conn:
        # 按顺序执行 seed SQL
        for sql_file in ['city_levels.sql', 'hotel_limits.sql', 'expense_rules.sql']:
            with open(f'alembic/seed/{sql_file}') as f:
                await conn.execute(f.read())
    print("Seed data loaded successfully!")

if __name__ == "__main__":
    asyncio.run(main())
```

- [ ] **Step 5: 验证种子数据**

Run: `cd backend && python scripts/seed_data.py`
验证：
- 城市等级表有数据
- 住宿标准表有数据
- 规则表有 9 条规则且全部 enabled

- [ ] **Step 6: Commit**

```bash
git add backend/
git commit -m "feat: 添加差旅报销制度和规则种子数据"
```

---

## 本阶段完成检查

- [ ] 完整报销流程（创建→上传→识别→草稿→预审→补件→提交→同步）端到端跑通
- [ ] 前后端 API 格式一致，无字段不匹配
- [ ] 错误场景有正确提示（上传失败、OCR 失败、同步失败）
- [ ] 种子数据加载成功，规则引擎使用种子数据执行预审
- [ ] Swagger 文档 http://localhost:8000/docs 可访问
- [ ] 审计日志记录了完整操作链路
