Files
novalon-website/docs/superpowers/specs/2026-07-17-cms-implementation-prd.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

12 KiB
Raw Blame History

PRDNovalon 轻量 Headless CMS 建设与内容全量迁移

本 PRD 基于 grilling 会话(docs/cms-evaluation.md)与 ADR-0007 整理而成。

Problem Statement

Novalon 官网目前存在两层脱节:

  1. CMS 数据层已建,但页面未切换src/lib/cms/ 已定义 ContentModelContentItemContentZoneMediaAssetAuditLog 等类型,/api/cms/*/api/admin/* 路由也已存在,但所有营销页面仍从 src/lib/constants/*.ts 读取内容。内容更新必须改代码、走构建、再部署,市场/运营人员无法自主维护。
  2. 部署模式口径不一致README.md 仍称项目为“纯静态网站”,但 next.config.mjs 已移除 output: 'export' 并存在 /api/cms/revalidate/api/cms/draft/* 等假设服务端运行的路由。团队对是否采用混合渲染(SSR/ISR)缺乏统一决策,导致 CMS 的实时预览、一键发布、版本回滚等能力无法落地。
  3. 权限与工作流未实现:类型中虽有 ContentStatusAuditLog,但缺少 RBAC 中间件、角色模型和“提交 → 审核 → 发布”的状态流转,review 状态实际是死状态。
  4. 媒体管理停留在类型层面MediaAsset 预留了 local | oss | s3 枚举,但无上传接口、无缩略图/格式转换、无 OSS 对接,媒体文件仍散落在 public/

结果是:官网内容运营效率低、协作流程不规范、CMS 投资无法产生实际价值。

Solution

在现有 src/lib/cms/ + Prisma + Next.js API 基础上,建设一个字段可配置、RBAC 模型+操作级、多语言预留、支持本地+OSS 双写、具备最简工作流的轻量 Headless CMS。配合已确认的**混合渲染(SSR/ISR)**部署模式,实现内容实时发布、草稿预览、版本回滚。

内容按页面类型全量迁移到 CMSlegal → news → team → cases → services → solutions → products → standalone-products → homepage zones,逐步废弃对应 src/lib/constants/*.ts 数据。

User Stories

系统管理员

  1. 作为系统管理员,我希望为不同用户分配角色(super_admin / content_admin / content_editor / reviewer / readonly),以便控制谁能操作哪些内容。
  2. 作为系统管理员,我希望按“角色 × 内容模型 × 操作(create/read/update/delete/publish)”配置权限矩阵,以便实现“编辑能写新闻但不能发布产品”这类需求。
  3. 作为系统管理员,我希望在管理后台查看操作日志(AuditLog),以便追踪内容变更与状态流转。
  4. 作为系统管理员,我希望为内容模型启用/禁用版本控制,以便灵活控制哪些模型需要保留历史版本。

内容编辑

  1. 作为内容编辑,我希望在管理后台创建和编辑新闻、案例、团队、产品、方案、服务、法律页等内容,而不需要修改代码。
  2. 作为内容编辑,我希望将内容保存为草稿,以便在正式发布前反复修改。
  3. 作为内容编辑,我希望将完成的内容提交审核,以便进入发布流程。
  4. 作为内容编辑,我希望收到审核结果通知(站内消息),以便知晓内容是否通过或需要修改。
  5. 作为内容编辑,我希望在内容被驳回后能看到驳回原因,并重新编辑提交。
  6. 作为内容编辑,我希望在媒体库上传图片并自动获得缩略图/WebP/AVIF 派生格式链接,以便在内容中引用优化后的图片。
  7. 作为内容编辑,我希望为同一个内容条目预留多语言字段(当前默认 zh-CN),以便未来扩展其他语言时无需重构。

内容审核员

  1. 作为审核员,我希望在管理后台看到所有待审核内容的列表和 badge,以便快速定位需要处理的内容。
  2. 作为审核员,我希望查看内容的完整版本差异(before/after),以便做出准确的审核判断。
  3. 作为审核员,我希望通过或驳回待审核内容,并填写审核意见,以便内容进入发布或回退到编辑状态。
  4. 作为审核员,我希望只有具备 publish 权限的人才能将内容发布到线上,以便保证内容质量。

网站访客

  1. 作为网站访客,我希望在内容发布后即刻看到最新内容(通过 ISR),而无需等待全站构建。
  2. 作为网站访客,我希望访问的法律条款、隐私政策等页面始终是最新版本,以便获取准确信息。
  3. 作为网站访客,我希望在移动端和桌面端都能正常浏览 CMS 驱动的内容,以便获得一致的响应式体验。

开发者/运维

  1. 作为开发者,我希望 CMS API 返回类型安全的数据结构,以便前端组件可靠渲染。
  2. 作为开发者,我希望内容发布后通过 /api/cms/revalidate 刷新 ISR 缓存,以便前端页面自动更新。
  3. 作为开发者,我希望草稿预览通过 Draft Mode 实现,以便编辑和审核人员在正式发布前验证页面效果。
  4. 作为运维,我希望媒体文件在开发/测试环境存储在本地,在生产环境写入 OSS/S3,以便降低本地开发成本并保证生产性能。
  5. 作为运维,我希望 Nginx 配置正确代理 SSR/ISR/API 请求到 Next.js 服务,以便混合渲染架构正常运行。
  6. 作为开发者,我希望为权限中间件、数据访问层、API 路由编写单元和集成测试,以便在持续迭代中防止回归。

Implementation Decisions

1. 部署模式:混合渲染(SSR/ISR)

  • 营销展示页面默认使用 SSG + ISR,CMS 内容发布后调用 /api/cms/revalidate 刷新缓存。
  • 管理后台、认证、CMS API、联系表单等使用 SSR/API Routes。
  • 草稿预览通过 Next.js Draft Mode 实现,由 /api/cms/draft/enable/api/cms/draft/disable 控制。
  • 该决策已记录于 ADR-0007。

2. CMS 路线:坚持自研轻量 Headless CMS

  • 基于现有 src/lib/cms/ + Prisma + Next.js API 继续建设。
  • 不引入 Strapi、Payload、Directus 等开源方案,也不采购 SaaS CMS。
  • 核心范围限定为:数据模型扩展、RBAC、媒体管理、最简工作流、内容迁移、管理后台界面。

3. 数据模型扩展

3.1 ContentItem 增加 locale 字段

  • 默认值为 'zh-CN'
  • 为存在 slug 的模型增加唯一索引 (slug, modelCode, locale),保证同一模型同语言下 slug 唯一。
  • 多语言内容通过新增 locale 记录实现,不改动现有字段结构。

3.2 RBAC 数据模型

  • Rolesuper_admin、content_admin、content_editor、reviewer、readonly。
  • Permission:角色 × 内容模型 × 操作(create / read / update / delete / publish)。
  • 用户与角色多对多关联。
  • /api/admin/* 路由增加权限中间件,拒绝未授权请求。

权限矩阵示例(来自 grilling 决策):

角色 news product legal
content_editor create/read/update read read
reviewer read/publish read/publish read/publish
readonly read read read

3.3 review 状态语义

  • review = 已提交待审核。
  • 仅拥有对应模型 publish 权限的角色可以审核通过(进入 published)或驳回(回到 draft)。
  • 状态流转:draft → review → published → archiveddraft → review → draft(驳回)。

4. 媒体管理模块

  • 完成 /api/admin/media 上传接口。
  • 本地环境/测试落盘到 public/uploads/;生产环境写入 OSS/S3。
  • 上传后生成缩略图、WebP、AVIF 派生格式;MediaAsset 记录原图与所有派生格式 URL。
  • 存储类型枚举沿用现有 local | oss | s3

5. 工作流引擎(最简版)

  • 状态机仅支持 draft → review → published / archived,驳回回 draft
  • 站内消息通知:审核人收到待审核 badge,提交人收到审核通过/驳回通知。
  • AuditLog 记录每次状态流转的 before/after、操作人、时间戳。
  • 不实现邮件、企业微信、钉钉等外部通知。

6. 内容迁移策略

  • 按页面类型全量迁移,顺序为:legal → news → team → cases → services → solutions → products → standalone-products → homepage zones。
  • 每个页面类型迁移时,同步废弃 src/lib/constants/*.ts 中对应数据,改为从 CMS API 获取。
  • 页面侧使用 ISR,发布/回滚后调用 /api/cms/revalidate
  • 独立产品(standalone-products)需要单独设计 standalone-product 内容模型,支持技术参数、合规认证等字段分组。

7. 管理后台界面

  • 模型管理:CRUD 内容模型与字段定义。
  • 内容编辑:按模型展示列表与表单,支持草稿、提交审核、发布。
  • 媒体库:上传、预览、复制链接、删除。
  • 角色权限:角色列表、权限矩阵配置。
  • 工作流审核:待审核列表、版本对比、通过/驳回。
  • 通知中心:站内消息列表与 badge。

8. API 契约

  • 保持现有 /api/admin/*/api/cms/* 路由结构。
  • 新增 /api/admin/media 用于媒体上传与管理。
  • 新增 /api/admin/roles/api/admin/permissions 用于 RBAC 配置。
  • 新增 /api/admin/notifications 用于站内消息。
  • /api/cms/revalidate 接收 pathtag 参数,刷新 ISR 缓存。
  • /api/cms/draft/* 继续用于 Draft Mode 启停。

Testing Decisions

测试原则

  • 只测外部行为,不测实现细节。例如:测试“未授权用户不能发布新闻”,而不是测试权限中间件的内部判断逻辑。
  • 优先复用现有测试基础设施:Jest 用于单元/集成测试,Playwright 用于 E2E。

测试接缝

  1. 数据访问层src/lib/cms/data-server.ts 中的增删改查函数。
  2. 权限中间件:在 /api/admin/* 路由上的授权行为。
  3. API 路由/api/admin/content/*/api/admin/media/api/cms/revalidate 的响应状态与数据。
  4. 管理后台界面Playwright 覆盖登录 → 创建草稿 → 提交审核 → 审核通过 → 页面可见的完整流程。

