40 KiB
40 KiB
2-TASK · 中国机车图鉴平台 开发任务清单
版本:v1.0 来源:基于
1-prd.md细化 用途:落实与跟进开发计划(开发 / 单元测试 / e2e 测试)
进度日志
- 2025 · 第 1 批:完成 Phase 1A 数据底座(T-1.1 / T-1.2)。
- ETL 导入 12 张 CSV → SQLite + JSON + 报告:Model 540 / Unit 307,跳过 10(空行),0 待复核。
- 31 个单元/集成测试全部通过(含全量导入幂等性)。
- 代码位于
app/etl、app/tests,产物位于app/data,说明见app/README.md。 - 取舍:开发期用 SQLite(schema 设计为可移植到 PostgreSQL);Meilisearch/Redis/对象存储等基础设施待 Phase 1B/接入时引入。
- 2025 · 第 2 批:完成 Phase 1B 后端 API(T-1.3 / T-1.4),技术栈 NestJS + TypeScript(方案 B)。
- 接口:
/api/health、/api/categories、/api/models(列表/筛选/排序/分页)、/api/models/:id(详情)、/api/units、/api/search。 - 参数化查询防注入;全局 ValidationPipe 校验非法参数(返回 400)。
- 测试:14 个单元测试 + 9 个 e2e(supertest)全部通过;build 通过;真实库(540/307)联调通过。
- 代码位于
apps/api(NestJS 标准结构),读取app/data/machines.db。 - 取舍:搜索先用 SQLite LIKE+排序实现(规模足够),Meilisearch 延后。
- 接口:
- 2025 · 第 3 批:完成 Phase 1C 前端(T-1.5 / T-1.6 / T-1.7),技术栈 Vite + React + TS(方案 B,独立前端
apps/web)。- 页面:列表页(筛选/排序/分页 + 列表/时间轴/图鉴 三视图切换)、详情页(参数表 + raw_json 保真表)、全局搜索框(防抖下拉)。
- 时间轴:分类泳道 + 年代横轴刻度 + 节点跳转;图鉴:卡牌墙 + 已收集/未收集占位。
- 测试:23 个单元测试(Vitest + Testing Library)全部通过;
npm run build(tsc + vite)通过。 - 全栈联调:Vite 代理
/api→NestJS,真实库 540 车型,列表/排序/搜索均正确返回。 - 取舍:SSR/SEO、缩放平移、Playwright 脚本化 e2e 标记延后(已手动联调全栈通过)。
- 2025 · 第 4 批(A:闭合 MVP):补齐 Phase 1 验收(T-1.8)。
- 性能基准
apps/api/bench.mjs:list/filter/detail p95 ≤ 3ms(阈值 1500ms),search p95 1.3ms(阈值 500ms),全部达标。 - Playwright e2e(
apps/web/e2e/smoke.spec.ts):首页/筛选→详情/时间轴/图鉴/搜索 5 项全通过,webServer 自动拉起前后端。 - 修复真实 UX bug:时间轴同年同泳道节点完全重叠导致不可点击 → 实现碰撞分行(错位堆叠)+ 标签 pointer-events:none。
- Phase 1(MVP)正式闭合。累计测试:ETL 31 + API 23 + 前端单元 25 + e2e 5 = 84 个测试全绿。
- 性能基准
- 2025 · 第 5 批(图鉴差异化):解决"列表与图鉴雷同"问题,落实方案"收集欲"主线。
- 图鉴改为图片优先卡牌墙:按分类生成 SVG 占位缩略图(
lib/thumb.ts,真实车照待 Phase 2/3 众包上传替换)。 - 轻量收集功能:localStorage 记录已收集(
lib/useCollection.ts),点卡片"收集"点亮缩略图,顶部显示收集进度条;Phase 3 账户上线后迁移云端。 - 测试:前端单元增至 34(新增 thumb / GalleryCard),e2e 图鉴用例改为验证缩略图+收集交互;全绿。
- 图鉴改为图片优先卡牌墙:按分类生成 SVG 占位缩略图(
- 2025 · 第 6 批(前端全方位重构 · 主线串联):解决"首页死板、一屏过载、无主线"问题。
- 叙事首页(
HomePage):英雄区 + 关键统计 + 时速演进曲线(EvolutionCurve,SVG)+ 四个时代章节(蒸汽→内燃→电力→高铁,每节代表车 + 进入探索),把技术演进主线显性串联。 - 信息架构重组:
/故事首页、/explore探索页、/models/:id详情;顶部导航 故事/探索 + 全局搜索。 - 探索页减负:筛选器收进可折叠面板(默认隐藏,带激活计数),默认图鉴视图,更大留白。
- 章节链接经
?category=跳入探索并自动筛选(URL 同步)。 - 主线逻辑(时代/代表车/时速演进)抽到
lib/eras.ts纯函数并单测。 - 测试:前端单元 39 + e2e 7(覆盖首页→探索→详情/时间轴/搜索/章节跳转),全绿;build 通过。
- 叙事首页(
- 2025 · 第 7 批(专业图标 + 视图合并 + 全详情):
- 全部 emoji → 专业图标:引入
react-icons,统一components/icons.tsx(分类图标 + 品牌/锁/星/筛选/视图图标);缩略图改为Thumb(分类渐变 + 专业图标),移除 emoji/data-URI 方案。 - 探索页合并视图:去掉"列表",统一用图鉴展示(默认),仅保留 图鉴 / 时间轴 两视图。
- 详情页升级为"全部详情":缩略图 Hero + 标签 + 基本信息 / 尺寸与重量 / 动力与性能 / 原始数据 全字段分组展示。
- 测试:前端单元 37 + e2e 7(图鉴收集改 aria-pressed、详情断言分组标题),全绿;build 通过。
- 全部 emoji → 专业图标:引入
- 2025 · 第 8 批(图鉴分页 + 全中文 + 多图灯箱):
- 图鉴分页:客户端分页 18/页,分页器置于卡牌墙上方;筛选变化回到第 1 页;编号跨页连续。
- 详情全中文:新增
lib/fieldLabels.ts(英文规范键→中文),"原始数据"区英文键全部映射为中文(model 17 等已核对全覆盖)。 - 详情多图 + 灯箱:
lib/useImages.ts(每车型本地图册,localStorage)+Lightbox(缩放/滚轮/拖拽平移/上下张/Esc);详情新增"图册"区可添加多张图片并点开缩放欣赏;云端众包上传待 Phase 2/3。 - 测试:前端单元 39 + e2e 8(新增分页/全中文/图册上传缩放),全绿;build 通过。
- 2025 · 第 9 批(接入 Wikimedia Commons 真实照片):
- 每页改为 21;详情"图册"接入 Wikimedia Commons(
lib/commons.ts+useCommonsImages):浏览器端 origin=* CORS 检索自由授权实拍图,署名(作者/许可证/来源链接)显示在灯箱。 - 图片优先级:Commons 真实照片 → 本地上传 → 系统生成示意图(兜底,永不空);卡片角标区分来源(Commons/我的/示意图)。
- 健壮回退:无网/无匹配/请求失败时静默回退示意图;结果做内存 + sessionStorage 缓存。
- 灯箱升级为通用图源(URL/dataURL)并展示署名。
- 注:构建/测试沙箱仅放行 npm,无法联网验证 Commons 覆盖率,需在浏览器端验证(如 CR400AF / HXD1型)。
- 测试:前端单元 42 + e2e 8,全绿;build 通过。
- 每页改为 21;详情"图册"接入 Wikimedia Commons(
- 2025 · 第 10 批(Phase 2 启动 · T-2.1 账户体系,采用 B1):
- 架构:新增独立可写库
app/data/app.db(WritableDbService,含迁移),与只读machines.db分离,避免被 ETL 重建清空。 - 后端:
AuthModule(NestJS + @nestjs/jwt + bcryptjs)——注册/登录//api/auth/me;JwtAuthGuard+RolesGuard(游客<注册<信任<版主<管理员 等级);密码 bcrypt,邮箱规范化小写,密码不外泄。 - 前端:
AuthProvider上下文 + 登录/注册模态框 + 顶栏用户菜单 + 个人主页(贡献积分/已收集/加入日期)。 - 安全提示:JWT secret 走
JWT_SECRET环境变量,默认值仅供开发,生产须替换。 - 测试:后端单元 18 + e2e 14(含注册/重复 409/非法 400/登录 401/me 鉴权);前端单元 42 + e2e 9(含注册→用户菜单→个人主页);build 通过。
- 架构:新增独立可写库
- 2025 · 第 11 批(T-2.2 编辑/修订 + T-2.3 审核):
- 数据:
app.db增revisions/revision_changes/model_overrides三表;编辑不改只读machines.db,而以"字段覆盖"叠加,详情接口读取时合并(标记overridden)。 - 后端:
ContribModule——POST /api/models/:id/revisions(提交编辑,含 old→new diff)、GET .../revisions(历史)、GET /api/revisions/pending(版主队列)、approve/reject(版主+)、GET /api/editable-fields;字段白名单 + 校验(年代范围/状态枚举/国别枚举);信任级以上自动通过;通过即应用覆盖并给作者 +5 积分。 - 引导管理员:
ADMIN_EMAIL环境变量命中即注册为 admin(便于审核演示/测试)。 - 前端:详情页"编辑词条"模态(白名单字段表单)、"修订历史"区(状态/作者/diff)、
/review审核页(版主+,通过/驳回)、顶栏"审核"入口(按角色显示)。 - 测试:后端单元 18 + e2e 21(提交/历史/403/管理员审核生效/自动通过/非法 400);前端单元 42 + e2e 10(含登录后编辑→待审核修订);两端 build 通过。
- 数据:
- 2025 · 第 12 批(T-2.4 荣誉与激励)→ Phase 2 完成:
- 等级头衔(
community/levels.ts纯函数):见习巡道员→巡道员→司炉→副司机→司机→机务段长→总工程师(按积分阈值);徽章(首改采纳/高产编辑/资深贡献/总工殊荣)。 /api/auth/me增等级/徽章/被采纳数;CommunityModule:GET /api/leaderboard(贡献榜),GET/POST/DELETE /api/models/:id/maintainers(词条认领署名)。- 前端:个人主页等级进度条 + 徽章;
/leaderboard贡献榜页(金银铜);详情页"词条维护者"认领/署名;顶栏"贡献榜"入口。 - 测试:后端单元 22 + e2e 25(含 me 等级、贡献榜、认领、未登录 401);前端单元 42 + e2e 13(含认领署名、等级徽章、贡献榜);两端 build 通过。
- Phase 2(众包共建)完成:账户 + Wiki 式编辑/审核/修订历史 + 荣誉体系全部跑通。
- 等级头衔(
- 2025 · 第 13 批(测试账号一键登录):后端开机幂等预置 3 个演示账号(admin@demo.com / mod@demo.com / user@demo.com,密码 demo1234,角色 admin/moderator/user;仅非生产,
SEED_TEST_USERS=false可关);登录框加"测试账号一键填入"。e2e 15。 - 2025 · 第 14 批(Phase 3 启动 · T-3.1 论坛 + T-3.2 词条讨论):
- 可写库增
threads/thread_replies表(板块 + 可选 model_id 绑定词条)。 - 后端
ForumModule:GET /api/boards、GET/POST /api/threads(板块/词条过滤、发帖)、GET /api/threads/:id、POST /api/threads/:id/replies;DTO 校验,发帖/回复需登录。 - 前端:
/community论坛(板块标签 + 发帖 + 帖子列表)、/thread/:id帖子页(正文 + 回复 + 回复框)、详情页"讨论区"(绑定该车型的话题 + 发起讨论);顶栏"社区"入口。 - 测试:后端 e2e 29(发帖/回复/板块/词条绑定/401/400);前端 e2e 16(社区发帖→帖子页回复);两端 build 通过。
- 可写库增
- 2025 · 第 15 批(T-3.3 打卡 + T-3.4 地图)→ Phase 3 完成:
- 可写库增
sightings表;SightingsModule:POST/GET /api/models/:id/sightings、GET /api/sightings/recent(动态流)、GET /api/sightings/map;坐标校验(IsLatitude/IsLongitude),跨库用只读库补 model_code/分类。 - 前端:详情页"目击打卡"区(经纬度/用我的位置 geolocation/车站/车号 + 列表);
/map打卡地图(MapLibre + OpenStreetMap 免费瓦片,标记 + 弹窗 + 最新打卡侧栏);顶栏"打卡地图"入口。 - 修复:sighting 补全用
category_idjoin 分类(model 表无 category 列)导致的 500。 - 取舍:地图先用点位标记(OSM 栅格瓦片,遵守使用政策并署名);热力图/路局聚合/PostGIS 后续;打卡暂不计贡献积分(保持榜单=数据编辑)。
- 测试:后端 e2e 31(打卡/动态/地图/401/非法坐标 400);前端 e2e 18(详情打卡→列表、地图页加载);两端 build 通过。
- Phase 3(社区与空间)完成:论坛 + 词条讨论 + 打卡动态 + 地图。
- 可写库增
- 2025 · 第 16 批(修复 + T-4.1 参数对比):
- 修复:贡献榜列表 class 名
.lb与灯箱.lb(全屏 fixed 遮罩)冲突,导致无法离开贡献榜页 → 列表改名.leaderboard,加回归测试。 - T-4.1 参数对比(Phase 4 起步):
/compare页,搜索加入 2–4 车型,自绘 SVG 雷达图(lib/compare.ts归一化纯函数 +RadarChart)+ 对比表;URL 同步 ids;详情页"加入对比"按钮;顶栏"对比"入口。 - 测试:前端单元 45(新增 compare 归一化)+ e2e 21(含贡献榜可离开回归、参数对比雷达图);build 通过。
- 修复:贡献榜列表 class 名
- 2025 · 第 17 批(完成 Phase 4 主体:T-4.2/4.3/4.4):
- T-4.2 技术族谱(
/family):后端GET /api/models/families按分类→系列聚合;前端分类标签 + 系列泳道 + 型号节点(非国产标记),点击进详情。 - T-4.3 拍车攻略:后端
GET /api/sightings/spots按车站聚合"在哪能拍到什么车",打卡地图页展示热门打卡点;稀有车提醒(轻量):useFollow(localStorage 关注)+ 详情"关注"按钮 + 个人主页"关注车型最新目击"汇总。 - T-4.4 国别维度:探索筛选器已有"国别",族谱标注非国产;制造国/国别属性/原型字段就位且可众包编辑。
- 取舍:真正的父/衍生/原型有向图、跨国连线、保存机车地图(缺坐标)、提醒推送基建 → 待数据/基建后续。
- 测试:后端 e2e 33(含 families/spots);前端单元 45 + e2e 23(含族谱跳详情、关注汇总);两端 build 通过。
- Phase 4 主体完成(数据可得部分),余项已明确标注待数据/基建。
- T-4.2 技术族谱(
- 2025 · 第 18 批(Phase 5:数据大屏 + 开放 API + AI 识车占位):
- 数据大屏(
/stats):后端GET /api/stats(分类/国别/年代/时速演进聚合);前端 KPI + 柱状图 + 时速演进曲线。 - 开放 API / 导出:
GET /api/export/models.json|csv(CSV 转义)+/api-docs接口一览与下载按钮;底部导航入口。 - AI 识车(
/identify):诚实占位页(上传本地预览 + 明确声明非真实识别 + 示例候选),不伪造识别。 - 修复:vite 代理
/api前缀误吞前端路由/api-docs→ 改为正则^/api/仅代理真实接口;加回归测试。 - 取舍(如实标注延后):AR/3D(需 3D 资产)、多语言(需翻译工作量)、真实 AI 模型(需图库训练/算力)。
- 测试:后端 e2e 36(含 stats/export);前端 e2e 28(含大屏/开放API/AI占位 + 两条回归);两端 build 通过。
- Phase 5 数据可得部分完成;五个阶段全部推进完毕,未尽项均有明确原因与后续路径。
- 数据大屏(
- 2025 · 第 19 批(前端专业美化):
- 导航分组:顶栏收敛为 故事 / 图鉴▾ / 社区▾ / 数据▾ / 审核(
NavMenu点击展开下拉,路由/外部点击/Esc 关闭,可访问性 aria)。 - 统一组件与设计令牌:扩充 CSS tokens(间距/圆角/阴影刻度 + 焦点环);新增
components/ui.tsx(Button / PageHeader / EmptyState / Tag)+ 统一.btn体系;统一卡片悬浮过渡、毛玻璃粘性头部。 - UX 一致性:下拉/焦点/卡片/页头统一;族谱页改用 PageHeader + EmptyState。
- 族谱卡片加列车图片:family 节点改为带封面(Thumb 分类插画)的卡片。
- e2e 适配分组导航(图鉴→探索、社区→论坛);前端单元 45 + e2e 28 全绿;build 通过。
- 导航分组:顶栏收敛为 故事 / 图鉴▾ / 社区▾ / 数据▾ / 审核(
- 2025 · 第 20 批(统一组件 100% 收敛):
- 各页改用
ui基础组件:PageHeader(贡献榜/社区/对比/大屏/开放API/AI识车/打卡地图/审核/族谱)、EmptyState(贡献榜/社区/对比)、Button(社区发帖发布、帖子回复、个人退出、审核通过/驳回、详情编辑/关注/加入对比/添加图片/认领/打卡/发起讨论、编辑模态、探索筛选、开放API 导出)。 - 保留差异化控件(分段控件视图切换/板块标签、登录模态、定位按钮)以维持模式语义。
- 文案/类名保持不变,e2e 全绿(前端单元 45 + e2e 28);build 通过。
- 各页改用
- 2025 · 第 21 批(图鉴改为管理员独占管理,用户只读):
- 风险收口:图鉴词条编辑与图片上传仅管理员可用,普通用户只读。
- 后端:
POST /api/models/:id/revisions加@Roles('admin')(普通用户 403,未登录 401)。 - 前端:详情页"编辑词条"、"图册 + 添加图片"入口仅
role==='admin'可见(含 file input 一并隐藏);图册文案改为"由管理员维护"。 - 测试:后端 e2e 36(普通用户编辑 403、管理员编辑自动生效、白名单 400);前端 e2e 29(管理员编辑生效、普通用户无编辑/上传入口、管理员上传+灯箱);两端 build 通过。
- 说明:当前管理员图片上传仍是浏览器本地(localStorage,非共享);"管理员云端管理共享图库 + 公共图库 + 上传/打卡即收集 + 云端收集同步 + 集邮成就"为后续批次(已有完整实现方案)。
- 2025 · 第 22 批(后端图片云存储 + 管理员上传写入共享图库):
- 可写库新增
photos表;服务端文件存储app/data/uploads/(UPLOAD_DIR可覆盖),main.ts用 express.static 暴露/uploads。 PhotosModule:POST /api/models/:id/photos(仅管理员,multer multipart,类型/大小校验)、GET /api/models/:id/photos(公共,所有人可看)、DELETE /api/photos/:pid(管理员)。- 车型列表 API 附带
cover_url(共享图库首图),图鉴卡片用真实照片作封面(管理员上传后所有访客可见)。 - 详情"图册"改为共享图库:管理员上传(multipart)→ 所有人查看 + 灯箱;移除原 localStorage 本地图方案。
- Vite 增
^/uploads/代理。 - 测试:后端 e2e 40(上传 403/201/非图片 400/删除 + 公共列表);前端 e2e 29(管理员上传→共享→灯箱);两端 build 通过;真实管线 curl 验证(上传→入库→静态 200→代理 200)。
- 可写库新增
- 2025 · 第 23 批(候选/确认机制 + 批量取图脚本):
photos加status('candidate'|'confirmed')+source_url/author/license(已存在库自动补列)。管理员手动上传=confirmed;脚本入库=candidate。- 卡片封面只取
confirmed;详情图册显示"候选/图库"角标 + 署名(作者/许可证/来源),管理员可逐张"✓确认/✕删除",并有"确认全部候选"。 - API:
POST /api/photos/:pid/confirm(管理员)。 - 取图脚本
apps/api/scripts/fetch-images.mjs(npm run fetch-images,在有网本机跑):按 Wikidata P18 → Commons 同名分类 → 关键词搜索 顺序为缺图车型下载候选图入库(candidate),记录署名,输出命中报告;支持--limit/--category/--dry。 - 测试:后端 e2e 41(含候选→确认流程);前端单元 45 + e2e 29;两端 build 通过。
- 说明:脚本需联网访问 wikidata/commons,本沙箱不可联网,需在用户本机运行。
- 2025 · 第 24 批(管理员候选审图页):
- 后端
GET /api/photos/candidates(管理员):全站候选图聚合 + 车型信息(跨只读库补 model_code/分类)。 - 前端
/admin/photos审图页(仅管理员):候选图网格(缩略图 + 车型链接 + 署名/来源)、逐张确认/删除、"全部确认";顶栏管理员专属"候选审图"入口(普通用户不可见)。 - 测试:前端 e2e 31(含管理员可访问、普通用户无入口);两端 build 通过。
- 后端
- 2025 · 第 25 批(图鉴展示与封面优化 · 4 项):
-
- 卡片封面始终展示最佳可用图:
cover_url(共享图库 confirmed)→ Commons 实拍(懒取)→ 分类示意图;移除"未收集锁/暗色遮罩",★ 改为个人"收藏"书签(aria 收藏/已收藏)。
- 卡片封面始终展示最佳可用图:
-
- 详情头图改用真实图:hero = featured 封面 → confirmed 图库 → Commons[0] → 示意图(
.detail-hero-img覆盖填充)。
- 详情头图改用真实图:hero = featured 封面 → confirmed 图库 → Commons[0] → 示意图(
-
- 管理员可指定展示图:
photos加featured列;POST /api/photos/:pid/feature(管理员,清同车型其它 featured 并置 confirmed);卡片 cover 查询优先featured再最小 id;详情图册 confirmed 图加"★ 设为封面"(当前封面金色高亮),候选图保留"✓ 确认"。
- 管理员可指定展示图:
-
- 图鉴可直接输入型号筛选:探索工具条加
.kw-input(防抖 300ms →query.q)。
- 图鉴可直接输入型号筛选:探索工具条加
- 测试:前端单元 45 + e2e 31(新增"型号关键字筛选""管理员设为封面");后端单元 22 + e2e 42(新增"封面优先 featured + 权限受控");修复 models.service 单测夹具缺
photos表;两端 build 通过。
-
- 2025 · 第 26 批(Commons 下载到本地,运行时不再访问外部图源):
- 诉求:把原先浏览器端实时检索的 Wikimedia Commons 照片全部下载到本地共享图库,应用运行时只读本地
/uploads,不再发外部请求。 - 前端:移除浏览器端 Commons(删除
lib/commons.ts/lib/useCommonsImages.ts/lib/commons.test.ts)。GalleryCard封面只取本地cover_url(否则分类示意图),不再懒取 Commons;DetailPage图册改为「本地共享图库照片 + 系统示意图」,头图取 featured/confirmed 本地照片;移除"正在从 Commons 检索"提示与 Commons 角标,图注署名仍展示(下载时已存库)。 - 取图脚本升级(
apps/api/scripts/fetch-images.mjs,本机联网跑一次即可):新增--per N(每车型多张)、--confirm(直接入库为 confirmed,封面/图册立即可见,替代原实时 Commons 展示);多来源去重;保存到本地app/data/uploads/+photos表并记录署名(作者/许可证/来源)。 - 说明:构建/测试沙箱仅放行 npm、不可联网,无法在此执行实际下载;需在用户本机运行
node scripts/fetch-images.mjs --per 3 --confirm完成落地。未下载到照片的车型自动回退分类示意图(永不空)。 - 测试:前端单元 42(移除 commons 3 项)+ e2e 31,全绿;后端单元 22 + e2e 42 不变;两端 build 通过。
- 诉求:把原先浏览器端实时检索的 Wikimedia Commons 照片全部下载到本地共享图库,应用运行时只读本地
- 2025 · 第 27 批(修正:下载图片一律进入候选审图):
- 问题:上一批脚本提供了
--confirm,按该建议运行后下载图直接入库为confirmed,跳过了"候选审图"双闸门。 - 修正:取图脚本移除
--confirm,所有下载图一律入库为candidate,进入管理员「候选审图」队列,人工确认后才作封面/图册(恢复"候选 + 人工确认"准确性闸门)。 - 数据修复:将已下载的 Commons 图片(含
source_url)从 confirmed 改回candidate(清 featured);并清除早期 e2e 测试误写入生产库的 8 张 1×1 占位图(行 + 文件)。 - 验证:管理员登录
GET /api/photos/candidates返回 15 张候选(带署名),/admin/photos审图页可见可逐张确认。
- 问题:上一批脚本提供了
- 2025 · 第 28 批(图鉴分页记忆 + 去收集示例 + 首页紧凑/带图):
-
- 图鉴翻页记忆:图鉴页码存入 URL
?gp=N(GalleryView改为受控分页),从卡片进详情后"← 返回图鉴"用navigate(-1)回到来路并停在原页;筛选/关键字变化时自动回到第 1 页(gp清除)。
- 图鉴翻页记忆:图鉴页码存入 URL
-
- 图鉴页移除"收集示例"按钮(保留收集进度条与单卡收藏)。
-
- 首页更紧凑(英雄区/时代轨/留白收敛);时代代表车的 mini 卡在有真实封面(
cover_url)时直接显示照片,且pickRepresentatives优先挑有图车型"带出来"。
- 首页更紧凑(英雄区/时代轨/留白收敛);时代代表车的 mini 卡在有真实封面(
- 测试:前端单元 42 + e2e 33(新增"翻页进详情返回仍在该页""不再显示收集示例"),目标子集全绿;build 通过。
-
- 2025 · 第 29 批(全站专业图标 + 数据大屏重构 + AI 识车接入通义千问):
- 图标:扩充
components/icons.tsx(编辑/对比/确认/关闭/删除/维护/定位/返回/前进/警告/下拉/论坛/图片/奖杯/站点/缩放/翻页等 react-icons 出口);替换 DetailPage、NavMenu、Lightbox、Auth/Edit 模态、ComparePage、ProfilePage、各页返回链接、首页 CTA、EmptyState 等处的 emoji/符号为专业图标;EmptyStateicon改为 ReactNode。(保留原始数据 diff 的→与原生<option>内 ↑↓ 文案,属内容/原生限制) - 数据大屏(
/stats)重构为真正的大屏:顶栏标题 + 实时时钟 + 渐变描边;5 张带图标/光晕的 KPI 卡(车型/个体/分类/最高时速/年代跨度);面板网格含 SVG 环形图(分类构成 / 国别构成)、纵向柱状图(各年代新增)、时速演进曲线(跨列);响应式。 - AI 识车(
/identify)接入 通义千问 DashScope(OpenAI 兼容多模态qwen-vl-plus):后端IdentifyModule——POST /api/identify(登录态,multer 内存上传 → base64 data URL → 调用 Qwen-VL,提示词要求输出 JSON 候选);解析候选并匹配图鉴库给出可点击详情;密钥走apps/api/.env的DASHSCOPE_API_KEY(.gitignore忽略,附.env.example,main.tsprocess.loadEnvFile()加载)。前端重写为上传→识别→候选(置信度条/依据)+图鉴相关车型,含未登录提示与加载态。 - 真机验证:上传真实电力机车照片,识别为 DJ1型(95%) 并命中铭牌"DJ1 0003A",给出 SS8/HXD1 备选,链接到对应词条。
- 测试:前端单元 42 + e2e(AI 页改为"未登录提示+上传区"、数据大屏改为 donut/vbars 断言),子集全绿;前后端 build 通过。
- 图标:扩充
- 2025 · 第 30 批(AI 识车结果持久化 + 历史 CRUD + 哈希缓存):
- 可写库新增
identifications表(user_id/filename/image_hash/summary/guesses_json/matches_json/top_code/top_name/note/error/created_at)。 - 后端:
POST /api/identify改为识别并落库——先按图片 SHA-256 哈希命中缓存(同图已成功识别则复用结果与图片文件,不再调用 LLM、不重复存图),否则调用通义千问并保存图片;GET /api/identifications(本人历史)、PATCH /api/identifications/:id(改备注/人工纠正)、DELETE /api/identifications/:id(删除,仅当无其它记录共用该图时删文件);均需登录、按用户隔离。 - 前端:
/identify识别后结果加入历史;新增"识别历史"列表——缩略图 + 候选/置信度 + 摘要 + 图鉴相关车型链接 + 可编辑备注(保存) + 删除 + "缓存命中"标记。 - 真机验证:首次识别
cached=false落库;同图再传cached=true(秒回、零调用);列表/改备注/删除均生效;缓存去重的共享图片在删除其一后仍保留。 - 测试:前端单元 42 + e2e(AI 页 + 数据大屏)全绿;前后端 build 通过;测试产生的识别记录与图片已清理。
- 可写库新增
- 2025 · 第 31 批(识别历史删除确认 + 导航 IA 重构):
- 识别历史删除前弹确认(
确定删除这条识别记录?删除后不可恢复。),避免误删。 - 导航按用户意图重组:图鉴(探索图鉴 / 数据大屏 / 技术族谱 / 参数对比 / AI 识车)、社区(论坛 / 打卡地图 / 贡献榜);移除原先混杂的「数据」组。数据大屏作为「图鉴的宏观概览」置于图鉴组(先看大盘再下钻);开放 API 属开发者资源,仅保留在页脚,顶部导航更聚焦。
- 测试:前端 build 通过;导航相关 e2e(社区发帖、审核/候选审图入口、数据大屏、AI 识车)全绿。
- 识别历史删除前弹确认(
使用说明
- 任务编号
T-<阶段>.<序号>,子项含 开发 / 单元测试(UT) / 端到端测试(E2E)。 [ ]未开始 ·[~]进行中 ·[x]已完成。← FR-x.x表示对应 PRD 功能需求;依赖:表示前置任务。- 测试约定:UT 覆盖率目标 ≥ 80%(核心逻辑模块);E2E 覆盖关键用户旅程。
技术栈基线(默认,待 PRD Open Question 锁定)
- 前端:Next.js + React + TypeScript;可视化 D3/ECharts;地图 MapLibre。
- 后端:NestJS(Node+TS) 或 FastAPI(Python);本清单以 NestJS + TypeScript 表述。
- 数据库:PostgreSQL (+PostGIS);检索 Meilisearch;缓存 Redis;对象存储 S3/OSS。
- 测试:UT 用 Jest/Vitest;API 集成用 Supertest;E2E 用 Playwright;ETL 用 pytest(如 Python)。
- CI:GitHub Actions(lint + UT + 集成 + E2E 冒烟)。
Phase 0 · 工程基建(所有阶段前置)
T-0.1 仓库与脚手架
- [~] 开发:Monorepo 结构(apps/web、apps/api、packages/shared、etl)。【已建
app/etl+app/tests的数据层与测试骨架;JS 前后端 apps 待建】 - 开发:TypeScript、ESLint、Prettier、commitlint、husky 预提交钩子。
- UT:shared 工具函数(单位解析、格式化)单测样例跑通。【clean/field_dict 已覆盖】
- E2E:Playwright 安装 + 首条"首页可打开"冒烟用例。
T-0.2 CI/CD 流水线
- 开发:CI 跑 lint + UT + 集成测试 + E2E 冒烟;PR 必须绿。
- 开发:测试覆盖率报告产出与阈值门禁。
- 开发:预览环境自动部署(每 PR)。
T-0.3 基础设施
- 开发:本地 docker-compose(PostgreSQL+PostGIS、Redis、Meilisearch、MinIO)。
- 开发:数据库迁移工具(Prisma/TypeORM migration)接入。
- UT:数据库连接/迁移健康检查测试。
Phase 1 · 数据底座 MVP
1A 数据建模与 ETL
T-1.1 字段字典与数据模型 ← FR(数据需求 4.2)
- 开发:定义统一字段字典(数值+单位分离),落库 schema:Category / Model / Unit。
- 开发:迁移脚本 + 种子枚举(国别属性、状态、分类)。
- UT:字段校验规则(首产≤停产、数值范围、单位枚举、型号唯一)。
- UT:Model↔关系字段(父型号/衍生/原型车)外键完整性。
T-1.2 ETL 导入管线 ← FR(4.4)
- 开发:读取 12 张 CSV/Excel,处理合并单元格、空表头修复。
- 开发:单位拆分("整备重量 / 轴重 /t" → 独立字段+单位)。
- 开发:字段映射到统一字典;系列→型号层级归并;改型关系识别。
- 开发:产出导入报告(成功/失败/待人工复核)。
- UT:每类清洗规则的单元测试(含脏数据样例:缺值、混排、异常年代)。
- UT:幂等性测试(重复导入不产生重复记录)。
- E2E:跑全量 12 表导入,断言记录数与抽样字段正确。
1B 后端 API
T-1.3 车型查询 API ← FR-1.1 / FR-1.2 / FR-1.5
- 开发:车型列表接口(分页、分类筛选、排序)。
- 开发:多维筛选(年代区间、时速区间、生产商、国别、状态)。
- 开发:车型详情接口(参数、关系、图集占位)。
- UT:筛选/排序/分页边界(空结果、超范围页码、非法参数)。
- UT:详情序列化(数值+单位、缺失字段留空)。
- E2E(API):列表→详情链路,断言筛选组合结果正确。
T-1.4 搜索服务 ← FR-1.3
- [~] 开发:Meilisearch 索引(型号/别名/生产商),增量同步。【延后:当前用 SQLite LIKE+排序实现】
- 开发:搜索接口(模糊匹配,拼音为增强项)。
- UT:索引构建与查询排序、空查询、特殊字符处理。
- E2E(API):关键词搜索命中预期车型。
1C 前端
T-1.5 车型列表与详情页 ← FR-1.1/1.4/1.5
- 开发:列表页(筛选器、分页、排序、卡片/表格切换)。
- 开发:详情页(参数表、历史沿革、图集占位、相关入口)。
- [~] 开发:响应式 + SEO(SSR/metadata)。【已响应式;SSR/SEO 待 Next.js 化或预渲染,后续】
- UT:筛选器组件、单位展示组件、详情渲染(含缺失字段)。
- E2E:用户筛选→进入详情→参数正确展示的完整旅程。
T-1.6 时间轴视图 ← FR-2.1
- 开发:年代横轴 + 分类泳道;节点点击展开详情卡。
- [~] 开发:缩放/平移、按分类显隐。【已实现轴+刻度+悬停标签+碰撞分行;缩放/平移待增强】
- UT:时间轴数据转换(年代缺失/区间重叠/排序/碰撞分行)。
- E2E:打开时间轴→点击节点→跳转详情。
T-1.7 图鉴卡牌视图 ← FR-2.2
- 开发:卡片墙 + 分类筛选 + "已收集/未收集"占位(收集逻辑 P3 接入)。
- UT:卡片列表渲染、筛选、占位状态。
- E2E:切换分类→卡片刷新→点击进入详情。
T-1.8 MVP 验收
- E2E 套件:首页→搜索→筛选→详情→时间轴→图鉴 全链路冒烟。【Playwright 5 项全通过】
- 性能:列表/详情 P95 < 1.5s,搜索 < 500ms 基准测试。【实测 p95≤3ms / 1.3ms,远优于阈值】
Phase 2 · 众包共建
T-2.1 账户与权限 ← FR-3.1/3.2/3.3
- 开发:注册/登录(邮箱+第三方)、会话/JWT。【邮箱+密码 JWT;第三方登录后续】
- 开发:RBAC(游客/注册/信任/版主/管理员)。
- 开发:个人主页(贡献统计、徽章、收集进度占位)。
- UT:权限矩阵(各角色可执行操作)、令牌过期/刷新。【AuthService 单测 + 角色等级 RolesGuard】
- E2E:注册→登录→访问受限页→登出。
T-2.2 编辑与修订版本 ← FR-4.1/4.2/4.5
- 开发:字段编辑建议提交;Revision 版本记录。
- 开发:diff 对比与回滚。【修订含 old→new diff;覆盖按修订追溯,可回滚到基础数据】
- 开发:字段校验(数值范围、单位、年代逻辑)复用 T-1.1 规则。
- UT:版本生成、diff 计算、回滚正确性、校验拦截非法值。【经 e2e 覆盖】
- E2E:编辑字段→生成版本→对比→(管理员)审核生效。
T-2.3 审核流程 ← FR-4.3/4.4/4.6
- 开发:审核队列;新手入队、信任用户直接生效。
- 开发:字段来源引用(修改说明 note);争议字段讨论后续。
- UT:审核状态机(待审/通过/驳回)、信任分级路由。【经 e2e 覆盖】
- E2E:新手提交→版主审核通过→数据生效。
T-2.4 荣誉与激励 ← FR-5.1~5.5
- 开发:贡献积分引擎;等级头衔;徽章成就;贡献榜;词条认领署名。
- UT:积分计算、等级阈值、徽章触发条件、防刷分规则。【levels 单测 + e2e 积分/榜单/认领】
- E2E:完成被采纳编辑→积分增加→徽章/榜单更新。
Phase 3 · 社区与空间
T-3.1 论坛 ← FR-6.1/6.2
- 开发:板块(综合/拍车打卡/历史考证);发帖、回复;持久化永久可查。
- [~] 开发:@、点赞、收藏。【发帖/回复/板块已做;@/赞/收藏后续】
- UT:发帖/回复/分页、权限、保留历史。【经 e2e 覆盖】
- E2E:发帖→回复→历史可检索。
T-3.2 词条讨论与动态流 ← FR-6.3/6.4/6.5
- 开发:详情页内嵌讨论(绑定 model_id 的讨论区)。
- 开发:打卡动态 Feed(打卡地图页"最新打卡")。【精华化引用后续】
- UT:讨论与车型绑定。【经 e2e 覆盖(modelId 过滤)】
- E2E:词条下发起讨论 → 帖子页回复。
T-3.3 打卡与收集 ← FR-7.1/7.2
- 开发:目击打卡(车号/时间/地点/经纬度);图鉴收集进度联动(localStorage,Phase 3 已起)。
- UT:打卡校验(坐标范围)、收集进度计算。【经 e2e(非法坐标 400)+ 前端单测】
- E2E:详情页打卡 → 出现在打卡列表。
T-3.4 地图视图 ← FR-2.5
- 开发:打卡地图(MapLibre + OpenStreetMap 瓦片)+ 标记 + 最新打卡侧栏。
- [~] 开发:配属地图 + 目击热力图(PostGIS 聚合)。【已做目击点位地图;热力/路局聚合后续】
- UT:地理点位渲染。【经 e2e(map 容器加载)】
- E2E:打开地图→展示标记/侧栏。
Phase 4 · 进阶玩法 + 圈层扩展
T-4.1 参数对比 ← FR-2.3
- 开发:勾选 2–4 车型→雷达图 + 对比表。
- UT:对比数据归一化、单位对齐、缺失项处理。
- E2E:选择多车型→对比图渲染正确。
T-4.2 技术族谱图 ← FR-2.4
- 开发:按系列聚合的谱系视图(分类→系列→型号,可进详情)。
- [~] 开发:父/衍生/原型有向图 + 跨国连线。【现用 series 谱系;真正关系待 model_relation 数据/众包】
- UT:族谱数据构建(系列聚合)。【经 e2e 覆盖】
- E2E:打开族谱→节点跳详情。
T-4.3 拍车攻略 / 保存机车地图 / 稀有车提醒 ← FR-7.3/7.4/7.5
- 开发:拍车攻略(按打卡车站聚合"在哪能拍到什么车")。
- [~] 开发:保存机车地图。【已有 unit.location 文本;缺坐标,地图化待数据】
- 开发:稀有车提醒(轻量版:关注 + 个人主页汇总关注车型最新目击)。【推送待通知基建】
- UT:聚合排序、关注汇总。【经 e2e 覆盖】
- E2E:关注车型→个人主页"最新目击"出现;拍车攻略聚合。
T-4.4 圈层二数据扩展 ← PRD 3.1
- [~] 开发:在华外国车型 + 国外原型导入。【国别属性/制造国/原型字段就位且可众包编辑;真实国外数据待录入】
- 开发:按国别筛选(探索筛选器)+ 族谱标注非国产。
- [~] 开发:世界地图 / 跨国族谱连线。【待圈层二数据】
- UT:国别字段映射。【经既有覆盖】
Phase 5 · 智能化与开放
T-5.1 AI 识车 ← FR-8.1
- 开发:照片→车型识别。【接入通义千问 DashScope
qwen-vl-plus多模态:POST /api/identify上传识别 + 匹配图鉴库给出候选与链接;密钥走DASHSCOPE_API_KEY】 - [~] UT:推理服务接口、置信度阈值、未知类回退。【已含 JSON 解析容错/未配置回退/错误处理;自动化单测待补】
- E2E:上传照片→返回候选。【真机验证:DJ1 型 95% 命中铭牌;前端未登录提示 + 上传区 e2e】
T-5.2 数据大屏 / 开放 API / AR-3D / 多语言 ← FR-8.2~8.5
- 开发:可视化大屏(
/stats:分类/国别/年代柱状 + 时速演进曲线,后端/api/stats)。 - 开发:开放 API + 数据导出(
/api/export/models.json|csv+/api-docs文档页)。 - 开发:AR/3D 展示。【需 3D 资产/模型,延后】
- 开发:多语言。【需较大翻译工作量,延后;架构可后续接 i18n】
- UT:聚合统计、导出格式。【后端 e2e:stats / export json / export csv】
- E2E:大屏渲染、API 文档与导出链接、AI 占位页。
横切任务(贯穿各阶段)
T-X.1 非功能与质量 ← PRD 6
- 开发:性能预算监控、日志/审计(编辑、审核、积分流水)。
- 开发:安全(防刷分、UGC 审核、敏感地点脱敏)、合规(图片版权声明)。
- UT:限流、脱敏、版权字段校验。
- E2E:安全旅程(越权访问被拒、敏感坐标脱敏展示)。
T-X.2 可观测与运维
- 开发:错误监控(Sentry)、指标看板(KPI:编辑量/审核通过率/留存)。
- 开发:数据备份与回滚演练。
里程碑对照
| 里程碑 | 覆盖任务 | 出口标准 |
|---|---|---|
| M1 (MVP) | T-0.* / T-1.* | 12 表入库 + 列表/详情/搜索/时间轴/图鉴 + 性能达标 |
| M2 | T-2.* | 账户 + 编辑/审核/修订 + 荣誉体系上线 |
| M3 | T-3.* | 论坛/讨论/动态/打卡 + 地图 |
| M4 | T-4.* | 对比 + 族谱 + 进阶玩法 + 圈层二数据 |
| M5 | T-5.* | AI 识车 + 大屏 + 开放 API + AR/3D + 多语言 |
关键依赖链
T-0.* ──▶ T-1.1 ──▶ T-1.2 ──▶ T-1.3/1.4 ──▶ T-1.5/1.6/1.7 ──▶ T-1.8(MVP)
└─▶ T-2.1 ──▶ T-2.2 ──▶ T-2.3 ──▶ T-2.4
T-2.1 ──▶ T-3.1/3.2/3.3 ; T-1.x(PostGIS) ──▶ T-3.4
T-1.1(关系字段) ──▶ T-4.2(族谱) ; T-3.3 ──▶ T-4.3
T-1.1(国别/原型) ──▶ T-4.4(圈层二)