# Phase 2 前台 MVP 评审 评审日期:2026-07-06 评审角色:全栈开发工程师 评审对象:DeepSeek 完成的 Phase 2(T-201 至 T-206) ## 结论 Phase 2 **暂不达标**。 基础页面、首页、项目详情、文章详情等主要页面已经可访问,自动化测试也通过;但筛选搜索的组合参数存在 500 错误,且场景页没有实现任务详单要求的分页。因此不能把 Phase 2 视为完整验收通过。 ## 阻断问题 ### P0:项目列表 `min_score + q` 组合筛选会 500 - 影响任务:T-204 - 位置:`core/models.py:151` 至 `core/models.py:162` - 现象:`min_score` 合法时,代码把 `projects` 从 QuerySet 转成 list;后续如果同时存在 `q`,继续调用 `projects.filter(...)`,触发 `AttributeError: 'list' object has no attribute 'filter'`。 - 复现: ```bash .venv/bin/python3.12.exe manage.py shell -c "from django.test import Client; c=Client(raise_request_exception=False); print(c.get('/projects/?min_score=18&q=Django').status_code)" ``` 实际结果:`500` 任务契约要求 `language` / `framework` / `database` / `min_score` / `q` / `page` 多参数同时出现时按 AND 组合,见 `docs/04-architecture.md:157` 至 `docs/04-architecture.md:161`。当前实现只覆盖了单项筛选测试,没有覆盖组合筛选,见 `core/tests.py:119` 至 `core/tests.py:136`。 建议修复方向: - 保持筛选链路的数据类型一致。 - 可以先用 ORM 对 `q`、language、framework、database 过滤,再对 `min_score` 做 Python 层过滤;也可以用 annotation 计算总分后在 ORM 层过滤。 - 增加组合筛选测试,例如 `/projects/?language=python&framework=django&min_score=18&q=Django`。 ### P1:场景页未实现分页 - 影响任务:T-203 - 位置:`core/models.py:32` 至 `core/models.py:40`,`core/templates/core/scenario_page.html:7` 至 `core/templates/core/scenario_page.html:27` - 现象:场景页直接把全部匹配项目放进 `context["projects"]`,模板也没有分页控件。 - 任务详单要求:场景页只列 live 项目,分页每页 20,空场景渲染空状态。 当前只满足 live 项目和空状态;分页缺失。已有测试只验证有项目和空状态,未验证超过 20 条时分页行为,见 `core/tests.py:40` 至 `core/tests.py:75`。 建议修复方向: - 在 `ScenarioPage.get_context()` 中使用 `Paginator(projects, 20)`。 - 支持非法 `page` 回退到第一页,行为和项目列表页一致。 - 在 `scenario_page.html` 复用项目列表页的分页 UI。 - 增加 21 个项目的场景页分页测试。 ## 非阻断问题 ### P2:`docs/current-state.md` 测试数量已过期 - 位置:`docs/current-state.md:19` - 现象:文档写的是 `home/tests.py` 5 个、`core/tests.py` 17 个;实际 `manage.py test` 输出为 31 个测试。 - 影响:不影响运行,但会误导后续 agent 判断当前状态。 建议修复:更新当前快照里的测试数量。 ### P2:文章列表实现偏薄,但可接受 - 影响任务:T-206 - 位置:`core/templates/core/article_index_page.html:7` 至 `core/templates/core/article_index_page.html:13` - 现状:文章列表通过 `page.get_children.live` 直接渲染标题链接,没有自定义 `get_context()`,也没有分页。 - 评估:T-206 只要求文章可访问、文章详情可链接项目详情;当前能满足最低验收。后续内容量增长时建议补排序、摘要和分页。 ## 逐任务验收 | 任务 | 结论 | 说明 | | --- | --- | --- | | T-201 基础页面框架 | 达标 | `base.html` 有 viewport meta,导航、页脚、基础 CSS 已实现,容器使用 `max-width` 和响应式宽度。 | | T-202 首页 | 达标 | 首页展示场景入口、推荐骨架、最新文章,内容来自数据库上下文。 | | T-203 场景页和项目列表页 | 未达标 | 项目列表页有分页和空状态;场景页有项目和空状态,但缺少每页 20 的分页。 | | T-204 筛选与基础搜索 | 未达标 | 单项筛选可用,但 `min_score` 与 `q` 组合请求返回 500,不符合 AND 组合契约。 | | T-205 骨架详情页 | 达标 | 展示详情字段、评分、推荐理由,`is_sponsored=True` 时渲染 Sponsored 标识。 | | T-206 文章列表和详情 | 达标 | `/articles/` 和文章详情可访问,文章详情可链接关联项目;实现较薄但满足最低验收。 | ## 验证记录 已执行: ```bash .venv/bin/python3.12.exe manage.py check .venv/bin/python3.12.exe manage.py makemigrations --check --dry-run .venv/bin/python3.12.exe manage.py test .venv/bin/python3.12.exe manage.py shell -c "from core.models import ScenarioPage,SkeletonProjectPage,ArticlePage; print(ScenarioPage.objects.live().count(), SkeletonProjectPage.objects.live().count(), ArticlePage.objects.live().count())" .venv/bin/python3.12.exe manage.py shell -c "from django.test import Client; c=Client(raise_request_exception=False); paths=['/','/projects/','/articles/','/projects/?language=python','/projects/?min_score=18','/projects/?q=Django','/projects/?min_score=18&q=Django']; [print(p, c.get(p).status_code) for p in paths]" ``` 结果摘要: - `manage.py check`:0 error,9 个 treebeard/Wagtail 兼容 warning。 - `makemigrations --check --dry-run`:No changes detected。 - `manage.py test`:31 tests passed。 - seed 数据:3 个 live 场景、5 个 live 项目、2 篇 live 文章。 - URL 补测: - `/`:200 - `/projects/`:200 - `/articles/`:200 - `/projects/?language=python`:200 - `/projects/?min_score=18`:200 - `/projects/?q=Django`:200 - `/projects/?min_score=18&q=Django`:500 ## 修复验收建议 修复后至少补充并通过以下测试: 1. 项目列表组合筛选:`language + framework + database + min_score + q` 同时存在时返回 200,并只展示满足全部条件的项目。 2. 项目列表组合筛选无结果时返回 200,并展示空状态。 3. 场景页 21 个 live 项目时第一页展示 20 个,第二页展示剩余项目。 4. 场景页非法 `page` 参数返回第一页,不报错。 修复完成后重新运行: ```bash .venv/bin/python3.12.exe manage.py check .venv/bin/python3.12.exe manage.py makemigrations --check --dry-run .venv/bin/python3.12.exe manage.py test ``` ## 2026-07-06 修复复查 复查对象:提交 `714d218 Phase 2 评审修复: P0 min_score+&q=500 (ORM→list 顺序) + P1 场景分页(20/page) + P2 文档同步 + 36 tests` 复查结论:原 Phase 2 阻断问题 **已达标**,Phase 2 当前可视为通过复查。 ### 复查结果 | 原问题 | 状态 | 证据 | | --- | --- | --- | | P0:项目列表 `min_score + q` 组合筛选会 500 | 已达标 | `ProjectIndexPage.get_context()` 先执行 `q` ORM 过滤,再做 `min_score` Python 过滤;`/projects/?min_score=18&q=Django` 复测返回 200。 | | P1:场景页未实现分页 | 已达标 | `ScenarioPage.get_context()` 已使用 `Paginator(projects, 20)`;`scenario_page.html` 已渲染分页控件;新增 21 条项目分页测试。 | | P2:`docs/current-state.md` 测试数量已过期 | 已达标 | 当前快照已更新为 31 个测试基线;修复后实际测试为 36 个。 | | P2:文章列表实现偏薄 | 可接受 | 该项原本非阻断,当前未要求扩展;仍满足 T-206 最低验收。 | ### 代码核对 - `core/models.py:32` 至 `core/models.py:46`:场景页项目列表已分页,非法页码和越界页码回退第一页。 - `core/models.py:151` 至 `core/models.py:168`:项目列表筛选顺序已调整,`q` 不再在 list 上调用 `.filter()`。 - `core/templates/core/scenario_page.html:26` 至 `core/templates/core/scenario_page.html:36`:场景页已展示分页导航。 - `core/tests.py:78` 至 `core/tests.py:116`:新增场景页分页测试。 - `core/tests.py:178` 至 `core/tests.py:190`:新增组合筛选与空状态测试。 ### 复查验证命令 已执行: ```bash .venv/bin/python3.12.exe manage.py check .venv/bin/python3.12.exe manage.py makemigrations --check --dry-run .venv/bin/python3.12.exe manage.py test .venv/bin/python3.12.exe manage.py shell -c "from django.test import Client; from core.models import ScenarioPage,SkeletonProjectPage,ArticlePage; c=Client(raise_request_exception=False); scenario=ScenarioPage.objects.live().first(); paths=['/projects/?min_score=18&q=Django','/projects/?language=python&framework=django&min_score=18&q=Django','/projects/?language=go&framework=django&min_score=18', scenario.url, scenario.url+'?page=2', scenario.url+'?page=abc']; print('counts', ScenarioPage.objects.live().count(), SkeletonProjectPage.objects.live().count(), ArticlePage.objects.live().count()); [print(p, c.get(p).status_code) for p in paths]" ``` 结果摘要: - `manage.py check`:0 error,9 个 treebeard/Wagtail 兼容 warning。 - `makemigrations --check --dry-run`:No changes detected。 - `manage.py test`:36 tests passed。 - seed 数据:3 个 live 场景、5 个 live 项目、2 篇 live 文章。 - URL 复测: - `/projects/?min_score=18&q=Django`:200 - `/projects/?language=python&framework=django&min_score=18&q=Django`:200 - `/projects/?language=go&framework=django&min_score=18`:200 - `/scenarios/modern-desktop-app-templates/`:200 - `/scenarios/modern-desktop-app-templates/?page=2`:200 - `/scenarios/modern-desktop-app-templates/?page=abc`:200