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

196 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# PRDNovalon 轻量 Headless CMS 建设与内容全量迁移
> 本 PRD 基于 grilling 会话(docs/cms-evaluation.md)与 ADR-0007 整理而成。
## Problem Statement
Novalon 官网目前存在两层脱节:
1. **CMS 数据层已建,但页面未切换**`src/lib/cms/` 已定义 `ContentModel``ContentItem``ContentZone``MediaAsset``AuditLog` 等类型,`/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. **权限与工作流未实现**:类型中虽有 `ContentStatus``AuditLog`,但缺少 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. 作为系统管理员,我希望为内容模型启用/禁用版本控制,以便灵活控制哪些模型需要保留历史版本。
### 内容编辑
5. 作为内容编辑,我希望在管理后台创建和编辑新闻、案例、团队、产品、方案、服务、法律页等内容,而不需要修改代码。
6. 作为内容编辑,我希望将内容保存为草稿,以便在正式发布前反复修改。
7. 作为内容编辑,我希望将完成的内容提交审核,以便进入发布流程。
8. 作为内容编辑,我希望收到审核结果通知(站内消息),以便知晓内容是否通过或需要修改。
9. 作为内容编辑,我希望在内容被驳回后能看到驳回原因,并重新编辑提交。
10. 作为内容编辑,我希望在媒体库上传图片并自动获得缩略图/WebP/AVIF 派生格式链接,以便在内容中引用优化后的图片。
11. 作为内容编辑,我希望为同一个内容条目预留多语言字段(当前默认 zh-CN),以便未来扩展其他语言时无需重构。
### 内容审核员
12. 作为审核员,我希望在管理后台看到所有待审核内容的列表和 badge,以便快速定位需要处理的内容。
13. 作为审核员,我希望查看内容的完整版本差异(before/after),以便做出准确的审核判断。
14. 作为审核员,我希望通过或驳回待审核内容,并填写审核意见,以便内容进入发布或回退到编辑状态。
15. 作为审核员,我希望只有具备 publish 权限的人才能将内容发布到线上,以便保证内容质量。
### 网站访客
16. 作为网站访客,我希望在内容发布后即刻看到最新内容(通过 ISR),而无需等待全站构建。
17. 作为网站访客,我希望访问的法律条款、隐私政策等页面始终是最新版本,以便获取准确信息。
18. 作为网站访客,我希望在移动端和桌面端都能正常浏览 CMS 驱动的内容,以便获得一致的响应式体验。
### 开发者/运维
19. 作为开发者,我希望 CMS API 返回类型安全的数据结构,以便前端组件可靠渲染。
20. 作为开发者,我希望内容发布后通过 `/api/cms/revalidate` 刷新 ISR 缓存,以便前端页面自动更新。
21. 作为开发者,我希望草稿预览通过 Draft Mode 实现,以便编辑和审核人员在正式发布前验证页面效果。
22. 作为运维,我希望媒体文件在开发/测试环境存储在本地,在生产环境写入 OSS/S3,以便降低本地开发成本并保证生产性能。
23. 作为运维,我希望 Nginx 配置正确代理 SSR/ISR/API 请求到 Next.js 服务,以便混合渲染架构正常运行。
24. 作为开发者,我希望为权限中间件、数据访问层、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 数据模型
- `Role`super_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` 接收 `path``tag` 参数,刷新 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,数据模型无需改动。
- 参考文档:
- [docs/cms-evaluation.md](../../cms-evaluation.md)
- [docs/adr/0007-hybrid-rendering-for-cms.md](../../adr/0007-hybrid-rendering-for-cms.md)
- [CONTEXT.md](../../../../CONTEXT.md)
- [CLAUDE.md](../../../../CLAUDE.md)