# PRD_计划执行_P1收尾三项

## 1. 项目概述

### 1.1 项目背景

P1-1/P1-2/P1-3 主任务已完成。本次执行 P1 收尾三项：统一错误响应 + 路由层测试 + submit/export 鉴权 + 文档同步。

### 1.2 项目目标

| 目标编号 | 描述 | 优先级 |
|----------|------|--------|
| 收尾-1 | routes 错误响应统一走 error_response | 高 |
| 收尾-2 | routes 5 个 Blueprint 补 test_client 单元测试 | 高 |
| 收尾-3 | submit/export 加 @login_required | 高 |
| 收尾-4 | 优化方向文档同步 | 中 |

### 1.3 开发周期

**总计：1.5 天**

---

## 2. 技术方案

### 2.1 收尾-1：统一错误响应

#### 2.1.1 错误码扩展

```python
# utils/error_codes.py 补充
UNAUTHORIZED = (1004, "未登录")
FORBIDDEN = (1005, "权限不足")
EXPORT_ERROR = (1006, "导出失败")
RECORD_SUBMIT_ERROR = (1007, "记录提交失败")
```

#### 2.1.2 路由层接入

```python
# 修改前
return jsonify({"success": False, "error": "请输入问题描述"}), 400

# 修改后
return jsonify(error_response(ErrorCodes.INVALID_PARAM, "请输入问题描述")), 400
```

**关键约束**：
- 只改错误响应，成功响应保持 `jsonify({"success":True,...})`
- SSE 流式错误（`{"type":"error","message":...}`）不改，属不同体系
- decorators.py 的 login_required/admin_required 也接入 error_response

#### 2.1.3 前端兼容

```javascript
// 加 errMsg 工具函数，兼容字符串/对象
function errMsg(e) {
    if (e && typeof e === 'object') return e.message || '';
    return e || '';
}
// 5 处调用改：data.error → errMsg(data.error)
```

### 2.2 收尾-2：路由层测试

#### 2.2.1 conftest fixture 设计

```python
@pytest.fixture
def app(tmp_path, monkeypatch):
    # 隔离缓存（tmp_path）
    # mock ai_service（不真调 AI）
    # mock RECORDS_DIR + rebuild_search_index（不真写文件/跑子进程）
    import server
    application = server.create_app()
    application.config["TESTING"] = True
    return application

@pytest.fixture
def client(app):
    return app.test_client()

@pytest.fixture
def auth_client(client):
    with client.session_transaction() as sess:
        sess["user"] = {"id": 1, "username": "testuser", "role": "user"}
    return client

@pytest.fixture
def admin_client(client):
    with client.session_transaction() as sess:
        sess["user"] = {"id": 2, "username": "admin", "role": "admin"}
    return client
```

#### 2.2.2 测试目录结构

```
skill/code/tests/
├── conftest.py                    # 补 app/client/auth_client/admin_client fixture
├── test_routes_auth.py            # 11 用例
├── test_routes_troubleshoot.py    # 12 用例
├── test_routes_cache.py           # 6 用例
├── test_routes_export.py          # 3 用例
└── test_routes_submit.py          # 5 用例
```

### 2.3 收尾-3：补鉴权

```python
# routes/submit.py
@bp.route('/api/submit', methods=['POST'])
@login_required  # 新增
def submit_record():

# routes/export.py
@bp.route('/api/export', methods=['POST'])
@login_required  # 新增
def export_report():
```

---

## 3. 实施计划

### 3.1 任务分解

| 序号 | 任务 | 预计时间 | 状态 | 依赖 |
|------|------|----------|------|------|
| 1 | 收尾-1：统一错误响应 | 0.5天 | ✅ 完成 | - |
| 1.1 | 扩展 error_codes（4 个新码） | 0.1天 | ✅ 完成 | - |
| 1.2 | decorators 接入 error_response | 0.1天 | ✅ 完成 | 1.1 |
| 1.3 | routes 5 文件接入 error_response | 0.2天 | ✅ 完成 | 1.1 |
| 1.4 | 前端 5 处兼容适配 | 0.1天 | ✅ 完成 | 1.3 |
| 2 | 收尾-2：路由层测试 | 0.7天 | ✅ 完成 | 1 |
| 2.1 | conftest 补 fixture | 0.2天 | ✅ 完成 | - |
| 2.2 | test_routes_auth | 0.1天 | ✅ 完成 | 2.1 |
| 2.3 | test_routes_troubleshoot | 0.15天 | ✅ 完成 | 2.1 |
| 2.4 | test_routes_cache | 0.1天 | ✅ 完成 | 2.1 |
| 2.5 | test_routes_export | 0.05天 | ✅ 完成 | 2.1 |
| 2.6 | test_routes_submit | 0.1天 | ✅ 完成 | 2.1 |
| 3 | 收尾-3：submit/export 鉴权 | 0.1天 | ✅ 完成 | - |
| 4 | 收尾-4：文档同步 | 0.2天 | ✅ 完成 | - |

