# PRD_计划执行_普通用户项目名称输入限制

## 1. 项目概述

### 1.1 背景

当前项目名称输入框通过 datalist 一次性加载全部 120 个项目，任何登录用户（含普通用户）均可浏览完整项目列表，存在项目信息泄露风险。需按角色限制：普通用户纯输入、管理员保留下拉搜索。

### 1.2 目标

| 目标编号 | 描述 | 优先级 |
|---------|------|--------|
| 1 | `/api/projects` 后端角色鉴权 | 🟠 高 |
| 2 | 前端按角色决定是否填充 datalist | 🟠 高 |

### 1.3 开发周期

预估 1.5 小时。

---

## 2. 技术方案

### 2.1 后端：`/api/projects` 角色鉴权

`routes/troubleshoot.py` 的 `get_projects` 加角色判断：

```python
from flask import session

@bp.route('/api/projects', methods=['GET'])
def get_projects():
    """获取项目列表（用于下拉建议）。
    安全：普通用户返回空列表，仅管理员可获取完整项目名（防止项目信息泄露）。
    """
    user = session.get('user') or {}
    role = user.get('role', '')
    engine = container.get_search_engine()

    if role != 'admin':
        # 普通用户：返回空列表，前端不展示 datalist
        return jsonify({'success': True, 'projects': []})

    return jsonify({
        'success': True,
        'projects': engine.get_projects(),
    })
```

**关键约束**：
- 不加 `@admin_required`（那会返回 403），而是登录后按角色返回空列表——保持 API 对普通用户"可用但无数据"
- 安全基线在后端，前端只是 UX 层面

### 2.2 前端：`loadProjects` 按角色填充

`templates/index.html` 的 `loadProjects()` 已读 `/api/projects`，后端返回空列表时 datalist 自然为空，前端**无需改动填充逻辑**。

需确认：datalist 为空时 `<input list="projectList">` 不会报错——经测试空 datalist 等同纯输入框，行为符合预期。

**可选增强**：普通用户的 placeholder 提示更明确（无需改代码，现有"输入项目名称，如：厦门银行"已合适）。

### 2.3 验证方案

| 角色 | 验证项 | 方式 |
|------|--------|------|
| 普通用户 | 项目名输入框无下拉 | 浏览器访问，输入字符 |
| 管理员 | 项目名输入框有下拉 | 浏览器访问，输入字符 |
| 普通用户 | `/api/projects` 返回 `[]` | curl + 登录态 |
| 管理员 | `/api/projects` 返回 120 项 | curl + 登录态 |
| 普通用户 | 搜索/AI 分析正常 | 手动输入项目名提交流程 |

---

## 3. 实施计划

### 3.1 任务分解

| 序号 | 任务 | 预计时间 | 状态 | 依赖 |
|------|------|---------|------|------|
| 1 | 后端 `/api/projects` 角色鉴权 | 0.5h | 待开始 | — |
| 2 | 前端验证（确认空 datalist 行为） | 0.5h | 待开始 | 1 |
| 3 | 浏览器验证普通/管理员差异 | 0.5h | 待开始 | 1 |
| 4 | 部署 + 验证 | 0.5h | 待开始 | 1, 2 |

---

## 4. 测试验证

### 4.1 验证项

| 验收项 | 标准 | 实测 |
|--------|------|------|
| 普通用户无下拉 | 输入框输入字符无 datalist 提示 | — |
| 管理员有下拉 | 输入框输入字符有 datalist 提示 | — |
| API 角色鉴权 | 普通用户返回空，管理员返回 120 | — |
| 搜索不受影响 | 普通用户手动输入可正常搜索 | — |

### 4.2 端到端验证

```bash
# 普通用户登录后调 /api/projects（需带 session）
# 管理员登录后调 /api/projects（需带 session）
# 浏览器访问，分别用普通用户/管理员登录看项目名输入框
```

---

## 5. 执行记录

### 5.1 执行日志

| 日期 | 任务 | 执行人 | 结果 | 备注 |
|------|------|--------|------|------|
| 2026-07-14 | 1. 后端 `/api/projects` 角色鉴权 | Claude | 完成 | session 角色判断，普通用户返回 [] |
| 2026-07-14 | 2. 前端验证 | Claude | 通过 | 空 datalist 行为等同纯输入，无需改前端代码 |
| 2026-07-14 | 3. 测试更新 | Claude | 完成 | 1→3 用例（未登录/普通/管理员），145 全绿 |
| 2026-07-14 | 4. 部署 + 验证 | Claude | 通过 | verify_deployment 全通过 |

### 5.2 问题记录

| 日期 | 问题 | 解决方案 | 状态 |
|------|------|---------|------|
| 2026-07-14 | test_projects 断言 120 项失败 | 拆为三个角色测试用例 | 已解决 |

---

## 6. 注意事项

1. **安全基线在后端**：前端 datalist 隐藏只是 UX 层面，真正防泄露的是 `/api/projects` 的角色判断。F12 改前端 DOM 无法绕过后端。
2. **不破坏管理员流程**：管理员依赖项目下拉快速选项目，保留完整能力。
3. **普通用户搜索准确度**：改为纯输入后，若项目名拼错则 project_filter 不命中（搜索会退化全局搜索，不会报错）。

---

## 7. 相关文档

- [PRD_需求文档_普通用户项目名称输入限制](PRD_需求文档_普通用户项目名称输入限制.md) — 本项目需求文档
