# v2.7 三级层次结构完整设计文档

> 日期：2026-05-17
> 版本：v1.0
> 作者：庞统
> 状态：待评审
> 变更记录：与用户 6 轮讨论后定稿

---

## 一、核心架构

### 1.1 三层结构

```
Project（项目）
  └── Card（卡片/策略/工作流）
        └── Task（原子任务）
```

| 层级 | 语义 | 例子 | 生命周期 |
|------|------|------|---------|
| **Project** | 业务领域/产品线 | sanguo_quant_live、General、Mail | 长期 |
| **Card** | 独立的工作流/策略 | 动量策略v1、v2.7开发 | 中期（天/周） |
| **Task** | 原子执行单元 | 编写回测脚本、清洗分钟线 | 短期（小时/天） |

### 1.2 隔离策略

**一个 Project 一个 DB + card_id 逻辑隔离。**

理由：
- Jira/Linear/Asana 均采用逻辑隔离，是成熟模式
- 跨 Card 查询天然支持（同一 DB）
- 备份/迁移按 Project 独立
- 单 DB <5000 Task，SQLite 性能无忧

**跨 Card 依赖不支持**——策略间应独立，数据引用用 artifacts 路径。

### 1.3 Card 状态 = Task 状态聚合

Card 不独立维护状态机，状态从内部 Task 推导（取最高水位）：

| Card 状态 | 推导规则 | 可创建 Task | Ticker 扫描 |
|-----------|---------|------------|------------|
| pending | 所有 Task 都是 pending | ✅ | ✅ |
| working | 有 Task 在 working | ✅ | ✅ |
| review | 有 Task 在 review | ✅ | ✅ |
| done | 所有 Task 都是 done | ❌ | ❌ |
| failed | 有 Task failed 且无 active Task | ❌ | ❌ |
| blocked | 有 Task blocked 且无 active Task | ❌ | ✅（检查是否解除） |
| cancelled | 用户/AI 取消 | ❌ | ❌ |
| **archived** | 用户/AI 归档 | ❌ | ❌ |
| **deleted** | 系统清理 | ❌ | ❌ |

额外两个状态（超出 Task 语义）：
- **archived**：人工/AI 归档决策，默认视图不显示，可切换查看
- **deleted**：archived 后 7-30 天物理清理

### 1.4 Stage 进度（AI 动态生成）

Card 创建时 AI 根据目标描述生成初始 Stages，执行中可动态调整：

```
Card: 动量策略v1
Stages（AI 生成，可演进）:
  [因子研究 ✅] → [策略编码 ✅] → [历史回测 🔄] → [参数优化 ⬜]
                                         ↑
                              AI 发现需要先做数据质量检查，动态插入新 Stage
```

数据模型：
- `cards.stages_json`：存当前 stages 定义
- `tasks.stage`：Task 绑定到某个 stage id

Stage 不是状态机——Task 可以在任意 stage 创建，stage 只用于分组显示进度。

---

## 二、特殊 Project

### 2.1 General（一般性任务）

- Project ID：`_general`
- 用途：无项目归属的 ad-hoc 任务
- 用户随口说的"帮我下载分钟线"→ 自动创建到 General
- 在 Dashboard 中作为一个普通 Project 显示

### 2.2 Mail（邮件系统）

- Project ID：`_mail`
- 用途：Agent 间 Mail 通信
- **独立 Tab 页面**，list 形式展示
- 显示字段：时间 | From | To | Title | 状态（已读/未读/已执行）
- 未来用户说"给司马懿发 mail"→ 在此 Project 创建 Task
- 不在主 Dashboard 的 Card 看板中显示

### 2.3 特殊 Project 列表

| Project ID | 显示位置 | 展示形式 |
|-----------|---------|---------|
| `_general` | Dashboard（普通 Project） | Card 看板 |
| `_mail` | 独立 Tab 页 | 列表 |
| 其他用户 Project | Dashboard | Card 看板 |

---

## 三、项目管理

### 3.1 项目发现

**自动发现 + 注册表补充元数据，不强制。**

- 系统启动时扫描 `~/.sanguo_projects/` 目录
- 新发现的目录自动添加到 registry（标记 `source=auto_discovered`）
- 用户可手动补充名称、描述、配置
- 已注册的项目以注册表为准

### 3.2 项目 CRUD

| 操作 | 实现 |
|------|------|
| 自动发现 | 扫描 sanguo_projects 目录 |
| 手动创建 | `POST /api/projects` |
| 修改元数据 | `PATCH /api/projects/{pid}` |
| 归档 | `PATCH /api/projects/{pid}` status→archived（级联归档所有 Card） |
| 删除 | archived 后 7-30 天物理清理 |

---

## 四、数据模型

### 4.1 Registry DB（全局）

路径：`data/registry.db`

```sql
CREATE TABLE IF NOT EXISTS projects (
    id          TEXT PRIMARY KEY,
    name        TEXT NOT NULL,
    description TEXT DEFAULT '',
    status      TEXT DEFAULT 'active',
    source      TEXT DEFAULT 'manual',     -- manual / auto_discovered
    config_json TEXT DEFAULT '{}',
    created_at  TEXT NOT NULL,
    updated_at  TEXT
);
```

### 4.2 Project DB（per-project）

路径：`data/{pid}/blackboard.db`

**新增 cards 表：**

```sql
CREATE TABLE IF NOT EXISTS cards (
    id          TEXT PRIMARY KEY,
    name        TEXT NOT NULL,
    description TEXT DEFAULT '',
    card_type   TEXT DEFAULT 'default',    -- default/strategy/data_pipeline/research
    stages_json TEXT DEFAULT '[]',         -- AI 生成的阶段定义
    labels_json TEXT DEFAULT '[]',
    created_at  TEXT NOT NULL,
    updated_at  TEXT,
    archived_at TEXT
);
CREATE INDEX IF NOT EXISTS idx_cards_id ON cards(id);
```

**所有现有表加 card_id：**

```sql
ALTER TABLE tasks ADD COLUMN card_id TEXT;
ALTER TABLE tasks ADD COLUMN stage TEXT DEFAULT NULL;
CREATE INDEX IF NOT EXISTS idx_tasks_card ON tasks(card_id);

ALTER TABLE outputs ADD COLUMN card_id TEXT;
ALTER TABLE reviews ADD COLUMN card_id TEXT;
ALTER TABLE comments ADD COLUMN card_id TEXT;
ALTER TABLE events ADD COLUMN card_id TEXT;
CREATE INDEX IF NOT EXISTS idx_events_card ON events(card_id);
ALTER TABLE task_attempts ADD COLUMN card_id TEXT;
ALTER TABLE routing_decisions ADD COLUMN card_id TEXT;
```

**DDL 变更策略：**
- 新 DB：CREATE TABLE 直接包含 card_id 和 stage
- 旧 DB：`_migrate_v27()` ALTER TABLE + 创建默认 Card + 回填

### 4.3 默认 Card

- 每个 Project 自动创建一个 `default` Card
- 迁移时所有现有数据的 card_id 设为 `default`
- 用户可以直接在 default Card 上工作（不感知 Card 层）

### 4.4 目录结构

```
data/
├── registry.db
├── _general/
│   ├── blackboard.db
│   └── artifacts/
├── _mail/
│   ├── blackboard.db
│   └── artifacts/
├── sanguo_quant_live/
│   ├── blackboard.db
│   └── artifacts/
├── sanguo_vnpy/
│   ├── blackboard.db
│   └── artifacts/
└── sanguo_moziplus_v2/
    ├── blackboard.db
    └── artifacts/
```

---

## 五、API 路由

### 5.1 Project 级

```
GET    /api/projects                    → 列出所有项目（含自动发现的）
POST   /api/projects                    → 手动创建项目
GET    /api/projects/{pid}              → 项目详情 + 聚合统计
PATCH  /api/projects/{pid}              → 更新项目元数据
DELETE /api/projects/{pid}              → 删除项目（archived 后）
```

### 5.2 Card 级

```
GET    /api/projects/{pid}/cards                  → 列出所有 Card
POST   /api/projects/{pid}/cards                  → 创建 Card
GET    /api/projects/{pid}/cards/{cid}            → Card 详情 + Stage 进度
PATCH  /api/projects/{pid}/cards/{cid}            → 更新 Card（改名/归档/调整 stages）
DELETE /api/projects/{pid}/cards/{cid}            → 删除 Card
POST   /api/projects/{pid}/cards/{cid}/fork       → Fork Card（策略迭代）
```

