log-center/docs/project-management-repair-plan.md
zyc 625e53dc44
All checks were successful
Build and Deploy Log Center / build-and-deploy (push) Successful in 2m16s
feat(project-mgmt): 项目管理 + 失败原因追踪 + 前端展示
- 新增 Project 模型(repo_url, local_path, name, description)
- 项目 CRUD API(GET/PUT /api/v1/projects)
- 日志上报自动 upsert Project 记录
- ErrorLog 增加 failure_reason 字段
- update_task_status / create_repair_report 写入失败原因
- Repair Agent 优先从 API 获取项目配置,回退 .env
- 新增 Web 端「项目管理」页面(表格 + 行内编辑)
- BugList/BugDetail/RepairList 展示失败原因
- 更新接入指南文档

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-24 11:18:27 +08:00

318 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Log Center 改进方案:项目管理 + 修复失败追踪
## 背景
Log Center 当前存在三个核心问题:
1. **Repair Agent 无法识别项目仓库和本地路径** — 仓库地址(`repo_url`)和本地项目路径(`local_path`)都硬编码在 `repair_agent/.env`,需手动配置,且当前全部为空。应在接入日志收集时自动注册项目信息,并可在 Web 端统一管理。
2. **修复失败原因未上报**`ErrorLog` 表没有 `failure_reason` 字段;`update_task_status` API 接收了 `message` 参数但直接丢弃(`main.py:113``upload_report` 失败时原因静默丢失。
3. **前端未展示失败原因** — BugList / BugDetail 页面无法看到修复失败的具体原因,用户必须逐一查看 RepairTask 记录才能找到。
---
## 第一部分:项目管理(仓库地址 + 本地路径 + Web 管理页)
### 1.1 新增 `Project` 数据模型
**文件**: `app/models.py`
```python
class Project(SQLModel, table=True):
id: Optional[int] = Field(default=None, primary_key=True)
project_id: str = Field(unique=True, index=True) # "rtc_backend"
name: Optional[str] = Field(default=None) # 显示名称
repo_url: Optional[str] = Field(default=None) # GitHub/Gitea 仓库地址
local_path: Optional[str] = Field(default=None) # 本地项目路径Agent 修复时使用)
description: Optional[str] = Field(default=None) # 项目描述
created_at: datetime = Field(default_factory=datetime.utcnow)
updated_at: datetime = Field(default_factory=datetime.utcnow)
```
新增 `ProjectUpdate` schema 用于编辑:
```python
class ProjectUpdate(SQLModel):
name: Optional[str] = None
repo_url: Optional[str] = None
local_path: Optional[str] = None
description: Optional[str] = None
```
### 1.2 日志上报自动注册项目
**文件**: `app/models.py``ErrorLogCreate` 增加字段
```python
class ErrorLogCreate(SQLModel):
# ... 现有字段 ...
repo_url: Optional[str] = None # 可选:上报时附带仓库地址
```
**文件**: `app/main.py``report_log()` 增加 upsert 逻辑
收到日志上报时:
1. 根据 `project_id` 查找 Project 记录
2. 不存在 → 自动创建(`project_id` + `repo_url`
3. 已存在且 `repo_url` 不为空 → 更新 `repo_url`
> 向后兼容:不传 `repo_url` 时仍正常创建 Project 记录(`repo_url` 为空),后续可在 Web 端手动补充。
### 1.3 项目管理 API
**文件**: `app/main.py`
| 端点 | 方法 | 用途 |
|------|------|------|
| `GET /api/v1/projects` | GET | 项目列表(改造现有端点,从 Project 表查询,返回完整信息) |
| `GET /api/v1/projects/{project_id}` | GET | 获取单个项目详情(含 repo_url、local_path |
| `PUT /api/v1/projects/{project_id}` | PUT | 编辑项目信息repo_url、local_path、name、description |
#### GET /api/v1/projects 响应示例
```json
{
"projects": [
{
"id": 1,
"project_id": "rtc_backend",
"name": "RTC 后端",
"repo_url": "https://gitea.example.com/team/rtc_backend.git",
"local_path": "/Users/maidong/Desktop/zyc/qy_gitlab/rtc_backend",
"description": "Django 后端服务",
"created_at": "2026-01-15T08:00:00",
"updated_at": "2026-02-20T10:30:00"
}
]
}
```
#### PUT /api/v1/projects/{project_id} 请求示例
```json
{
"name": "RTC 后端",
"repo_url": "https://gitea.example.com/team/rtc_backend.git",
"local_path": "/Users/maidong/Desktop/zyc/qy_gitlab/rtc_backend",
"description": "Django 后端服务"
}
```
### 1.4 Repair Agent 适配
#### task_manager.py — 新增 `get_project_info()`
```python
def get_project_info(self, project_id: str) -> Optional[dict]:
"""从 Log Center API 获取项目配置repo_url + local_path"""
response = self.client.get(f"{self.base_url}/api/v1/projects/{project_id}")
return response.json() # { repo_url, local_path, ... }
```
#### core.py — 修改 `fix_project()` 和 `fix_single_bug()`
优先级链:
- **local_path**API 返回值 → `settings.get_project_path()` (.env) → 报错退出
- **repo_url**API 返回值 → `settings.get_github_repo()` (.env) → 跳过 Git 操作
```python
# 获取项目配置API 优先)
project_info = self.task_manager.get_project_info(project_id)
project_path = (project_info and project_info.get("local_path")) or settings.get_project_path(project_id)
github_repo = (project_info and project_info.get("repo_url")) or settings.get_github_repo(project_id)
```
### 1.5 Web 端项目管理页面
**新增文件**: `web/src/pages/ProjectList.tsx`
功能:
- 表格展示所有项目project_id、名称、仓库地址、本地路径、描述、更新时间
- 行内编辑:点击「编辑」按钮进入编辑模式,可修改所有可编辑字段
- 状态指示:`repo_url` / `local_path` 为空时标红显示「未配置」
- 移动端适配:卡片式布局
**修改文件**: `web/src/App.tsx`
- 侧边栏新增「项目管理」入口(使用 `FolderGit2` 图标)
- 路由新增 `/projects``ProjectList`
**修改文件**: `web/src/api.ts`
```typescript
export interface Project {
id: number;
project_id: string;
name: string | null;
repo_url: string | null;
local_path: string | null;
description: string | null;
created_at: string;
updated_at: string;
}
export const getProjectList = () =>
api.get<{ projects: Project[] }>('/api/v1/projects');
export const getProjectDetail = (projectId: string) =>
api.get<Project>(`/api/v1/projects/${projectId}`);
export const updateProject = (projectId: string, data: Partial<Project>) =>
api.put(`/api/v1/projects/${projectId}`, data);
```
### 1.6 数据库变更
```sql
-- 新建 Project 表
CREATE TABLE project (
id SERIAL PRIMARY KEY,
project_id VARCHAR UNIQUE NOT NULL,
name VARCHAR,
repo_url VARCHAR,
local_path VARCHAR,
description VARCHAR,
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
CREATE UNIQUE INDEX ix_project_project_id ON project (project_id);
```
---
## 第二部分:修复失败原因录入数据库
### 2.1 ErrorLog 增加 `failure_reason` 字段
**文件**: `app/models.py`
```python
class ErrorLog(SQLModel, table=True):
# ... 现有字段 ...
failure_reason: Optional[str] = Field(default=None, sa_column=Column(Text, nullable=True))
```
### 2.2 `update_task_status` API 存储 message
**文件**: `app/main.py``update_task_status()`
当前代码(第 113 行):
```python
task.status = status_update.status
# We could log the message to a history table if needed ← message 被丢弃了
```
修改为:
```python
task.status = status_update.status
if status_update.message and status_update.status == LogStatus.FIX_FAILED:
task.failure_reason = status_update.message
```
### 2.3 `create_repair_report` API 同步更新 ErrorLog
**文件**: `app/main.py``create_repair_report()`
当前仅在 `FIXED` / `FIX_FAILED` 时更新 ErrorLog 的 status。增加逻辑
```python
if error_log:
error_log.status = report.status
if report.failure_reason and report.status == LogStatus.FIX_FAILED:
error_log.failure_reason = report.failure_reason
session.add(error_log)
```
### 2.4 数据库变更
```sql
ALTER TABLE errorlog ADD COLUMN failure_reason TEXT;
```
---
## 第三部分:前端展示失败原因
### 3.1 TypeScript 类型更新
**文件**: `web/src/api.ts`
```typescript
export interface ErrorLog {
// ... 现有字段 ...
failure_reason: string | null;
}
```
### 3.2 BugList 页面
**文件**: `web/src/pages/BugList.tsx`
当 bug 状态为 `FIX_FAILED` 时,在状态列旁或下方显示 `failure_reason` 摘要(超长截断)。
### 3.3 BugDetail 页面
**文件**: `web/src/pages/BugDetail.tsx`
当状态为 `FIX_FAILED``failure_reason` 不为空时,增加醒目的失败原因卡片:
```tsx
{bug.failure_reason && (
<div className="card" style={{ borderLeft: '3px solid var(--error)' }}>
<h2><AlertTriangle size={16} /> 修复失败原因</h2>
<pre className="code-block error">{bug.failure_reason}</pre>
</div>
)}
```
### 3.4 RepairList 页面
**文件**: `web/src/pages/RepairList.tsx`
表格新增「失败原因」列,显示截断文本(`text-overflow: ellipsis`)。
---
## 文件变更清单
### 后端
| 文件 | 操作 | 说明 |
|------|------|------|
| `app/models.py` | 修改 | 新增 Project + ProjectUpdateErrorLog 增加 failure_reason |
| `app/main.py` | 修改 | 项目 CRUD API修改 report_log / update_task_status / create_repair_report |
| `app/database.py` | 修改 | 追加迁移 SQLProject 表 + failure_reason 列) |
| `repair_agent/agent/task_manager.py` | 修改 | 新增 get_project_info() |
| `repair_agent/agent/core.py` | 修改 | fix_project / fix_single_bug 优先使用 API 配置 |
### 前端
| 文件 | 操作 | 说明 |
|------|------|------|
| `web/src/api.ts` | 修改 | Project 类型 + API 函数ErrorLog 增加 failure_reason |
| `web/src/App.tsx` | 修改 | 路由 + 侧边栏增加「项目管理」 |
| `web/src/pages/ProjectList.tsx` | **新增** | 项目列表 + 行内编辑 |
| `web/src/pages/BugList.tsx` | 修改 | 展示 failure_reason |
| `web/src/pages/BugDetail.tsx` | 修改 | 突出展示 failure_reason |
| `web/src/pages/RepairList.tsx` | 修改 | 增加失败原因列 |
---
## 实施顺序
1. **后端模型** — 新增 Project 模型 + ErrorLog 增加 failure_reason + 数据库迁移
2. **后端 API** — 项目 CRUD + 修改 report_log / update_task_status / create_repair_report
3. **Repair Agent** — task_manager 获取项目配置 + core.py 优先使用 API 配置
4. **前端 API 层** — api.ts 类型和函数更新
5. **前端页面** — ProjectList 新页面 + BugList / BugDetail / RepairList 展示 failure_reason
6. **路由 / 侧边栏** — App.tsx 接入项目管理入口
---
## 验证方式
1. 调用 `POST /api/v1/logs/report``repo_url` → 检查 Project 表自动创建
2. Web 端「项目管理」页 → 编辑 `repo_url` / `local_path` → 验证保存成功
3. Repair Agent `status` 命令 → 验证读取到 API 配置的 `repo_url` + `local_path`
4. 触发一次修复失败 → 检查 `ErrorLog.failure_reason` 已写入
5. Web 端 BugList / BugDetail / RepairList → 确认失败原因正确展示