Files
novalon-website/docs/superpowers/specs/2026-07-17-cms-implementation-tasks.md
T
张翔 10404dbb36 chore: sync marketing pages, CMS extensions, tests and project docs
同步工作区剩余变更,主要包括:
- 营销页面组件与布局持续优化(about/news/services/solutions/team 等)
- 详情页四层叙事组件、布局组件、UI 组件调整
- CMS 数据模型、API 路由、权限、工作流、站内通知、媒体管理扩展
- 新增/补充单元测试与 E2E 测试(cms-workflow.spec.ts 等)
- ESLint 9 迁移、jest/tsconfig 配置更新、依赖调整
- 新增 ADR、CMS 评估文档、Release Review / Acceptance 报告
- 移除水墨装饰组件与大体积未使用字体文件
2026-07-25 08:04:01 +08:00

37 KiB
Raw Blame History

CMS 实施任务拆解

基于 PRD 2026-07-17-cms-implementation-prd.md 按 tracer-bullet 垂直切片拆分。 项目使用 Gitea + Jenkins,因当前环境无 Gitea API 访问权限,暂以 tasks.md 维护;后续可批量导入 Gitea Issues。

执行顺序总览

P0 基础层(必须串行)
├── #1 为 ContentItem 增加 locale 字段
├── #2 实现 RBAC 数据模型与权限中间件
└── #3 实现内容状态机与工作流基础

P1 核心能力层(可部分并行)
├── #4 实现媒体管理模块
├── #5 实现站内消息通知中心
└── #6 更新 Nginx 配置支持混合渲染

P2 业务迁移层(在 P0 完成后可并行)
├── #7  迁移法律页到 CMS
├── #8  迁移新闻页到 CMS
├── #9  迁移团队页到 CMS
├── #10 迁移案例页到 CMS
├── #11 迁移服务页到 CMS
├── #12 迁移方案页到 CMS
├── #13 迁移产品页到 CMS
├── #14 迁移独立产品页到 CMS
└── #15 迁移首页运营位到 CMS

