# 任务看板(Tasks)
> 把 MVP 拆成小步、可独立交付的任务,让 AI 一步一步开发,避免一次生成整个项目。
## 使用规则
1. 每轮只领取一个状态为 `TODO`、且依赖均已 `DONE` 的任务,取最靠前的那个。
2. 开始前把任务改成 `DOING`。
3. 完成后跑验证,把证据追加到 [`../progress.md`](../progress.md),再改成 `DONE`。
4. 同步更新 [`current-state.md`](current-state.md)。
5. 不实现 Backlog 或后续阶段功能,除非任务已明确要求。
6. 任务表只是索引;有「任务详单」的任务,实现指引和验证命令以详单为准。
## 状态图例
`TODO` 待开始 · `DOING` 进行中 · `DONE` 已完成并验收 · `BLOCKED` 受阻
---
## Phase 0 · 地基
| ID | 任务 | 依赖 | 验收要点 | 状态 |
| --- | --- | --- | --- | --- |
| T-000 | 初始化 harness 文档 | - | 根目录入口、需求、技术栈、架构、规则、任务和当前状态文档已建立 | DONE |
| T-001 | 初始化 Wagtail 项目骨架 | T-000 | Python 3.12 虚拟环境可用;Wagtail/Django 项目生成;SQLite 配置可 migrate;首页或默认 Wagtail 页面可访问;`init.ps1` / `init.sh` 替换为真实命令 | DONE |
| T-002 | 建立基础配置与环境样例 | T-001 | 存在 `requirements.txt`、`.env.example` 或等价配置说明;不包含真实密钥;`DEBUG`、`ALLOWED_HOSTS`、media/static 配置清楚 | DONE |
| T-003 | 建立最小验证基线 | T-001 | `manage.py check` 和基础测试命令可运行;验证结果写入 `progress.md` | DONE |
## Phase 1 · 内容模型
| ID | 任务 | 依赖 | 验收要点 | 状态 |
| --- | --- | --- | --- | --- |
| T-101 | 建立场景、语言、框架、数据库、功能标签模型 | T-003 | Wagtail 后台可维护这些 Snippet;迁移文件生成并通过 migrate | TODO |
| T-102 | 建立骨架项目详情模型 | T-101 | `SkeletonProjectPage` 严格按 `04-architecture.md` §3.3 表和必填/默认附注实现;多对多用 `ParentalManyToManyField`;同时建 `ProjectIndexPage`;评分字段带 0-5 校验器;总分由分项计算 | TODO |
| T-103 | 建立文章模型 | T-101 | 可维护文章列表和详情;文章可链接骨架项目 | TODO |
| T-104 | 准备首批种子内容 | T-102, T-103 | 至少有 3 个场景、5 个骨架项目、2 篇文章;候选项目、评分和评语须经人工确认,禁止模型编造(见详单) | TODO |
## Phase 2 · 前台 MVP
| ID | 任务 | 依赖 | 验收要点 | 状态 |
| --- | --- | --- | --- | --- |
| T-201 | 实现基础页面框架 | T-104 | `base.html`、导航、页脚、纯 CSS 基础样式;含 viewport meta;无超过视口的固定宽度容器 | TODO |
| T-202 | 实现首页 | T-201 | 首页展示场景入口、推荐骨架和最新文章 | TODO |
| T-203 | 实现场景页和项目列表页 | T-202 | 场景页展示对应项目;项目列表支持分页和空状态 | TODO |
| T-204 | 实现筛选与基础搜索 | T-203 | 严格按 `04-architecture.md` §3.4 参数契约实现筛选和关键词搜索 | TODO |
| T-205 | 实现骨架详情页 | T-204 | 展示需求文档要求的详情字段、评分、推荐理由和 Sponsored 标识 | TODO |
| T-206 | 实现文章列表和文章详情 | T-203 | 文章可访问,可链接项目详情 | TODO |
## Phase 3 · SEO 与上线准备
| ID | 任务 | 依赖 | 验收要点 | 状态 |
| --- | --- | --- | --- | --- |
| T-301 | 补 SEO 基础 | T-205, T-206 | 核心页面有 title、description、canonical 或等价设置;sitemap 可用 | TODO |
| T-302 | 补部署文档 | T-301 | 2 核 2G VPS 上 Gunicorn + Nginx + SQLite 的部署步骤清楚 | TODO |
| T-303 | SQLite 上线检查 | T-302 | JSON1 验证、WAL 启用、备份策略和 PostgreSQL 迁移触发条件已记录 | TODO |
| T-305 | 接入轻量访问统计与外链点击记录 | T-301 | Plausible / Umami 或等价方案接入;外部链接点击可统计;不引入重量级分析 SDK;这是里程碑 M3(SEO 验证)和 M4(Affiliate)的数据前置 | TODO |
| T-304 | MVP 完整验收 | T-303, T-305 | `02-requirements.md` 的 P0 验收全部通过,验证命令和结果写入 `progress.md` | TODO |
## 任务详单
> 本节给出实现指引、验收核对项和验证命令,弥补任务表一行放不下的细节。验证命令的输出一律追加到 [`../progress.md`](../progress.md) 作为完成证据。
### T-001 初始化 Wagtail 项目骨架
前置:`python3.12 --version` 可用。不可用则任务标 `BLOCKED` 并在 `progress.md` 记录缺口,**不要改用其他 Python 版本**。
步骤:
1. `python3.12 -m venv .venv && .venv/bin/pip install --upgrade pip`
2. `.venv/bin/pip install wagtail`(当前稳定版)
3. `.venv/bin/wagtail start skelet .`(在仓库根目录生成 `manage.py`、`skelet/` 配置包、`home/`、`search/`)
4. `.venv/bin/python manage.py startapp core` 并加入 `INSTALLED_APPS`;保留 `home` / `search`,不重命名(结构决策见 `04-architecture.md` §六)
5. 删除生成的 `Dockerfile`;`requirements.txt` 按 `.venv/bin/pip show wagtail` 的实际版本钉死 `wagtail==X.Y.Z`
6. `.venv/bin/python manage.py migrate && .venv/bin/python manage.py createsuperuser`
7. 替换 `init.sh` 顶部三个命令变量;回写 `03-tech-stack.md` §一/§三、`04-architecture.md` §六、`current-state.md`
验证(括号内为预期结果):
- `.venv/bin/python manage.py check`(System check identified no issues)
- `runserver` 后另开终端 `curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1:8000/`(200);同法访问 `/admin/login/`(200)
### T-002 基础配置与环境样例
- `skelet/settings/` 保持 base/dev/production 拆分;`SECRET_KEY`、`DEBUG`、`ALLOWED_HOSTS` 从环境变量读取,dev 环境给安全默认值。
- 新建 `.env.example`:只含占位值(如 `SECRET_KEY=replace-me`),逐项注释用途;真实 `.env` 已被 `.gitignore` 忽略。
- 验证:`grep -riE "secret|token|password" .env.example` 只出现占位值;`manage.py check` 无错误。
### T-003 最小验证基线
- 在 `home/tests.py` 写一个 smoke 测试:test client 访问 `/`,断言状态码 200。
- 验证:`.venv/bin/python manage.py test`(至少 1 个测试通过)。
- 完成后同步 `05-coding-rules.md` §7 的真实命令和 `init.sh` 的 `VERIFY_CMD`。
### T-101 分类与标签模型
- 场景不是 Snippet:建 `ScenarioIndexPage` / `ScenarioPage`(`core` app,Page 类型,本轮只建模型,不做模板)。
- Snippet 共 4 个:`Language`、`Framework`、`DatabaseOption`、`SkeletonFeature`;字段一律 `name`(Char,unique)+ `slug`(unique,作 URL 筛选参数值),注册为 Wagtail Snippet。
- 不建 `AiCodingScore` 模型(见 `04-architecture.md` §3.2)。
- 验证:`makemigrations` + `migrate` 成功;每个 Snippet 一个单元测试(创建对象、slug 重复时抛错);`manage.py test` 全部通过。
### T-102 骨架项目详情模型
- `SkeletonProjectPage`(`core` app):字段、必填/可空/默认严格按 `04-architecture.md` §3.3 表和附注实现,不增不减。
- **多对多字段(`scenarios`、`languages`、`frameworks`、`databases`、`features`)必须用 modelcluster 的 `ParentalManyToManyField`**,不能用普通 `ManyToManyField`(见 §3.1 Wagtail 实现注意)。
- 同时建 `ProjectIndexPage`(项目详情页在页面树上的父节点,见 §3.1 页面树;本轮只建模型,筛选逻辑留给 T-204)。
- 6 个评分字段带 `MinValueValidator(0)` / `MaxValueValidator(5)`;`total_score` 为 property(6 项之和,0-30)。
- 后台按 5 组分面板:基本信息 / 分类标签 / 评分 / 评测内容 / 展示控制。
- 验证单元测试至少 3 个:合法对象 `full_clean()` 通过;某评分设为 6 时 `full_clean()` 抛 `ValidationError`;`total_score` 等于 6 项之和。`manage.py test` 全部通过。
### T-103 文章模型
- `ArticleIndexPage` + `ArticlePage`(`core` app);正文用 RichTextField 或 StreamField;文章到骨架项目用可空多对多关联。
- 验证:`migrate` 成功;单元测试创建文章并关联一个项目;`manage.py test` 全部通过。
### T-104 首批种子内容(人工输入边界)
- **候选项目、评分和评语必须来自用户提供或经用户逐条确认**,来源方法见 [`../business/research-sourcing-strategy.md`](../business/research-sourcing-strategy.md);agent 不得凭记忆编造项目名、GitHub 地址或评分。
- 仓库内没有人工确认的清单时,本任务标 `BLOCKED`,在 `progress.md` 记录"等待首批项目清单",不要往下做。
- 有清单后:按 SaaS、内容站/CMS 两个场景录入 ≥3 个场景页、≥5 个项目、≥2 篇文章(后台录入或 fixture,方式记入 `progress.md`)。
- 验证:`manage.py shell -c` 分别输出场景、项目、文章的 count(≥3 / ≥5 / ≥2)。
### Phase 2 / Phase 3 关键约束与验证速查
| 任务 | 关键实现约束 | 验证 |
| --- | --- | --- |
| T-201 | `base.html` 含 ``;纯 CSS 无构建链路;无超视口固定宽度容器 | `curl /` 返回 200;各页面模板均继承 `base.html` |
| T-202 | 首页三区块全部来自数据库查询(`is_featured`、最新文章),不硬编码内容 | 测试断言 featured 项目标题出现在 `/` 响应中 |
| T-203 | 场景页只列已发布(live)项目;分页每页 20;空场景渲染 `empty_state.html` | 测试两用例:有项目场景(200 且含项目名)、空场景(200 且含空状态文案) |
| T-204 | 严格按 `04-architecture.md` §3.4 契约;筛选实现在 `ProjectIndexPage.get_context()`;搜索用 ORM `icontains` | 测试 4 用例:`language` 过滤、`min_score` 过滤、`q` 搜索、非法参数被忽略 |
| T-205 | 展示 §3.3 全部展示字段;`is_sponsored=True` 时渲染 `sponsored_badge.html` | 测试断言详情页含评分、推荐理由;赞助用例含 Sponsored 标识 |
| T-206 | 文章详情可点击进入关联项目详情页 | 测试断言文章页响应含项目详情链接 |
| T-301 | title/description 用 Wagtail 自带 `seo_title` / `search_description`;sitemap 用 `wagtail.contrib.sitemaps` | `curl /sitemap.xml` 返回 200 且含项目 URL;首页响应含 `