# DB Design & Migrations（数据库设计与迁移）｜Tasks

> 对应计划：`spec_kit/Personalized Reco/modules/db-design/plan.md`
>
> 目标：在“库为空”的前提下，落地推荐系统最小可用数据模型 + Alembic 迁移，并通过最小查询/契约验收。

---

## 0. 任务状态约定

- `[ ]`：未开始
- `[~]`：进行中
- `[x]`：已完成
- `[-]`：已取消/不做（需写明原因）

---

## 1. 环境与依赖准备

- [ ] **确认 MySQL 版本与字符集支持**
  - 验收：MySQL 版本为 8.x；库/表可用 `utf8mb4`（建议 `utf8mb4_0900_ai_ci`）。
- [x] **后端依赖补齐 Alembic**
  - 说明：`server/requirements.txt` 已包含 `alembic>=1.13`
  - 验收：在 `server/.venv` 中可成功 `import alembic`。

---

## 2. ORM 模型落地（推荐最小集合）

- [x] **创建 ORM 模型目录**
  - 目标路径：`server/app/db/models/`
  - 验收：目录存在，且可被 Python 正常 import。
- [x] **实现 `contents` 模型**
  - 字段：`content_id(PK, 自增)`、`text_en?`、`text_tc?`、`author_id?`、`template_id?`、`created_at`、`updated_at`
  - 索引：`author_id`、`template_id`
  - 验收：Alembic autogenerate 能识别表结构。
- [x] **实现 `content_profiles` 模型**
  - 字段：`content_id(PK/FK)`、`stage(enum)`、`emotion_score(NULL=general)`、`context_suitability_json(JSON)`、`need_suitability_json(JSON)`、`personalization_power(0/5/10)`、`review_confidence?`、`is_safe_pool`、`updated_at`
  - 索引：`stage`、`personalization_power`、`is_safe_pool`
  - 验收：Alembic autogenerate 能识别表结构；`content_id` 具备外键与级联删除。
- [x] **实现 `content_risk_flags` 模型（关联表）**
  - 字段：`id(PK)`、`content_id(FK)`、`flag`、`created_at`
  - 约束：`UNIQUE(content_id, flag)`
  - 索引：`flag`、`content_id`
  - 验收：Alembic autogenerate 能识别唯一约束与索引。

---

## 3. Alembic 初始化与迁移生成

- [x] **初始化 Alembic 目录**
  - 目标位置：`server/alembic/`（含 `versions/`、`env.py`）
  - 验收：在 `server/` 下可运行 `alembic -h` 且能读取配置。
- [x] **配置 Alembic 连接串来源**
  - 要求：复用现有 `DATABASE_URL`（对齐 `server/app/core/config.py`）
  - 验收：`alembic` 命令可加载 `env.py` 并读取 `DATABASE_URL`（未连 DB 验收留到第 4 章）。
- [x] **配置 `env.py` 支持 autogenerate**
  - 要求：引入 ORM `Base` 与 models（确保 metadata 完整）
  - 验收：Alembic 能识别 `target_metadata`；且已提供初始迁移版本文件。
- [ ] **生成并执行初始迁移**
  - 命令：`alembic upgrade head`
  - 验收：数据库中出现 `contents`、`content_profiles`、`content_risk_flags` 与 Alembic 版本表。

---

## 4. 数据契约验收（最小入库与查询）

- [ ] **准备一条最小文案数据（人工插入或脚本）**
  - 必须字段（对齐 plan）：`text`、`stage`、`emotion_score(可 NULL)`、`context_suitability_json(5 keys)`、`need_suitability_json(5 keys)`、`personalization_power(0/5/10)`、`risk_flags(可空)`
  - 验收：可插入成功，不违反约束。
- [ ] **验证按 `content_id` 批量查询可用**
  - 目标：能 join 组装出 `ContentProfile` 所需字段集合（含 risk_flags 列表）
  - 验收：至少验证字段：`content_id/text/stage/emotion_score/context_suitability/need_suitability/personalization_power/risk_flags`。
- [ ] **验证 Hard Filter 关键 flag 可过滤**
  - 插入：至少一条带 `block_health_medical` 的记录
  - 验收：通过 `content_risk_flags` 可在 SQL 层排除该内容（后续供推荐候选召回使用）。
- [ ] **验证安全池（L3）可用**
  - 插入：至少一条 `is_safe_pool=true`
  - 验收：可单独查询出安全池候选集（不依赖画像条件）。

---

## 5. 规则口径验收（risk_flags 严格对齐）

- [ ] **建立 risk_flags 白名单/校验策略（写入侧或读取侧）**
  - 要求：flag 命名必须以 `unsafe_for_` / `block_` / `soft_` 开头（对齐 `句子文案打分规则`）
  - 验收：插入非法前缀时被拒绝或被修正（选择其一，并写清策略）。
- [ ] **旧 flag 兼容映射验收（若存在历史数据导入）**
  - 覆盖：`block_stage_unknown`→`unsafe_for_stage_unknown` 等（详见 plan）
  - 验收：系统对外（读出/下游）不再出现旧 flag 名称。

---

## 6. 文档与交接

- [ ] **补齐本子模块 README/说明（可选，但建议）**
  - 内容：如何初始化 DB、如何跑迁移、如何插入一条最小文案数据、如何验证查询。
  - 验收：新同学按文档能在 30 分钟内跑通迁移 + 插入 + 查询。