### 5.3 Task 级

```
GET    /api/projects/{pid}/cards/{cid}/tasks              → Card 下所有 Task
POST   /api/projects/{pid}/cards/{cid}/tasks              → 创建 Task
GET    /api/projects/{pid}/cards/{cid}/tasks/{tid}        → Task 详情
POST   /api/projects/{pid}/cards/{cid}/tasks/{tid}/status → 更新状态
POST   /api/projects/{pid}/cards/{cid}/tasks/{tid}/outputs → 添加产出
POST   /api/projects/{pid}/cards/{cid}/tasks/{tid}/reviews → 添加审查
POST   /api/projects/{pid}/cards/{cid}/tasks/{tid}/comments → 添加评论
```

### 5.4 便利路由

```
GET    /api/projects/{pid}/tasks          → Project 下所有 active cards 的 tasks（合并）
GET    /api/projects/{pid}/events         → Project 下所有事件
```

### 5.5 Mail Tab

```
GET    /api/mail                          → Mail 列表（from/to/title/status/time）
GET    /api/mail/{id}                     → Mail 详情
PATCH  /api/mail/{id}                     → 标记已读/已执行
```

### 5.6 向后兼容

- 旧路由 `/api/projects/{pid}/tasks` 保留，内部查所有 active cards
- 不传 card_id 时自动使用 `default` Card
- 前端渐进迁移

---

## 六、Ticker 变更

### 6.1 扫描逻辑

```python
for project in registry.list_projects(status='active'):
    db_path = data_root / project.id / "blackboard.db"
    active_cards = card_ops.list_cards(db_path, status='active')
    for card in active_cards:
        tick_card(db_path, card.id)
```

### 6.2 性能

- 单 DB 内按 card_id 查询，索引命中，微秒级
- active cards 过多时加 LIMIT 分批

---

## 七、上下文隔离

### 7.1 Agent 视角

Agent 执行 Task 时，prompt 只注入当前 Card 的数据：

```python
context = queries.build_agent_context(db_path, task_id, card_id=task.card_id)
```

### 7.2 写入自动带 card_id

Agent 写 output、改 status 时，API 自动从 Task 关联获取 card_id，Agent 不感知。

### 7.3 跨 Card 引用

Fork Card 时可注入源 Card 的摘要。写入仍在当前 Card。

---

## 八、Stage 进度

### 8.1 AI 动态生成

1. Card 创建时，AI 根据目标描述生成初始 stages → 写入 `stages_json`
2. 执行中 Agent 可提议修改 stages（新增/删除/重排）→ 更新 `stages_json`
3. 用户可手动调整
4. Task 绑定 stage，前端按 stage 分组显示

### 8.2 进度计算

```python
def card_progress(db_path, card_id, stages):
    for stage in stages:
        total = count(tasks WHERE card_id=? AND stage=?)
        done = count(tasks WHERE card_id=? AND stage=? AND status='done')
        active = count(tasks WHERE card_id=? AND stage=? AND status IN ('working','review'))
```

### 8.3 默认 Stage

不指定 stage 的 Task 归入"未分类"组。

---

## 九、联动功能

| 阶段 | 操作 | 粒度 | 谁触发 |
|------|------|------|--------|
| **创建** | 创建 Project | Project | 用户/AI |
| | 创建 Card | Card | 用户/AI |
| | 创建 Task | Task | 用户/AI/Ticker |
| **发现** | 扫描 sanguo_projects 目录 | Project | 系统 |
| | 手动补充元数据 | Project | 用户 |
| **规划** | AI 生成 Stages | Card | AI |
| | AI 动态调整 Stages | Card | AI 提议 |
| | 用户调整 Stages | Card | 用户 |
| **执行** | Agent 执行 Task | Task | Ticker |
| | Review 流转 | Task | Ticker/Agent |
| | 重试/暂停/取消 Task | Task | Ticker/用户/AI |
| **进度** | Stage 进度条 | Card | 自动推导 |
| | Card 状态聚合 | Card | 自动推导 |
| | Project 整体进度 | Project | 自动推导 |
| **查询** | 单 Card 查询 | Card | 用户/AI |
| | 单 Project 查询 | Project | 用户/AI |
| | 全局任务列表 | 跨 Project | 用户/AI |
| **暂停** | 暂停 Card | Card | 用户/AI |
| | 暂停 Project | Project | 用户 |
| **取消** | 取消 Card | Card | 用户/AI |
| | 取消 Project | Project | 用户 |
| **归档** | 归档 Card | Card | 用户/AI |
| | 归档 Project（级联 Card） | Project | 用户 |
| | 查看归档数据 | Card/Project | 用户 |
| **删除** | 物理清理（归档 7-30 天后） | Card/Project | 系统 |
| | 立即删除 | Card/Project | 用户 |
| **恢复** | 归档 → active | Card/Project | 用户 |
| | 已删除 → 恢复（7天内） | Card/Project | 用户 |
| **Fork** | 从已有 Card 创建新 Card | Card | 用户/AI |
| **移动** | Task 跨 Card 移动 | Task | 用户 |
| | Card 跨 Project 移动 | Card | 用户 |

