diff --git a/docs/04-architecture.md b/docs/04-architecture.md
index ed953ce..46b8c46 100644
--- a/docs/04-architecture.md
+++ b/docs/04-architecture.md
@@ -61,12 +61,32 @@ SQLite db.sqlite3
| `HomePage` | Page | 首页,展示场景入口、推荐骨架、最新文章。 |
| `ScenarioIndexPage` | Page | 场景总览页。 |
| `ScenarioPage` | Page | 单个场景页,如 SaaS、管理后台、API 服务。 |
+| `ProjectIndexPage` | Page | 项目列表页(`/projects/`),承载筛选与分页。 |
| `SkeletonProjectPage` | Page | 骨架项目详情页。 |
| `ArticleIndexPage` | Page | 文章列表。 |
| `ArticlePage` | Page | 评测、对比、避坑指南等内容文章。 |
模型归属:`HomePage` 在 `home` app(`wagtail start` 生成,沿用不改名);其余 Page、Snippet 和文章模型集中在 `core` app(见本文第六节)。
+**页面树结构(唯一权威)**:
+
+```text
+HomePage (/)
+├── ScenarioIndexPage (/scenarios/)
+│ └── ScenarioPage (/scenarios/{slug}/)
+├── ProjectIndexPage (/projects/)
+│ └── SkeletonProjectPage (/projects/{slug}/)
+└── ArticleIndexPage (/articles/)
+ └── ArticlePage (/articles/{slug}/)
+```
+
+- 项目详情页统一挂在 `ProjectIndexPage` 下,**不挂在场景页下**:一个项目属于多个场景(多对多),而页面树上只能有一个父节点。
+- `ScenarioPage` 没有子项目页;它通过查询 `SkeletonProjectPage.objects.live().filter(scenarios=...)` 渲染本场景的项目列表。
+- 列表筛选与分页在 `ProjectIndexPage.get_context()` 中做服务端查询实现(参数契约见 3.4),**不另建独立 Django view**。
+- `/languages/{slug}/`、`/frameworks/{slug}/` MVP 由筛选参数替代,不建 Page(见 `routes.md`)。
+
+**Wagtail 实现注意**:Page 模型上的多对多字段(`scenarios`、`languages`、`frameworks`、`databases`、`features`)必须用 modelcluster 的 `ParentalManyToManyField`,不能用 Django 普通 `ManyToManyField`,否则后台编辑、草稿和预览会出错。
+
### 3.2 Snippet / 辅助模型
| 模型 | 说明 |
diff --git a/docs/06-tasks.md b/docs/06-tasks.md
index 5bc5a7b..8e7a7bb 100644
--- a/docs/06-tasks.md
+++ b/docs/06-tasks.md
@@ -31,7 +31,7 @@
| ID | 任务 | 依赖 | 验收要点 | 状态 |
| --- | --- | --- | --- | --- |
| T-101 | 建立场景、语言、框架、数据库、功能标签模型 | T-003 | Wagtail 后台可维护这些 Snippet;迁移文件生成并通过 migrate | TODO |
-| T-102 | 建立骨架项目详情模型 | T-101 | `SkeletonProjectPage` 严格按 `04-architecture.md` §3.3 表和必填/默认附注实现;评分字段带 0-5 校验器;总分由分项计算 | 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 |
@@ -101,6 +101,8 @@
### 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` 全部通过。
@@ -124,7 +126,7 @@
| 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 契约;搜索用 ORM `icontains` | 测试 4 用例:`language` 过滤、`min_score` 过滤、`q` 搜索、非法参数被忽略 |
+| 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;首页响应含 `