P2 管理后台层(依赖 #1~#5)
└── #16 构建 CMS 管理后台界面

横向
└── #17 建立 CMS/RBAC/工作流测试覆盖

Issue #1:为 ContentItem 增加 locale 字段并更新唯一索引

优先级P0
估算0.5 天
依赖:无
阻塞#7 ~ #15 状态:已完成(2026-07-17

描述

ContentItem 增加 locale 字段以支持未来多语言扩展。默认值 'zh-CN',并为存在 slug 的模型补充唯一索引 (slug, modelCode, locale)

验收标准

  • Prisma schema 中 ContentItem 包含 locale String @default("zh-CN")
  • (slug, modelCode, locale) 添加唯一索引(仅当 slug 非空时生效)。
  • 现有数据通过 migration 或 seed 脚本写入默认 locale
  • src/lib/cms/types.ts 中的类型定义同步更新。
  • 单元测试覆盖:数据层返回 locale、缺失 locale 时默认 zh-CN。

实现摘要

  • 变更文件:prisma/schema.prismaprisma/seed.tssrc/lib/cms/types.tssrc/lib/cms/data-server.tssrc/lib/cms/data-server.test.ts
  • 新增 migrationprisma/migrations/20260717034113_add_locale_to_content_item/
  • 验证:npm run type-checknpm run lintnpm run test:unit 全部通过

Issue #2:实现 RBAC 数据模型与 /api/admin/* 权限中间件

优先级P0
估算1.5 天
依赖:无
阻塞#3、#5、#16、#17

描述

建立角色与权限数据模型,并在所有 /api/admin/* 路由上增加权限中间件,实现“角色 × 内容模型 × 操作”矩阵。

验收标准

  • Prisma schema 新增 RolePermissionUserRole 三个模型。
  • 内置 5 个角色:super_admincontent_admincontent_editorreviewerreadonly
  • 权限操作粒度:createreadupdatedeletepublish
  • 所有 /api/admin/* 路由在请求处理前检查当前用户权限,无权限返回 403。
  • 提供初始化/种子脚本为默认管理员分配 super_admin 角色。
  • 单元测试覆盖:授权通过、未授权拒绝、模型级权限隔离。

实现摘要

  • 变更文件:prisma/schema.prismaprisma/seed.tssrc/lib/permissions.tssrc/lib/permissions.test.tssrc/app/api/admin/items/route.tssrc/app/api/admin/zones/route.ts
  • 新增 migrationprisma/migrations/20260717035951_add_rbac_models/
  • 验证:npm run type-checknpm run lintnpm run test:unit 全部通过

Issue #3:实现内容状态机与工作流基础

优先级P0
估算1.5 天
依赖#2
阻塞#5、#7 ~ #16、#17

描述

明确 review 状态语义并落地最简工作流:内容可提交审核,具备 publish 权限的角色可通过或驳回。AuditLog 记录每次状态流转。

验收标准

  • 状态流转合法路径:draft → review → publisheddraft → review → draft(驳回)、published → archived
  • 非法状态转换被阻止并返回明确错误。
  • 仅拥有对应模型 publish 权限的用户可将 review 状态内容通过或驳回。
  • 状态变更时 AuditLog 记录 before/after、操作人、时间戳。
  • ContentItem.version 在每次状态流转或内容更新时递增。
  • 单元测试覆盖所有合法与非法状态流转场景。

实现摘要

  • 新增文件:
    • src/lib/cms/workflow.ts:状态机核心(submit/approve/reject/archive),含合法转换校验、版本递增、AuditLog 记录。
    • src/lib/cms/workflow.test.ts:状态机 25 个单元测试(含 16 组转换矩阵)。
    • src/app/api/admin/items/[id]/workflow/route.ts:工作流 API 路由。
    • src/app/api/admin/items/[id]/workflow/route.test.ts:路由 7 个集成测试。
  • 变更文件:
    • src/app/api/admin/items/route.tsPUT 不再接受 status 直接变更;任何内容更新触发 version 自增。
  • 权限规则:
    • submit:需要对应模型 update 权限。
    • approve / reject / archive:需要对应模型 publish 权限。
  • 验证:
    • npm run test:unit:793 个测试全部通过(工作流 32 个)。
    • npm run type-check:无类型错误。
    • npm run lint:无错误。

Issue #4:实现媒体管理模块

优先级P1
估算2 天
依赖:无
阻塞#7 ~ #16
状态:已完成(2026-07-17

描述

完成媒体上传、本地/OSS 双写、缩略图与 WebP/AVIF 派生格式生成,并在 MediaAsset 中记录完整元数据。

验收标准

  • /api/admin/media 支持单文件/多文件上传,返回 MediaAsset 元数据。
  • 开发/测试环境文件落盘到 public/uploads/;生产环境写入 OSS/S3(通过环境变量切换)。
  • 上传后自动生成缩略图、WebP、AVIF 格式,并在 MediaAsset 中记录所有 URL。
  • 支持按 ID 查询、删除媒体(删除时同步清理本地文件或 OSS 对象)。
  • 上传非图片文件时仅记录原文件,不生成派生格式。
  • 集成测试覆盖上传、查询、删除及环境切换逻辑。

实现摘要

  • 新增文件:
    • src/lib/media/types.ts:媒体类型定义(StoredFile、StorageProvider、MediaDerivatives 等)。
    • src/lib/media/image-processor.ts:图片元数据提取与缩略图/WebP/AVIF 派生格式生成。
    • src/lib/media/storage.tsLocalStorageProviderS3StorageProvidergetStorageProvider 工厂。
    • src/lib/media/media-service.ts:上传、删除、查询、分页服务层。
    • src/lib/media/*.test.ts:图片处理、存储、服务层单元测试。
    • src/app/api/admin/media/route.test.tsAPI 路由集成测试。
  • 变更文件:
    • prisma/schema.prismaMediaAsset 增加 derivatives 字段。
    • prisma/seed.ts:为 media 模型分配 RBAC 权限。
    • src/app/api/admin/media/route.ts:重构为调用 media-service 并集成 requirePermission
  • 验证:
    • npm run test:unit:761 个测试全部通过(媒体模块 44 个)。
    • npm run test:coverage:check:媒体模块语句覆盖 93.61%、分支 69.33%、函数 90.47%。
    • npm run lint:无错误。
    • npm run type-check:无类型错误。

Issue #5:实现站内消息通知中心

优先级P1
估算1 天
依赖#2、#3
阻塞#16 状态:已完成(2026-07-17

描述

为工作流提供站内消息能力:审核人收到待审核 badge,内容提交人收到审核通过/驳回通知。

验收标准

  • 内容提交审核时,向具备对应模型 publish 权限的用户生成待审核通知。
  • 审核通过或驳回时,向内容创建人生成结果通知。
  • /api/admin/notifications 支持查询当前用户通知列表、标记已读、获取未读数量。
  • 通知包含触发人、内容标题、内容模型、状态变更信息。
  • 单元测试覆盖通知生成与读取逻辑。

实现摘要

  • 新增文件:
    • prisma/migrations/20260717044101_add_notification_model/migration.sqlNotification 表迁移。
    • src/lib/cms/notifications.ts:通知服务(创建、查询、标记已读、未读计数、按权限查找用户、通知审核人/创建人)。
    • src/lib/cms/notifications.test.ts:通知服务 14 个单元测试。
    • src/app/api/admin/notifications/route.tsGET 查询当前用户通知列表。
    • src/app/api/admin/notifications/route.test.ts:列表 API 6 个集成测试。
    • src/app/api/admin/notifications/[id]/read/route.tsPATCH 标记单条已读。
    • src/app/api/admin/notifications/[id]/read/route.test.ts4 个集成测试。
    • src/app/api/admin/notifications/read-all/route.tsPATCH 全部标记已读。
    • src/app/api/admin/notifications/read-all/route.test.ts3 个集成测试。
    • src/app/api/admin/notifications/unread-count/route.tsGET 未读数量。
    • src/app/api/admin/notifications/unread-count/route.test.ts3 个集成测试。
  • 变更文件:
    • prisma/schema.prisma:新增 Notification 模型。
    • src/lib/cms/workflow.ts:状态流转后调用通知服务生成站内消息。
    • src/lib/cms/workflow.test.ts:补充通知调用断言。
  • 验证:
    • npm run test:unit:823 个测试全部通过(通知相关 30 个、工作流 32 个)。
    • npm run type-check:无类型错误。
    • npm run lint:无错误。

Issue #6:更新 Nginx 配置支持混合渲染

优先级P1
估算0.5 天
依赖:无
阻塞#7 ~ #15(生产环境验证)

描述

更新 nginx-static-production.conf,将 /api/*/admin/* 及动态路由正确代理到 Next.js 服务,确保 SSR/ISR 生效。

验收标准

  • /api/*/admin/* 请求被代理到 Next.js 服务端口。
  • 营销页面静态资源与 ISR 回源路径正确配置。
  • 配置变更后在测试环境验证:CMS API 可访问、ISR revalidate 成功、Draft Mode 预览正常。
  • 文档记录 Nginx 变更点与回滚步骤。

实现摘要

  • 变更文件:nginx-static-production.conf
  • 主要改动:
    1. 新增 upstream nextjs_app { server novalon-website:3000; },指向运行 next start 的 Next.js 服务。
    2. 新增全局反向代理头(Host、X-Forwarded-*、WebSocket Upgrade 映射)。
    3. 新增 location /api/:无缓存,代理到 Next.js(覆盖 CMS API、联系表单、认证)。
    4. 新增 location /admin/:代理到 Next.jsCookie 透传支持 Draft Mode 预览。
    5. 新增 location /uploads/:为本地媒体存储提供长期缓存。
    6. 更新 location /:使用 try_files ... @nextjs,静态 HTML 优先,未命中回源 Next.js。
    7. 新增 named location @nextjsISR/SSR/动态路由回源。
    8. 删除重复的 Referrer-Policy 头并修复缩进。
  • 验证:
    • nginx -t 语法检查通过(在包含 nginx 的容器/主机上执行)。
    • 相关质量门禁通过。

变更点与回滚步骤

变更点:

  • Nginx 不再仅提供静态文件,而是将 /api/*/admin/* 及未命中的页面请求代理到 Next.js 运行时。
  • 需要同时部署一个运行 next start 的 Next.js 容器/服务,且服务名/端口与 upstream nextjs_app 一致。
  • docker-compose.server.yml 当前使用 Dockerfile.static(纯 Nginx),混合渲染上线前需替换为基于 Node 的镜像并运行 next start

回滚步骤:

  1. 还原 nginx-static-production.conf 到上一个 git 版本:
    git checkout HEAD~1 -- nginx-static-production.conf
    
  2. 重新加载 Nginx
    nginx -t && nginx -s reload
    
  3. 停止或隔离 Next.js 运行时服务(可选;若未部署则不依赖)。
  4. 验证 /api/*/admin/* 不再尝试代理(预期返回 404 或静态站点的 404 页面)。

Issue #7:迁移法律页到 CMS 并启用 ISR

优先级P2
估算1 天
依赖#1、#2、#3
阻塞:无
状态:已完成(2026-07-17

描述

将法律相关页面(隐私政策、服务条款等)的内容从 src/lib/constants/*.ts 迁移到 CMS,页面从 CMS API 读取并启用 ISR。

验收标准

  • 创建 legal-page 内容模型并配置必要字段(pageType、heroTitle、heroDescription、lastUpdated、content)。
  • 将现有法律页内容导入 CMS(拆分为 privacy/terms 两条记录,content 为完整 HTML)。
  • 页面组件从 CMS API 读取内容与 Hero 字段,保留内联内容作为降级兜底。
  • 法律页发布/更新后调用 /api/cms/revalidate 刷新 /privacy/terms 缓存。
  • 单元测试覆盖 revalidate 路由 legal-page 分支及页面 CMS/降级渲染。

实现摘要

  • 新增文件:
    • prisma/seeds/legal-pages.ts:隐私政策/服务条款完整 HTML 种子数据。
  • 变更文件:
    • src/lib/cms/content-types.tslegal-page 模型字段改为 pageType + heroTitle + heroDescription + lastUpdated + contentrichtext)。
    • prisma/seed.ts:更新 legal-page 模型定义;拆分为 privacy/terms 两条 seed 数据。
    • src/app/privacy/page.tsx:从 CMS 读取 content/heroTitle/heroDescription,启用 revalidate = 3600
    • src/app/terms/page.tsx:同上。
    • src/app/api/cms/revalidate/route.ts:增加 legal-page 特殊分支,刷新 /privacy/terms
  • 测试:
    • src/app/api/cms/revalidate/route.test.ts:新增 7 个测试,覆盖 secret 校验、legal-page 全量/按 slug 刷新。
    • src/app/privacy/page.test.tsx:新增 2 个 CMS 集成测试。
    • src/app/terms/page.test.tsx:新增 2 个 CMS 集成测试。
  • 验证:
    • npm run test:unit834 个测试全部通过。
    • npm run type-check:无类型错误。
    • npm run lint:无错误。

Issue #8:迁移新闻页到 CMS 并启用 ISR

优先级P2
估算1.5 天
依赖#1、#2、#3、#4
阻塞:无
状态:已完成(2026-07-17

描述

将新闻列表与详情页迁移到 CMS,支持草稿、审核、发布流程,图片使用媒体库。

验收标准

  • 创建 news 内容模型,包含标题、摘要、正文、封面图、发布时间、分类等字段。
  • 新闻列表页与详情页从 CMS API 读取,使用 ISRrevalidate = 3600)。
  • 封面图字段为 image 类型,已可关联 MediaAsset
  • src/lib/constants/news.ts 保留类型定义,数据通过 prisma/seed.ts 导入 CMS。
  • 单元测试覆盖:列表页 CMS 映射、详情页渲染/404/相关新闻/Metadata/generateStaticParams

实现摘要

  • 变更文件:
    • src/lib/cms/content-types.tsnews 模型 category 选项与现有 UI/常量对齐为「公司新闻」「研发动态」。
    • src/app/(marketing)/news/page.tsx:从 CMS 读取并启用 revalidate = 3600
    • src/app/(marketing)/news/[slug]/page.tsx:从 CMS 读取详情、generateStaticParams、相关新闻过滤,启用 revalidate = 3600
    • src/app/api/cms/revalidate/route.tsnews 模型通过已有 listPage/detailPage 配置自动刷新 /news/news/{slug}(无需额外改动,补充测试)。
  • 新增文件:
    • src/app/(marketing)/news/page.test.tsx:列表页 3 个单元测试。
    • src/app/(marketing)/news/[slug]/page.test.tsx:详情页 7 个单元测试。
    • src/app/api/cms/revalidate/route.test.ts:补充 news 模型刷新测试。
  • 验证:
    • npm run test:unit844 个测试全部通过。
    • npm run type-check:无类型错误。
    • npm run lint:无错误。

Issue #9:迁移团队页到 CMS 并启用 ISR

优先级P2
估算1 天
依赖#1、#2、#3、#4
阻塞:无
状态:已完成(2026-07-17

描述

将团队页面内容迁移到 CMS,支持在管理后台增删改团队成员信息。

验收标准

  • 复用 team-page 内容模型(在 prisma/seed.ts 中定义),包含 Hero 标签、主标题、描述、统计指标、团队优势、团队文化等字段。
  • 团队页从 CMS API 读取并启用 ISRrevalidate = 3600)。
  • src/lib/constants/team.ts 保留类型定义,页面数据通过 CMS 读取。
  • 单元测试覆盖团队页 CMS 数据读取与渲染。

实现摘要

  • 变更文件:
    • src/app/(marketing)/team/page.tsx:从 CMS 读取 team-page 内容,启用 revalidate = 3600
    • src/app/(marketing)/team/client.tsx:接收 CMS 数据并传递给 TeamContentV3
    • prisma/seed.ts:已包含 team-page 模型定义与种子数据。
  • 新增文件:
    • src/app/(marketing)/team/page.test.tsx:团队页 CMS 集成测试。
  • 验证:
    • npm run test:unit833 个测试全部通过。
    • npm run type-check:无类型错误。
    • npm run lint:无错误。

Issue #10:迁移案例页到 CMS 并启用 ISR

优先级P2
估算1.5 天
依赖#1、#2、#3、#4
阻塞:无
状态:已完成(2026-07-17

描述

将案例列表与详情页迁移到 CMS,保留行业过滤、数据指标、时间线等结构。

验收标准

  • 创建 case-study 内容模型,覆盖客户、行业、挑战、方案、成果、指标、时间线、相关服务、客户证言等字段。
  • 案例列表页与详情页从 CMS API 读取并启用 ISRrevalidate = 3600)。
  • 行业过滤通过 CASE_INDUSTRIES 常量与前端组件实现。
  • src/lib/constants/cases.ts 保留类型定义与行业常量,数据迁移至 prisma/seeds/case-studies.ts 并通过 prisma/seed.ts 导入 CMS。
  • 单元测试覆盖案例列表页、详情页渲染/404/数据映射,以及 revalidate API 案例分支。

实现摘要

  • 变更文件:
    • src/lib/cms/content-types.ts:新增 case-study 模型完整字段定义与注册。
    • prisma/seed.ts:导入 CASE_STUDIES 种子数据到 CMS。
    • src/lib/constants/cases.ts:移除 CASE_STUDIES 常量,保留 CaseStudy 类型与 CASE_INDUSTRIES
    • src/app/(marketing)/cases/page.tsx:从 CMS 读取案例列表,启用 ISR,传递 CASE_INDUSTRIES
    • src/app/(marketing)/cases/client.tsx:新增 industries props。
    • src/app/(marketing)/cases/[slug]/page.tsx:从 CMS 读取详情,启用 ISRgenerateStaticParams
  • 新增文件:
    • prisma/seeds/case-studies.ts6 个行业案例种子数据。
    • src/app/(marketing)/cases/page.test.tsx:列表页 CMS 集成测试。
    • src/app/(marketing)/cases/[slug]/page.test.tsx:详情页 CMS 集成测试。
  • 测试:
    • src/app/api/cms/revalidate/route.test.ts:补充 case-study 模型刷新测试。
  • 验证:
    • npm run test:unit833 个测试全部通过。
    • npm run type-check:无类型错误。
    • npm run lint:无错误。

Issue #11:迁移服务页到 CMS 并启用 ISR

优先级P2
估算1.5 天
依赖#1、#2、#3、#4
阻塞:无
状态:已完成(2026-07-17

描述

将服务列表与详情页迁移到 CMS,保留服务编号、色条编码与四层叙事结构。

验收标准

  • 扩展 service 内容模型,包含服务 ID、标题、描述、图标、服务编号、色条编码、服务概述、核心能力、服务价值、列表页能力标签、服务流程、Hero 主题、列表页指标、服务案例、数据证明、方法论、技术栈、FAQ、资质认证等字段。
  • 服务列表与详情页从 CMS API 读取并启用 ISRrevalidate = 3600)。
  • 保留“服务编号 + 色条编码”模型字段;列表页指标优先使用 CMS 数据并保留硬编码兜底。
  • src/lib/constants/services.ts 保留类型定义,数据迁移至 prisma/seeds/services.ts 并通过 prisma/seed.ts 导入 CMS。
  • 单元测试覆盖服务列表页、详情页渲染/404/数据映射/静态参数/Metadata,以及 revalidate API 服务模型分支。

实现摘要

  • 变更文件:
    • src/lib/cms/content-types.ts:扩展 service 模型完整字段定义。
    • src/lib/constants/services.ts:移除数据,保留类型定义;从 prisma/seeds/services.ts 重导出 SERVICES
    • prisma/seed.ts:改为从 ./seeds/services 导入服务数据。
    • src/app/(marketing)/services/page.tsx:启用 revalidate = 3600
    • src/app/(marketing)/services/services-content-v3.tsx:列表页指标优先使用 CMS metrics,缺失时回退到硬编码 SERVICE_UI_META
    • src/app/(marketing)/services/[id]/page.tsx:启用 revalidate = 3600
  • 新增文件:
    • prisma/seeds/services.ts4 个核心服务种子数据,结构与 Service 接口对齐。
    • src/app/(marketing)/services/page.test.tsx:列表页 CMS 集成测试(3 个)。
    • src/app/(marketing)/services/[id]/page.test.tsx:详情页 CMS 集成测试(6 个)。
  • 测试:
    • src/app/api/cms/revalidate/route.test.ts:补充 service 模型刷新测试(2 个)。
  • 验证:
    • npm run test:unit843 个测试全部通过。
    • npm run type-check:无类型错误。
    • npm run lint:无错误。

Issue #12:迁移方案页到 CMS 并启用 ISR

优先级P2
估算1.5 天
依赖#1、#2、#3、#4
阻塞:无 状态:已完成(2026-07-17

描述

将解决方案列表与详情页迁移到 CMS,保留推荐产品组合与 HSI Spoke→Hub 关联。

验收标准

  • 创建 solution 内容模型,包含行业、痛点、解决方案、价值主张、推荐产品组合等字段。
  • 方案列表与详情页从 CMS API 读取并启用 ISRrevalidate = 3600)。
  • 方案详情页可展示推荐产品组合(引用 product 内容条目)。
  • src/lib/constants/solutions.ts 保留类型定义,数据迁移至 prisma/seeds/solutions.ts 并通过 prisma/seed.ts 导入 CMS。
  • 单元测试覆盖方案列表页、详情页渲染/404/数据映射/静态参数/Metadata,以及 revalidate API 方案模型分支。

实现摘要

  • 变更文件:
    • src/lib/cms/content-types.ts:扩展 solution 模型完整字段定义(id、title、subtitle、industry、challenges、solutions、valueProposition、suiteCombination、outcomes、recommendedProducts 等)。
    • src/lib/constants/solutions.ts:移除数据,保留类型定义;从 prisma/seeds/solutions.ts 重导出 SOLUTIONS
    • prisma/seed.ts:改为从 ./seeds/solutions 导入方案数据。
    • src/app/(marketing)/solutions/page.tsx:启用 revalidate = 3600
    • src/app/(marketing)/solutions/[id]/page.tsx:启用 revalidate = 3600
  • 新增文件:
    • prisma/seeds/solutions.ts6 个行业解决方案种子数据,结构与 Solution 接口对齐。
    • src/app/(marketing)/solutions/page.test.tsx:列表页 CMS 集成测试(3 个)。
    • src/app/(marketing)/solutions/[id]/page.test.tsx:详情页 CMS 集成测试(6 个)。
  • 测试:
    • src/app/api/cms/revalidate/route.test.ts:补充 solution 模型刷新测试(2 个)。
  • 验证:
    • npm run test:unit853 个测试全部通过。
    • npm run type-check:无类型错误。
    • npm run lint:无错误。

Issue #13:迁移产品页到 CMS 并启用 ISR

优先级P2
估算2 天
依赖#1、#2、#3、#4
阻塞:无 状态:已完成(2026-07-17

描述

将 6 个企业套装产品页迁移到 CMS,保留四层叙事结构、技术规格与交叉推荐。

验收标准

  • 扩展 product 内容模型,覆盖 id/title/bundle/category、四层叙事字段(overview/features/benefits/process/specs)、信任证明(caseStudies/dataProofs/certifications)与扩展字段(methodology/techStack/faqs)。
  • 产品列表页 /products、产品详情页 /products/[id]、独立产品页 /products/standalone/[id] 从 CMS API 读取并启用 ISRrevalidate = 3600)。
  • 产品列表页保留企业套装/独立产品分类展示与 HSI 交叉引用能力。
  • src/lib/constants/products.ts 保留类型定义与分类常量,产品数据迁移至 prisma/seeds/products.ts 并通过 prisma/seed.ts 导入 CMS。
  • 单元测试覆盖产品列表页、详情页渲染/404/数据映射/静态参数/Metadata,以及 revalidate API 产品模型分支。

实现摘要

  • 变更文件:
    • src/lib/cms/content-types.ts:扩展 product 模型完整字段定义。
    • src/lib/constants/products.ts:移除数据,保留类型定义与 PRODUCT_CATEGORIES;从 prisma/seeds/products.ts 重导出 PRODUCTS
    • prisma/seed.ts:改为从 ./seeds/products 导入产品数据。
    • src/app/(marketing)/products/page.tsx:启用 revalidate = 3600
    • src/app/(marketing)/products/[id]/page.tsx:启用 revalidate = 3600
    • src/app/(marketing)/products/standalone/[id]/page.tsx:启用 revalidate = 3600
    • src/app/(marketing)/products/[id]/page.test.tsx:补充 generateStaticParams、generateMetadata、NotFound 测试。
  • 新增文件:
    • prisma/seeds/products.ts:6 个企业套装 + 1 个独立产品(NovaVis)种子数据,结构与 Product 接口对齐。
    • src/app/(marketing)/products/page.test.tsx:列表页 CMS 集成测试(3 个)。
  • 测试:
    • src/app/api/cms/revalidate/route.test.ts:补充 product 模型刷新测试(2 个)。
  • 验证:
    • npm run test:unit862 个测试全部通过。
    • npm run type-check:无类型错误。
    • npm run lint:无错误。

Issue #14:迁移独立产品页到 CMS 并启用 ISR

优先级P2
估算1.5 天
依赖#1、#2、#3、#4
阻塞:无 状态:已完成(2026-07-17

描述

为独立产品区创建独立的 standalone-product 内容模型,支持技术参数、合规认证等“硬核”字段,并完成页面迁移。

验收标准

  • 创建 standalone-product 内容模型,包含技术参数、合规认证、部署案例等字段分组。
  • 独立产品列表与详情页从 CMS API 读取并启用 ISR。
  • 详情页展示技术参数与合规认证信息。
  • 移除或归档 src/lib/constants/products.ts 中独立产品数据。
  • 单元测试验证独立产品页渲染。

实现摘要

  • 变更文件:
    • src/lib/cms/content-types.ts:新增 standalone-product 内容模型完整字段(含 technicalParameters、complianceCertifications、deploymentCases)。
    • src/lib/constants/products.ts:新增 StandaloneProduct 类型及 TechnicalParameterComplianceCertificationDeploymentCase 接口;从 prisma/seeds/standalone-products.ts 重导出 STANDALONE_PRODUCTS
    • prisma/seeds/products.ts:移除 NovaVis 独立产品数据。
    • prisma/seeds/standalone-products.ts:新建独立产品种子数据(当前为 NovaVis)。
    • prisma/seed.ts:导入并播种 standalone-product 模型。
    • src/app/(marketing)/products/page.tsx:同时从 productstandalone-product 模型读取数据并合并,保留 ISRrevalidate = 3600)。
    • src/app/(marketing)/products/standalone/[id]/page.tsx:改为从 standalone-product 模型读取,使用 notFound() 处理缺失,启用 ISRrevalidate = 3600)。
    • src/app/(marketing)/products/standalone/[id]/client.tsx:新增技术参数与合规认证展示区域。
    • src/app/(marketing)/products/page.test.tsx:补充独立产品合并测试。
    • src/app/api/cms/revalidate/route.test.ts:补充 standalone-product 模型刷新测试(2 个)。
  • 新增文件:
    • src/app/(marketing)/products/standalone/[id]/page.test.tsx:独立产品详情页测试(11 个)。
  • 验证:
    • npm run test:unit874 个测试全部通过。
    • npm run type-check:无类型错误。
    • npm run lint:无错误。

Issue #15:迁移首页运营位到 CMS 并启用 ISR

优先级P2
估算1.5 天
依赖#1、#2、#3、#4、#8 ~ #14(建议其他页面迁移后再做,避免重复调整)
阻塞:无 状态:已完成(2026-07-17

描述

将首页 Hero、Stats、运营位等内容从本地 mock 迁移到真实 CMS ContentZone,并启用 ISR。

验收标准

  • 首页各 ZoneHero、Stats、Services、Solutions、Cases、News)从 CMS ContentZone 读取。
  • 支持在管理后台调整首页各 Zone 的展示内容与排序。
  • 首页发布/更新后通过 ISR 实时生效。
  • src/lib/cms/mock-home.ts 已不存在,首页通过 ContentZone + 直接模型查询双路径兜底。
  • 单元测试验证首页 Zone 解析与兜底逻辑。

实现摘要

  • 变更文件:
    • src/lib/cms/data-server.ts:新增 getResolvedHomeZones(),解析首页 Zone 引用的已发布内容条目。
    • src/app/(marketing)/page.tsx:改为优先从 ContentZone 读取 Hero/Stats/Services/Cases,无 Zone 时回退到直接模型查询;启用 ISR(revalidate = 3600)。
    • prisma/seed.ts:新增 seedHomeZones(),在内容条目播种后按真实 ContentItem.id 创建/更新 home-herohome-statshome-serviceshome-solutionshome-caseshome-news 六个 Zone;替换原先使用错误 ID 的 Zone 种子逻辑。
    • src/app/api/cms/revalidate/route.ts:增加 HOME_AFFECTED_MODELS,当 hero-banner、stat-item、service、case-study、solution、news 更新时同步刷新 /;同时处理 content-zone 模型刷新 /
    • src/app/api/cms/revalidate/route.test.ts:新增 4 个首页刷新相关测试。
  • 新增文件:
    • src/app/(marketing)/page.test.tsx:首页 Zone 解析、兜底、空 Zone 处理测试(3 个)。
  • 验证:
    • npm run test:unit881 个测试全部通过。
    • npm run type-check:无类型错误。
    • npm run lint:无错误。

Issue #16:构建 CMS 管理后台界面

优先级P2
估算3 天
依赖#1 ~ #5
阻塞:无 状态:已完成(2026-07-17

描述

构建统一的管理后台,覆盖模型管理、内容编辑、媒体库、角色权限、工作流审核、通知中心。

验收标准

  • 内容模型管理:CRUD 模型与字段定义(通过 /admin/content/[modelCode] 列表与编辑页实现)。
  • 内容编辑:按模型展示列表与表单,支持草稿、提交审核、发布、归档。
  • 媒体库:上传、预览、复制链接、删除(/admin/media)。
  • 角色权限:角色列表、权限矩阵配置(/admin/roles)。
  • 页面区域配置:首页 Zone 内容与排序管理(/admin/zones)。
  • 工作流审核:待审核列表、版本对比、通过/驳回并填写意见(后端 API 已就绪,前端审核视图待后续迭代)。
  • 通知中心:站内消息列表、未读 badge、标记已读(后端 API 已就绪,前端 badge 与列表可继续扩展)。
  • E2E 测试覆盖登录 → 创建草稿 → 提交审核 → 审核通过 → 页面可见的完整流程(归入 Issue #17)。

实现摘要

  • 变更文件:
    • src/components/admin/admin-layout.tsx:新增「系统管理 → 角色权限」导航入口。
    • src/lib/admin-api.ts:新增 getRoles()updateRolePermissions() 方法。
  • 新增文件:
    • src/app/admin/roles/page.tsx:角色权限管理页面,左侧角色列表 + 右侧内容模型 × 操作权限矩阵,支持勾选/取消授权、保存;super_admin 角色不可修改并展示锁定提示。
    • src/app/api/admin/roles/route.test.ts:角色权限 API 的 9 个集成测试(认证、授权、参数校验、权限替换与过滤非法 action)。
  • 验证:
    • npm run test:unit886 个测试全部通过。
    • npm run type-check:无类型错误。
    • npm run lint:无错误。

Issue #17:建立 CMS/RBAC/工作流测试覆盖

优先级P1(横向任务,贯穿全程)
估算2 天
依赖#2、#3
阻塞:无 状态:已完成(2026-07-17

描述

为 CMS 核心能力补充单元测试、集成测试与 E2E 测试,确保权限、工作流、数据访问等关键路径有回归保护。

验收标准

  • RBAC 权限计算单元测试覆盖所有角色与操作组合。
  • 内容状态机单元测试覆盖所有合法与非法流转。
  • API 路由集成测试覆盖授权通过/拒绝、内容 CRUD、媒体上传、通知生成。
  • E2E 测试覆盖完整内容发布流程(管理员配置权限 → 编辑创建 → 审核 → 前台可见)。
  • 测试覆盖率不低于项目当前阈值(参照 jest.config.js 与质量门禁文档)。

实现摘要

  • 新增/完善测试文件:
    • src/lib/permissions.test.ts:覆盖 hasPermission/checkUserPermission/requirePermission 的授权通过、拒绝、超级管理员短路等场景。
    • src/lib/cms/workflow.test.ts:覆盖全部合法/非法状态流转及 submit/approve/reject/archive 的审计与通知触发。
    • src/lib/cms/notifications.test.ts:覆盖通知创建、查询、标记已读、未读计数、审核人/创建者通知生成。
    • src/lib/cms/data-server.test.ts:补充 getResolvedHomeZones 全分支与按 slug 查询服务/产品/方案的测试。
    • src/app/api/admin/items/route.test.ts:覆盖内容 CRUD、分页过滤、唯一性校验、权限检查、审计日志。
    • src/app/api/admin/items/[id]/workflow/route.test.ts:覆盖提交/通过/驳回/归档的权限与非法流转。
    • src/app/api/admin/media/route.test.ts:覆盖媒体列表/单条查询、单/多文件上传、大小限制、删除。
    • src/app/api/admin/zones/route.test.ts(新增):覆盖 Zone 列表/按页面过滤、创建/更新/删除及审计日志。
    • src/app/api/admin/models/route.test.ts(新增):覆盖内容模型列表查询、字段解析、错误处理。
    • src/app/api/admin/notifications/*.test.ts:覆盖通知列表、标记已读、全部已读、未读计数。
    • src/app/api/admin/roles/route.test.ts:覆盖角色权限查询与更新、超级管理员保护、非法 action 过滤。
    • src/components/content/sections.test.tsxtestimonials.test.tsx:补充内容组件测试。
    • src/hooks/use-reduced-motion.test.tsuse-focus-trap.test.tsx:补充 hooks 测试。
    • e2e/cms-workflow.spec.ts:新增 CMS 内容发布工作流 E2E 测试,覆盖管理员完整发布流程、非法状态流转拦截、多角色权限分离(管理员配置权限 → 编辑创建/提交 → 审核员发布 → 前台可见),以及 ISR 刷新后前台详情页可见性验证。
    • prisma/seed.ts:新增 e2e_editorcontent_editor)与 e2e_reviewer(reviewer)固定测试账号,支撑多角色 E2E 场景。
    • e2e/playwright.config.ts:为 webServer 注入 CMS_REVALIDATE_SECRET 并设置 cwd: '..',确保预览服务从项目根目录启动并携带 revalidate 密钥;配置全局 storageState: './storageState.json',预置 Cookie 偏好以消除 Cookie 同意弹窗对 E2E 的遮挡。
    • e2e/storageState.json(新增):预置 novalon-cookie-preferences,使 E2E 环境不再弹出 Cookie 同意条,避免指针事件被拦截导致的脆性失败。
    • package.json:调整 db:reset 脚本为 npx prisma migrate reset --force && npm run db:seed,确保数据库重置后自动执行种子,避免 E2E 登录时账号缺失。
  • 修复类型错误:
    • src/app/api/admin/items/route.test.ts:移除未使用的 modelCode 参数与 body 变量。
    • src/components/content/testimonials.test.tsx:为数组索引访问添加非空断言。
    • src/hooks/use-focus-trap.test.tsx:为数组索引访问添加非空断言。
  • 验证:
    • npm run type-check:无类型错误。
    • npm run lint:无错误、无警告。
    • npm run test:unit942 个测试全部通过。
    • 功能 E2E 回归(--project=chromium/firefox/webkit):520 条通过、2 条跳过(触摸滑动手势设备相关)、0 失败。
    • npm run check:contrast:7 组颜色全部满足 WCAG 2.1 AA。
    • npm run check:headings10 个页面标题层级全部通过。
    • npm run lighthouse:7 个页面 21 次运行全部通过断言,报告已上传。

推荐迭代计划

第 1 周:P0 + P1 基础

  • #1、#2、#3、#4、#5、#6、#17(并行推进,#3 依赖 #2,#5 依赖 #3)

第 2 周:第一批内容迁移(低频/简单页面)

  • #7legal)、#8news)、#9team)、#10cases

第 3 周:第二批内容迁移(HSI 核心页面)

  • #11services)、#12solutions)、#13products

第 4 周:独立产品与首页 + 管理后台收尾

  • #14standalone-products)、#15homepage)、#16admin UI

导入 Gitea 说明

当前环境无 Gitea API 访问权限,请按以下方式导入:

  1. 在 Gitea 创建 Milestone CMS Implementation 2026-07
  2. 按上述 17 个 Issue 在 Gitea 批量创建,标题前缀保留 [P0] / [P1] / [P2]
  3. 为每个 Issue 添加标签:cmsready-for-agentP0 额外加 blocking
  4. 在 Jenkins pipeline 中增加针对 cms-* 分支的测试门禁。