同步工作区剩余变更,主要包括: - 营销页面组件与布局持续优化(about/news/services/solutions/team 等) - 详情页四层叙事组件、布局组件、UI 组件调整 - CMS 数据模型、API 路由、权限、工作流、站内通知、媒体管理扩展 - 新增/补充单元测试与 E2E 测试(cms-workflow.spec.ts 等) - ESLint 9 迁移、jest/tsconfig 配置更新、依赖调整 - 新增 ADR、CMS 评估文档、Release Review / Acceptance 报告 - 移除水墨装饰组件与大体积未使用字体文件
37 KiB
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.prisma、prisma/seed.ts、src/lib/cms/types.ts、src/lib/cms/data-server.ts、src/lib/cms/data-server.test.ts - 新增 migration:
prisma/migrations/20260717034113_add_locale_to_content_item/ - 验证:
npm run type-check、npm run lint、npm run test:unit全部通过
Issue #2:实现 RBAC 数据模型与 /api/admin/* 权限中间件
优先级:P0
估算:1.5 天
依赖:无
阻塞:#3、#5、#16、#17
描述
建立角色与权限数据模型,并在所有 /api/admin/* 路由上增加权限中间件,实现“角色 × 内容模型 × 操作”矩阵。
验收标准
- Prisma schema 新增
Role、Permission、UserRole三个模型。 - 内置 5 个角色:
super_admin、content_admin、content_editor、reviewer、readonly。 - 权限操作粒度:
create、read、update、delete、publish。 - 所有
/api/admin/*路由在请求处理前检查当前用户权限,无权限返回 403。 - 提供初始化/种子脚本为默认管理员分配
super_admin角色。 - 单元测试覆盖:授权通过、未授权拒绝、模型级权限隔离。
实现摘要
- 变更文件:
prisma/schema.prisma、prisma/seed.ts、src/lib/permissions.ts、src/lib/permissions.test.ts、src/app/api/admin/items/route.ts、src/app/api/admin/zones/route.ts - 新增 migration:
prisma/migrations/20260717035951_add_rbac_models/ - 验证:
npm run type-check、npm run lint、npm run test:unit全部通过
Issue #3:实现内容状态机与工作流基础 ✅
优先级:P0
估算:1.5 天
依赖:#2
阻塞:#5、#7 ~ #16、#17
描述
明确 review 状态语义并落地最简工作流:内容可提交审核,具备 publish 权限的角色可通过或驳回。AuditLog 记录每次状态流转。
验收标准
- 状态流转合法路径:
draft → review → published、draft → 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.ts:PUT 不再接受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.ts:LocalStorageProvider、S3StorageProvider与getStorageProvider工厂。src/lib/media/media-service.ts:上传、删除、查询、分页服务层。src/lib/media/*.test.ts:图片处理、存储、服务层单元测试。src/app/api/admin/media/route.test.ts:API 路由集成测试。
- 变更文件:
prisma/schema.prisma:MediaAsset增加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.sql:Notification 表迁移。src/lib/cms/notifications.ts:通知服务(创建、查询、标记已读、未读计数、按权限查找用户、通知审核人/创建人)。src/lib/cms/notifications.test.ts:通知服务 14 个单元测试。src/app/api/admin/notifications/route.ts:GET 查询当前用户通知列表。src/app/api/admin/notifications/route.test.ts:列表 API 6 个集成测试。src/app/api/admin/notifications/[id]/read/route.ts:PATCH 标记单条已读。src/app/api/admin/notifications/[id]/read/route.test.ts:4 个集成测试。src/app/api/admin/notifications/read-all/route.ts:PATCH 全部标记已读。src/app/api/admin/notifications/read-all/route.test.ts:3 个集成测试。src/app/api/admin/notifications/unread-count/route.ts:GET 未读数量。src/app/api/admin/notifications/unread-count/route.test.ts:3 个集成测试。
- 变更文件:
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 - 主要改动:
- 新增
upstream nextjs_app { server novalon-website:3000; },指向运行next start的 Next.js 服务。 - 新增全局反向代理头(Host、X-Forwarded-*、WebSocket Upgrade 映射)。
- 新增
location /api/:无缓存,代理到 Next.js(覆盖 CMS API、联系表单、认证)。 - 新增
location /admin/:代理到 Next.js,Cookie 透传支持 Draft Mode 预览。 - 新增
location /uploads/:为本地媒体存储提供长期缓存。 - 更新
location /:使用try_files ... @nextjs,静态 HTML 优先,未命中回源 Next.js。 - 新增 named location
@nextjs:ISR/SSR/动态路由回源。 - 删除重复的
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。
回滚步骤:
- 还原
nginx-static-production.conf到上一个 git 版本:git checkout HEAD~1 -- nginx-static-production.conf - 重新加载 Nginx:
nginx -t && nginx -s reload - 停止或隔离 Next.js 运行时服务(可选;若未部署则不依赖)。
- 验证
/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.ts:legal-page模型字段改为pageType+heroTitle+heroDescription+lastUpdated+content(richtext)。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:unit:834 个测试全部通过。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 读取,使用 ISR(
revalidate = 3600)。 - 封面图字段为
image类型,已可关联MediaAsset。 src/lib/constants/news.ts保留类型定义,数据通过prisma/seed.ts导入 CMS。- 单元测试覆盖:列表页 CMS 映射、详情页渲染/404/相关新闻/Metadata/
generateStaticParams。
实现摘要
- 变更文件:
src/lib/cms/content-types.ts:news模型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.ts:news模型通过已有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:unit:844 个测试全部通过。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 读取并启用 ISR(
revalidate = 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:unit:833 个测试全部通过。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 读取并启用 ISR(
revalidate = 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:新增industriesprops。src/app/(marketing)/cases/[slug]/page.tsx:从 CMS 读取详情,启用 ISR,generateStaticParams。
- 新增文件:
prisma/seeds/case-studies.ts:6 个行业案例种子数据。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:unit:833 个测试全部通过。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 读取并启用 ISR(
revalidate = 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:列表页指标优先使用 CMSmetrics,缺失时回退到硬编码SERVICE_UI_META。src/app/(marketing)/services/[id]/page.tsx:启用revalidate = 3600。
- 新增文件:
prisma/seeds/services.ts:4 个核心服务种子数据,结构与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:unit:843 个测试全部通过。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 读取并启用 ISR(
revalidate = 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.ts:6 个行业解决方案种子数据,结构与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:unit:853 个测试全部通过。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 读取并启用 ISR(revalidate = 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:unit:862 个测试全部通过。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类型及TechnicalParameter、ComplianceCertification、DeploymentCase接口;从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:同时从product与standalone-product模型读取数据并合并,保留 ISR(revalidate = 3600)。src/app/(marketing)/products/standalone/[id]/page.tsx:改为从standalone-product模型读取,使用notFound()处理缺失,启用 ISR(revalidate = 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:unit:874 个测试全部通过。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。
验收标准
- 首页各 Zone(Hero、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-hero、home-stats、home-services、home-solutions、home-cases、home-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:unit:881 个测试全部通过。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:unit:886 个测试全部通过。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.tsx、testimonials.test.tsx:补充内容组件测试。src/hooks/use-reduced-motion.test.ts、use-focus-trap.test.tsx:补充 hooks 测试。e2e/cms-workflow.spec.ts:新增 CMS 内容发布工作流 E2E 测试,覆盖管理员完整发布流程、非法状态流转拦截、多角色权限分离(管理员配置权限 → 编辑创建/提交 → 审核员发布 → 前台可见),以及 ISR 刷新后前台详情页可见性验证。prisma/seed.ts:新增e2e_editor(content_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:unit:942 个测试全部通过。- 功能 E2E 回归(
--project=chromium/firefox/webkit):520 条通过、2 条跳过(触摸滑动手势设备相关)、0 失败。 npm run check:contrast:7 组颜色全部满足 WCAG 2.1 AA。npm run check:headings:10 个页面标题层级全部通过。npm run lighthouse:7 个页面 21 次运行全部通过断言,报告已上传。
推荐迭代计划
第 1 周:P0 + P1 基础
- #1、#2、#3、#4、#5、#6、#17(并行推进,#3 依赖 #2,#5 依赖 #3)
第 2 周:第一批内容迁移(低频/简单页面)
- #7(legal)、#8(news)、#9(team)、#10(cases)
第 3 周:第二批内容迁移(HSI 核心页面)
- #11(services)、#12(solutions)、#13(products)
第 4 周:独立产品与首页 + 管理后台收尾
- #14(standalone-products)、#15(homepage)、#16(admin UI)
导入 Gitea 说明
当前环境无 Gitea API 访问权限,请按以下方式导入:
- 在 Gitea 创建 Milestone
CMS Implementation 2026-07。 - 按上述 17 个 Issue 在 Gitea 批量创建,标题前缀保留
[P0]/[P1]/[P2]。 - 为每个 Issue 添加标签:
cms、ready-for-agent,P0 额外加blocking。 - 在 Jenkins pipeline 中增加针对
cms-*分支的测试门禁。