---

## 十、前端设计

### 10.1 页面结构

```
┌─────────────────────────────────────────────────┐
│  [Dashboard]  [Mail]  [Settings]                │  ← 顶部 Tab
├─────────────────────────────────────────────────┤
│  左侧：Project 导航                             │
│  ├── General                                     │
│  ├── sanguo_quant_live                          │
│  ├── sanguo_vnpy                                │
│  └── sanguo_moziplus_v2                         │
├─────────────────────────────────────────────────┤
│  右侧：Card 看板 / Mail 列表                     │
│  ┌──────────┐ ┌──────────┐ ┌──────────┐        │
│  │ Card 1   │ │ Card 2   │ │ Card 3   │        │
│  │ ■■■□ 75% │ │ ■□□□ 20% │ │ □□□□  0% │        │
│  └──────────┘ └──────────┘ └──────────┘        │
│                                                  │
│  [Stage 进度条]  [Task 列表]  [事件流]           │
└─────────────────────────────────────────────────┘
```

### 10.2 Mail Tab

| 时间 | From | To | Title | 状态 |
|------|------|----|-------|------|
| 22:30 | simayi | pangtong | 路由方案评审通过 | ✅ 已读 |
| 22:15 | pangtong | simayi | 代码评审请求 | 📬 未读 |
| 21:40 | zhangfei | pangtong | e2e-rt-002 完成 | ✅ 已执行 |

### 10.3 Card 详情

- 顶部：Stage 进度条
- 中部：Task 列表（按 stage 分组）
- 底部：事件流 / 评论

---

## 十一、路由方案兼容性

完全兼容：
- routing_decisions 表加 card_id
- agent_profiles 和 routing 配置在 Project 级
- AgentRouter per-Project，Card 只是查询过滤条件

---

## 十二、数据迁移

```python
def migrate_v27(db_path):
    # 1. 创建 cards 表
    # 2. 所有表加 card_id + stage
    # 3. 创建 default Card
    # 4. 回填 card_id = 'default'
    # 5. 创建索引

def migrate_registry(data_root):
    # 读 _registry.yaml → 写 registry.db
    # 扫描 sanguo_projects 目录 → 补充 auto_discovered
```

---

## 十三、实施计划

### v2.7.0 范围

| 序号 | 任务 | 预计 |
|------|------|------|
| 1 | registry.db + ProjectRegistry + 自动发现 | 0.5 天 |
| 2 | cards 表 + 所有表加 card_id + stage + 迁移 | 0.5 天 |
| 3 | CardOps + Blackboard/Queries 加 card_id | 1 天 |
| 4 | API 路由（Card CRUD + Task 嵌套 + Mail） | 1 天 |
| 5 | Ticker 适配（per-card 扫描） | 0.5 天 |
| 6 | 前端 Dashboard 重构（Card 看板 + Stage 进度） | 1.5 天 |
| 7 | 前端 Mail Tab | 0.5 天 |
| 8 | 端到端测试 + 迁移验证 | 0.5 天 |
| **合计** | | **6 天** |

### 不在 v2.7.0 范围

- Card 模板系统（Phase 2）
- 全局搜索/FTS（Phase 2）
- 跨 Project 统计报表（Phase 2）
- 冷存储迁移脚本（按需）

### 前置条件

- ✅ v2.6.1 路由方案已落地并 E2E 验证