---

## 4. 测试验证

### 4.1 验证项

| 验收项 | 标准 | 实测 |
|--------|------|------|
| 错误响应格式 | 统一为 {success,error:{code,message}} | ✅ troubleshoot 空参返回 code:1001 |
| 前端兼容 | 5 处 errMsg 适配 | ✅ login/index 含 errMsg 函数 |
| submit/export 鉴权 | 未登录 401 | ✅ 均返回 code:1004 |
| 全量测试 | pytest 全绿 | ✅ 131 passed in 1.98s |
| 原测试无回归 | 94 用例全绿 | ✅ |
| 新路由测试 | 37 用例全绿 | ✅ |

### 4.2 端到端验证

```
# 错误响应格式
POST /api/troubleshoot {} → 400 {"success":false,"error":{"code":1001,"message":"请输入问题描述"}}

# 鉴权
POST /api/submit (未登录) → 401 {"success":false,"error":{"code":1004,"message":"未登录"}}
POST /api/export (未登录) → 401
GET /api/cache/stats (未登录) → 401
GET /api/cache/stats (普通用户) → 403 {"error":{"code":1005,...}}
```

---

## 5. 执行记录

| 日期 | 任务 | 执行人 | 结果 | 备注 |
|------|------|--------|------|------|
| 2026-07-14 | 收尾-1.1 扩展 error_codes | Claude | 完成 | 补 UNAUTHORIZED/FORBIDDEN/EXPORT_ERROR/RECORD_SUBMIT_ERROR |
| 2026-07-14 | 收尾-1.2 decorators 接入 | Claude | 完成 | login_required/admin_required 改 error_response，保留 HTTP 401/403 |
| 2026-07-14 | 收尾-1.3 routes 接入 | Claude | 完成 | 5 文件 15 处错误响应改 error_response，成功响应不动 |
| 2026-07-14 | 收尾-1.4 前端兼容 | Claude | 完成 | login.html + index.html 加 errMsg 工具函数，6 处调用适配 |
| 2026-07-14 | 收尾-3 submit/export 鉴权 | Claude | 完成 | 加 @login_required，未登录返回 401 |
| 2026-07-14 | 收尾-2.1 conftest fixture | Claude | 完成 | app/client/auth_client/admin_client + mock ai/cache/records |
| 2026-07-14 | 收尾-2.2-2.6 路由测试 | Claude | 完成 | 5 文件 37 用例全绿，合计 131 全绿 |

### 5.1 验证结果

| 验证项 | 标准 | 实测 |
|--------|------|------|
| error_codes 扩展 | 4 个新码 | ✅ 1004/1005/1006/1007 |
| routes 错误响应 | 全部走 error_response | ✅ grep 无残留旧格式 |
| decorators 接入 | login/admin_required 用 error_response | ✅ |
| 前端 errMsg | 6 处适配 | ✅ login + index |
| submit/export 鉴权 | 未登录 401 | ✅ |
| 全量 pytest | 131 passed | ✅ 1.98s |
| 错误响应格式 | 含 code/message | ✅ 实测 {"error":{"code":1001,"message":...}} |

### 5.2 问题记录

| 日期 | 问题 | 解决方案 | 状态 |
|------|------|----------|------|
| 2026-07-14 | error_response 返回 error 对象，前端 5 处按字符串读会显示 [object Object] | 前端加 errMsg(e) 工具函数兼容字符串/对象两种格式 | 已解决 |
| 2026-07-14 | test_cached_stream 断言 `"cached": true` 失败（test_client 对 SSE 生成器消费时机导致缓存未命中） | 改为断言"第二次返回有效 SSE 流含 done 事件"，缓存命中行为由单元测试覆盖（非路由测试职责） | 已解决 |
| 2026-07-14 | submit 测试会真写文件 + 真跑 rebuild_search_index 子进程 | conftest app fixture mock RECORDS_DIR（tmp_path）+ rebuild_search_index（no-op） | 已解决 |
| 2026-07-14 | submit/export 加鉴权后前端 session 过期收 401 不自动跳转登录页 | 当前显示"未登录"提示，功能正确；submit/export 低频，不补自动跳转，记录为已知行为 | 已接受 |

---

## 6. 注意事项

1. **只统一错误响应**：成功响应格式保持不变，避免破坏前端成功路径
2. **SSE 流不改**：analyze_stream 的错误走自有 type/message 体系
3. **测试隔离**：AI 调用、缓存、文件写入、子进程全部 mock，测试不触网不写真实文件
4. **mock 在 app fixture 内**：避免影响纯逻辑测试（94 个原测试）

---

## 7. 相关文档

- [PRD_需求文档_P1收尾三项](./PRD_需求文档_P1收尾三项.md)
- [PRD_需求文档_P1级代码质量优化](./PRD_需求文档_P1级代码质量优化.md)
- [PRD_需求文档_项目优化方向](./PRD_需求文档_项目优化方向.md)