具体测试覆盖

  • 单元测试:RBAC 权限计算、状态机流转、媒体元数据生成、locale 唯一索引校验。
  • 集成测试:带权限中间件的 API 路由、Prisma 事务与回滚、ISR revalidate 调用。
  • E2E 测试
    • 管理员创建角色并分配权限;
    • 编辑登录后创建新闻草稿并提交审核;
    • 审核人登录后通过新闻;
    • 前台新闻页面在 revalidate 后显示新内容;
    • 未授权用户尝试发布内容被 403。

现有参考

  • src/lib/cms/data-server.test.ts 已存在 CMS 数据层测试,可扩展覆盖 locale 与 RBAC 相关场景。
  • e2e/ 目录已有 Playwright 配置与测试,可新增 CMS 管理后台流程测试。

Out of Scope

  1. 字段级权限:本期只实现模型级 + 操作级 RBAC,字段级权限作为未来扩展预留。
  2. 外部通知:不实现邮件、企业微信、钉钉等工作流通知,仅保留站内消息。
  3. 内容日历与任务分配:不实现排期、指派、协作看板等高级 CMS 功能。
  4. 表单/线索统一管理:联系表单继续由独立 /api/contact/* 处理,本期不纳入 CMS。
  5. 多语言前端切换:虽然预留 locale 字段,但本期不实现语言切换 UI 与多语言内容录入,仅保证数据模型可扩展。
  6. 替换开源/SaaS CMS:本期坚持自研,不引入 Strapi、Payload、Sanity 等第三方 CMS。
  7. 字段级版本历史:版本控制到内容条目级别,不细化到单个字段。

Further Notes

  • 风险:全量迁移工作量较大,可能挤压 7 月其他任务。缓解措施是按 P0 → P1 → P2 分阶段交付,内容迁移可逐页面进行。
  • 风险:混合渲染对 Nginx 配置提出新要求。缓解措施是更新 nginx-static-production.conf,确保 /api/*/admin/* 及动态路由正确代理到 Next.js 服务。
  • 风险:SQLite 高并发写入可能成为瓶颈。当前后台管理并发低,可接受;未来可平滑迁移至 PostgreSQL,数据模型无需改动。
  • 参考文档: