Files
wagtailcms/documents/设计方案分析与完善版.md
T

24 KiB
Raw Blame History

企业官网 Headless CMS 设计方案 —— 分析与完善版

本文档基于 documents/ 目录下现有的 5 份 PDF 设计文档整理分析,并结合当前代码仓库的真实状态(manage.py + 裸 Django 6.0 项目骨架,尚未引入 Wagtail),产出一份可直接指导开发的完善版设计方案


一、现有文档分析

1.1 文档清单

文档 定位
基于 Wagtail 的现代前后端分离 CMS 设计方案.pdf 通用架构设计(30 章节,最全面)
Next.js + Wagtail 企业级 Headless CMS 完整项目代码架构.pdf Monorepo + 代码架构细化
Wagtail CMS Backend 完整源码(企业级 Headless CMS.pdf 后端代码骨架示例
Next.js 企业官网完整源码模板(基于 Wagtail Headless CMS.pdf 前端代码骨架示例
软件公司企业官网设计方案(基于 Wagtail Headless CMS.pdf 官网 IA / 页面 / 视觉设计
整体设计图.png 首页高保真视觉稿(TechFlow 品牌示例)

1.2 共性结论

5 份文档高度一致地收敛到同一技术选型:Django 5 + Wagtail 7 + DRF + Strawberry GraphQL + Next.js 15 (React 19) + PostgreSQL + Redis + Celery + OpenSearch/Elasticsearch + MinIO/S3 + Docker/K8s。这说明该技术栈选型是合理、成熟的,可以直接作为最终方案基线,不需要重新论证

1.3 已发现的不足 / 待完善点

逐份文档都以"罗列技术名词 + 目录结构"为主,普遍缺少可落地的细节,具体归纳如下:

A. 架构完整性缺口

  1. 只给出多租户"共享库 / Schema 隔离"两个方案名词,未给出本项目该如何取舍(本项目是单一企业官网,暂不需要多租户,过度设计)。
  2. 没有数据库 ER 图 / 字段级设计,Page 模型都只写了 1-2 个示例字段。
  3. 没有 Headless 预览(Preview)机制设计 —— 编辑在 Wagtail 后台点"预览"Next.js 如何展示草稿内容(draft mode / preview token)完全没有提及。
  4. 没有"发布后前端缓存失效"的具体实现(只画了 Content Published → Event Bus → Webhook → Frontend Revalidate 的框图,没有落地到 Wagtail page_published signal + Next.js revalidateTag 的代码级方案)。
  5. API 只给了 URL 列表,没有分页、排序、过滤、错误码、版本弃用策略等规范。

B. 安全设计不落地 6. 安全章节只列了名词(HTTPS/CSP/WAF/JWT Rotation…),没有给出 Django 层面应设置的具体 settings 项(SECURE_HSTS_SECONDSSESSION_COOKIE_SECURECSRF_TRUSTED_ORIGINS、DRF 节流类等)。 7. CORS_ALLOW_ALL_ORIGINS = True 是示例代码里的真实隐患,生产环境必须收敛为白名单。 8. 没有考虑富文本 XSSWagtail RichTextField 需要配置白名单 WAGTAILADMIN_RICH_TEXT_EDITORS / bleach)。

C. 本地化 / 合规缺失(重要) 9. 所有文档默认使用 AWS S3 + Cloudflare CDN + Google 字体生态,但"整体设计图.png"高保真稿明确显示目标是中国大陆企业官网(简体中文导航、"沪ICP备xxxxxxxx号-1"、中国移动/招商银行/中国平安/上汽集团/美团 等客户 Logo)。这是一个关键但被忽视的落地风险:

  • AWS S3/Cloudflare 在中国大陆访问速度和合规性都存在问题,需替换为 阿里云 OSS/腾讯云 COS + 阿里云 CDN/腾讯云 CDN 等国内方案。
  • 网站备案:需要 ICP 备案(个人/企业备案流程、幕布拍照要求等),这会影响上线时间表,必须提前规划。
  • 需要 隐私政策 / Cookie 同意条,遵循《个人信息保护法》(PIPL),而不是文档里默认的 GDPR 话术。
  • Google Fonts / Google Maps 在中国大陆不可用,需要自托管字体(思源黑体/HarmonyOS Sans 子集化)、替换为高德/腾讯地图。
  • 人机验证码建议用极验/腾讯云验证码而非 reCAPTCHA。
  • 表单营销自动化提到 HubSpot/Salesforce,国内客户更常用企业微信 + 探迹/纷享销客等 CRM,需要补充可选国内方案。

D. 工程化缺口 10. 没有测试策略(单元测试、集成测试、E2E),文档提到 pytest 仅在 lint 章节一笔带过。 11. 没有环境变量与密钥管理方案(.env.example、多环境 settings 分层的实际代码)。 12. 没有健康检查 / 就绪探针(/healthz/readyz),K8s 部署缺了这个会导致滚动更新时无法探活。 13. 日志没有约定格式(结构化 JSON 日志 + request-id 贯穿链路),排障困难。

E. 内容建模细节不足 14. StreamField Block 只给了 HeroBlockFeatureBlock 两个例子,官网设计方案里列出的 14 个 BlockStats/CTA/Pricing/FAQ/CaseStudy/Timeline/Team/LogoCloud/TechStack/BlogList/Video/Form 等)都没有代码,容易导致前后端字段不对齐。 15. 没有说明图片如何做响应式(Wagtail Renditions + srcset)与前端 next/image 的对接方式。

1.4 与当前代码仓库现状的差距

当前仓库仅是 django-admin startproject 生成的裸项目(Django 6.0.5,未安装 Wagtail/DRFINSTALLED_APPS 只有 Django 内置应用,urls.py 只有 admin/)。也就是说,目前处于"设计文档阶段",代码尚未开始落地,因此完善设计的同时,应当同步启动 Phase 1 的工程骨架搭建(见本文档第二部分 §18 路线图,以及仓库中已完成的初始化改动)。


二、完善后的整体设计方案

2.1 项目目标

在原有目标基础上明确补充中国大陆本地化与合规目标

  • 面向中国大陆企业客户的现代化 B2B 官网 + Headless CMS 内容中台
  • 前后端彻底分离:Wagtail(内容与 API+ Next.js(展示层)
  • 满足 ICP 备案、PIPL 合规、国内 CDN/存储加速
  • 可平滑演进到多语言(中/英/日)、多站点,暂不做多租户(YAGNI,待 SaaS 化需求明确后再引入 django-tenants
  • 内容编辑体验优先(StreamField 组件化、预览、审核流)

2.2 总体架构

flowchart TB
    subgraph Client
        Browser["浏览器 / 移动端"]
    end
    subgraph Edge["Edge / CDN"]
        CDN["国内 CDN(阿里云 CDN / 腾讯云 CDN"]
    end
    subgraph FE["Next.js 前端(App Router"]
        NextApp["React 19 + SSR/ISR"]
    end
    subgraph Gateway
        Nginx["Nginx / Traefik 网关"]
    end
    subgraph BE["Wagtail 后端"]
        Wagtail["Django 5 + Wagtail 7"]
        DRF["DRF REST v2"]
        GQL["Strawberry GraphQL"]
    end
    subgraph Infra["基础设施"]
        PG[(PostgreSQL)]
        Redis[(Redis)]
        Search[(OpenSearch)]
        OSS[(阿里云 OSS / 腾讯云 COS)]
        Celery["Celery Worker"]
    end

    Browser --> CDN --> NextApp --> Nginx --> Wagtail
    Wagtail --> DRF
    Wagtail --> GQL
    Wagtail --> PG
    Wagtail --> Redis
    Wagtail --> Search
    Wagtail --> OSS
    Wagtail -. 异步任务 .-> Celery
    Wagtail -- "publish webhook" --> NextApp

2.3 技术栈(含国内替代方案对照)

分层 通用方案(原文档) 中国大陆推荐替代 / 补充
对象存储 AWS S3 / MinIO 阿里云 OSS / 腾讯云 COSdjango-storages 均支持 S3 兼容协议)
CDN Cloudflare 阿里云 CDN、腾讯云 CDN、又拍云
字体 Google Fonts 思源黑体 / HarmonyOS Sans,构建期子集化后自托管,避免运行时依赖 Google
地图 Google Maps 高德地图 / 腾讯地图 JS SDK
验证码 reCAPTCHA 极验 GeeTest / 腾讯云验证码
短信/通知 阿里云短信服务 + 企业微信机器人 Webhook(替代 Slack
登录方式(可选) OAuth2/Auth0/Keycloak 保留通用 OAuth2;如需 C 端可加"企业微信扫码登录"
搜索 Elasticsearch/OpenSearch 同左,国内可用阿里云 OpenSearch 托管版或自建
备案 需在页脚展示 ICP 备案号,域名/服务器需完成 ICP 备案后方可上线

其余后端(Django/Wagtail/DRF/GraphQL/PostgreSQL/Redis/Celery)与前端(Next.js/React/Tailwind/Zustand/React Query)技术栈维持原文档选型不变,属于合理选型。

2.4 Monorepo 目录结构(沿用并细化)

wagtailcms/                  # 当前仓库根目录(后端仓库,独立 git 仓库)
├── manage.py
├── requirements/
│   ├── base.txt
│   ├── dev.txt
│   └── production.txt
├── wagtailcms/               # 设置包(实际未按早期草案重命名为 config/,沿用项目同名包)
│   ├── settings/
│   │   ├── base.py
│   │   ├── dev.py
│   │   └── production.py
│   ├── urls.py
│   ├── wsgi.py
│   └── asgi.py
├── apps/
│   ├── core/                # 基础抽象:SEOablePage、健康检查、公共 Block ✅
│   ├── home/                # 首页 ✅
│   ├── blog/                # 技术博客 ✅
│   ├── products/            # 产品 ✅
│   ├── solutions/           # 解决方案(行业)✅
│   ├── cases/                # 客户案例 ✅
│   ├── forms/                # 线索表单 ✅
│   └── api/                  # DRF + Wagtail API v2 路由 ✅
├── documents/                 # 设计文档(当前目录)
└── (frontend/ 已拆分为独立仓库,不在本仓库内,见下方说明)

说明:前后端已拆分为两个独立 git 仓库(后端本仓库 + frontend/ 独立仓库),通过 REST APIWagtail API v2 + /api/v1/custom/)契约解耦。后端根 .gitignore 已排除 frontend/,避免嵌套仓库冲突。两个仓库目前均为本地仓库,尚未配置远程/推送。

2.5 内容模型与数据库设计

在原有 Page + StreamField 思路基础上,补齐字段级设计:

# apps/core/models.py
class SEOablePage(Page):
    """所有业务页面的抽象基类,统一 SEO 字段"""
    seo_title = models.CharField(max_length=70, blank=True)
    seo_description = models.CharField(max_length=160, blank=True)
    og_image = models.ForeignKey(
        "wagtailimages.Image", null=True, blank=True,
        on_delete=models.SET_NULL, related_name="+",
    )
    canonical_url = models.URLField(blank=True)
    schema_json = models.JSONField(blank=True, default=dict)

    promote_panels = Page.promote_panels + [
        FieldPanel("seo_title"),
        FieldPanel("seo_description"),
        FieldPanel("og_image"),
        FieldPanel("canonical_url"),
        FieldPanel("schema_json"),
    ]

    class Meta:
        abstract = True

页面树结构(细化到本项目实际官网 IA):

HomePage
 ├── ProductIndexPage
 │     └── ProductPage[]
 ├── SolutionIndexPage
 │     └── SolutionPage[]
 ├── CaseStudyIndexPage
 │     └── CaseStudyPage[]
 ├── BlogIndexPage
 │     └── BlogPage[]
 ├── AboutPage
 ├── CareerIndexPage
 │     └── CareerPage[]
 └── ContactPage

Snippet(非页面树内容,用于跨页面复用):TeamMemberTestimonialPartner/LogoCloudNavigationMenuSiteSettingsBaseSiteSetting,存放公司电话/ICP备案号/社交账号等全局配置)。

2.6 StreamField 组件体系(补全清单)

Block 用途 关键字段 状态
HeroBlock 首屏 title, subtitle, cta_buttons(list), background_image/video 已实现
StatsBlock 数据展示 items: [{value, label}] 已实现
FeatureGridBlock 能力/优势 icon, title, description 已实现(对应原 FeatureBlock
ProductCardBlock 产品矩阵 title, description, image, link 待开发
LogoCloudBlock 客户 Logo 墙 logos: [{url, title}](暂为图片列表,未接入 Partner Snippet 已实现(简化版)
CaseStudyBlock 案例卡片 case_page: PageChooser(cases.CaseStudyPage), summary 已实现
PricingBlock 定价 plans: [{name, price, features}] 待开发
FAQBlock 常见问题 items: [{question, answer(richtext)}] 已实现
TimelineBlock 发展历程 items: [{year, event}] 待开发
TeamBlock 团队展示 members: [SnippetChooser(TeamMember)] 待开发(依赖 TeamMember Snippet
TechStackBlock 技术架构图 items: [{icon, label}] 待开发
VideoBlock 视频 video_file/embed_url, poster 待开发
FormBlock 线索表单 form: SnippetChooser(forms.FormDefinition)get_api_representation 展开完整字段定义供前端渲染 已实现
CTABlock 行动号召 heading, button_text, button_link 已实现

所有 Block 统一放在 apps/core/blocks.pyCOMMON_BLOCKS,前端 frontend/blocks/BlockRenderer.tsx 维护对应的"type → 组件"映射表,目前两者手动保持一致;CI 自动化一致性校验仍待建立(见 §2.17 风险表)。

2.7 Headless API 设计规范(补全缺失细节)

RESTWagtail API v2 + DRF 自定义)

  • 统一前缀:/api/v2/Wagtail 官方 API v2+ /api/v1/custom/(自定义业务接口,如表单提交)
  • 分页:统一 limit / offset,响应体包含 meta: {total, limit, offset}
  • 排序/过滤:?order=-first_published_at?type=blog.BlogPage
  • 错误响应统一结构:
    { "error": { "code": "NOT_FOUND", "message": "..." } }
    
  • 限流:DRF ScopedRateThrottle,公开只读接口 100/min,表单提交接口 5/min(防刷)
  • 版本弃用策略:新版本上线后旧版本保留至少 2 个发布周期,响应头带 Deprecation / Sunset

预览模式(原文档缺失,重要补充)

  • Wagtail 后台"预览"生成一次性 preview_token(存 RedisTTL 5 分钟)
  • Next.js 提供 /api/draft 路由,校验 token 后开启 Next.js Draft Mode,直接向 Wagtail 请求草稿版本 API?revision=latest

发布后缓存失效(原文档只有框图,这里补齐实现)

# apps/core/signals.py
from wagtail.signals import page_published

@receiver(page_published)
def notify_frontend_revalidate(sender, instance, **kwargs):
    requests.post(
        settings.FRONTEND_REVALIDATE_URL,
        json={"tags": [f"page:{instance.id}", instance.url_path]},
        headers={"Authorization": f"Bearer {settings.REVALIDATE_SECRET}"},
        timeout=3,
    )

Next.js 侧对应 revalidateTag API Route,收到 webhook 后失效对应 ISR 缓存标签。

2.8 权限体系(RBAC 矩阵,细化落地)

角色 页面编辑 提交审核 审批发布 用户管理 Snippet 管理 Django Admin
Super Admin
Tenant/Site Admin (本站点)
Editor
Reviewer 查看 查看
Author (仅自己)
Viewer 查看

落地方式:使用 Wagtail 原生 Group + GroupPagePermission + collections 权限,不需要额外引入 RBAC 框架。

2.9 工作流与内容审核

采用 Wagtail 5+ 内置 Workflow 模块,定义 草稿 → 编辑自检 → 审核 → 通过 → 定时发布,并在 TaskState 变更时通过企业微信机器人 Webhook 通知责任人(替代原文档 Slack 方案)。

2.10 搜索、SEO、多语言

  • 搜索:中文分词是关键缺失点,OpenSearch 需配置 IK 分词插件(原文档完全没提中文分词,这是国内落地必须解决的问题)。
  • SEO:站点级 sitemap.xmlwagtail.contrib.sitemaps+ 页面级 schema_jsonJSON-LD+ robots.txt 动态生成。
  • 多语言:WAGTAIL_I18N_ENABLED + wagtail-localizeURL 采用 /zh//en/ 前缀,默认 /zh/ 对国内用户免前缀(根路径直接是中文)。

2.11 安全设计(落地到具体配置)

# config/settings/production.py
SECURE_SSL_REDIRECT = True
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
SECURE_HSTS_SECONDS = 31536000
SECURE_HSTS_INCLUDE_SUBDOMAINS = True
SECURE_CONTENT_TYPE_NOSNIFF = True
X_FRAME_OPTIONS = "DENY"
# 阿里云 SLB / 腾讯云 CLB 等负载均衡在边缘终止 TLS 时,需要此项避免 SECURE_SSL_REDIRECT 死循环重定向
SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")
CORS_ALLOWED_ORIGINS = env.list("CORS_ALLOWED_ORIGINS", default=[])
CSRF_TRUSTED_ORIGINS = env.list("CSRF_TRUSTED_ORIGINS", default=[])

REST_FRAMEWORK = {
    "DEFAULT_THROTTLE_CLASSES": ["rest_framework.throttling.ScopedRateThrottle"],
    "DEFAULT_THROTTLE_RATES": {"public": "100/min", "forms": "5/min"},
}

富文本安全:WAGTAILADMIN_RICH_TEXT_EDITORS 限定可用 feature(禁用危险 HTML embed),后端渲染前统一走 bleach 白名单清洗。

白名单配置说明(三者含义不同,勿混淆):

  • ALLOWED_HOSTS:填后端自身域名(如 cms.example.com),校验 HTTP Host 头,防 Host 头注入。
  • CORS_ALLOWED_ORIGINS:填 Next.js 前端域名(如 https://www.example.com),允许浏览器跨域调用 Wagtail REST API/api/v1/custom/leads/ 为匿名公开接口,仅受此白名单 + 限流保护,不受 CSRF 校验。
  • CSRF_TRUSTED_ORIGINS:仅在"浏览器带 session Cookie 发起跨站不安全请求"时生效(如已登录编辑者调用需认证的预览/管理接口),填涉及认证态跨域请求的域名。
  • 三者均通过 .env 中的 ALLOWED_HOSTS/CORS_ALLOWED_ORIGINS/CSRF_TRUSTED_ORIGINS 环境变量注入,部署时按实际域名填写即可,无需改代码(参见 .env.example)。

2.12 可观测性与运维

  • 健康检查:/healthz(存活)、/readyz(含数据库/Redis 连通性检查),供 K8s liveness/readiness 探针使用。
  • 日志:structlog 输出 JSON,贯穿 request_id(中间件生成,透传前端 X-Request-Id)。
  • 监控:Prometheus + Grafanadjango-prometheus),错误监控 Sentry,链路追踪 OpenTelemetry。

2.13 测试策略(原文档缺失,新增)

层级 工具 覆盖内容
单元测试 pytest + pytest-django + factory_boy Model、Block、Serializer
集成测试 pytest + DRF APIClient API 端到端响应结构
前端组件测试 Vitest + React Testing Library Block 组件渲染
E2E Playwright 关键转化路径(首页 → 联系我们 → 表单提交)
契约测试 schemathesis(基于 OpenAPI schema 防止后端 API 破坏性变更

CI 中要求单元测试覆盖率不低于 70%,核心 apps/forms(涉及线索转化)不低于 90%。

2.14 CI/CD 与环境管理

  • .env.example 统一列出所有必需环境变量,密钥类使用 GitHub Actions Secrets / 云厂商 KMS,不进仓库。
  • 分支策略:main(生产)/ staging(预发)/ 功能分支 PR,合并前必须通过 Lint + Test + Build。
  • 部署流水线:Lint → Test → Build Image → 推送镜像仓库(阿里云 ACR/腾讯云 TCR)→ 部署 K8s(或轻量场景用 Docker Compose + 云服务器)

2.15 合规与本地化清单(新增,落地检查表)

  • 完成 ICP 备案(域名 + 服务器均已在国内云厂商完成备案)
  • 页脚展示备案号并链接工信部备案查询(frontend/components/layout/Footer.tsx,实际备案号 冀ICP备2025130506号-1
  • 隐私政策内容已上线(apps.core.SimpleContentPage 通用富文本内容页模型 + seed_privacy_policy 管理命令 + 前端 /privacy-policy 页面 + 页脚链接,内容覆盖 PIPL 要求的收集目的/用途/用户权利/Cookie 说明等)
  • Cookie 同意条控件(frontend/components/layout/CookieConsent.tsx"use client" 组件,首次访问展示"接受/拒绝"横幅,选择结果存入 localStorage,已挂载到根 layout
  • 字体/地图/验证码/CDN 均替换为可在国内正常访问的服务
  • 表单收集的个人信息需明确告知用途并支持删除请求(PIPL 数据主体权利)

2.16 开发路线图(对齐当前仓库状态)

阶段 目标 状态
Phase 0 需求与设计文档完善(本文档) 已完成
Phase 1 Wagtail 基础 CMS + REST API + Next.js 首页渲染 + 基础 SEO 🚧 进行中(进度见下方清单)
Phase 2 GraphQL、OpenSearch 中文搜索、工作流审核、多语言 待规划
Phase 3 AI 能力(摘要/翻译/SEO 重写)、SaaS 化评估(视业务需要再决定是否引入多租户) 待规划

Phase 1 详细进度:

已完成:

  • 后端 Django + Wagtail 项目骨架,分层 settingsbase/dev/production),独立 git 仓库并已提交
  • apps/coreSEOablePage 抽象基类、COMMON_BLOCKS9/14 个 Block,见 §2.6)、健康检查 /healthz /readyz、发布后 page_published signal → 前端 revalidate webhook
  • apps/homeapps/blog(含标签 ClusterTaggableManager
  • apps/productsProductIndexPage/ProductPage)、apps/casesCaseStudyIndexPage/CaseStudyPage)、apps/solutionsSolutionIndexPage/SolutionPage
  • apps/formsFormDefinition/FormDefinitionField/LeadSnippet 方式)+ 提交 API/api/v1/custom/leads/,限流 + 邮件通知)
  • Wagtail API v2 挂载、分页/过滤/排序(Wagtail 内置)
  • Next.js 前端脚手架(独立仓库):Header/Footer/layout、首页、博客/产品/案例/解决方案列表与详情页、BlockRenderer、ISR + revalidate routelint/build 已验证通过
  • pytest 基础测试框架(pytest-django + factory_boy):pytest.ini + conftest.pyroot_page/home_page fixtures),为 apps/coreSEOablePage 字段、FormBlock API 表示、SimpleContentPage 页面树)、apps/productsapps/casesapps/forms(线索提交 API)编写了基础单元测试,共 11 个用例均通过
  • apps/core.SimpleContentPage:通用富文本法务/说明类页面模型,用于隐私政策等内容,配套 seed_privacy_policy management command 用于幂等创建/更新隐私政策页面(需在 HomePage 实例存在后手动运行)

未完成(待规划排期):

  • SnippetTeamMember/Testimonial/Partner/NavigationMenu/SiteSettingsBaseSiteSetting)均未创建
  • 预览模式(Wagtail preview_token + Next.js Draft Mode)未实现
  • 剩余 5 个 StreamField BlockPricing/Timeline/Team/TechStack/Video/ProductCard)未开发
  • RBAC 落地(Wagtail Group + GroupPagePermission 实际配置)未开始
  • 测试覆盖率仍不完整(已有基础单元测试,但集成测试、前端组件测试、E2E 均未编写,当前无 CI 流水线)
  • 生产安全 settings(§2.11 中 SECURE_*/CORS/CSRF 白名单等)已在 production.py 中逐项落实,并补充 SECURE_PROXY_SSL_HEADER(适配国内云厂商 SLB/CLB 边缘终止 TLS 场景);实际域名需在部署时通过 .env 填入
  • ICP 备案、页脚备案号展示、隐私政策内容、Cookie 同意条控件均已完成(详见 §2.15),合规清单剩余"字体/地图/验证码/CDN 国内可访问"与"表单 PIPL 数据删除权支持"两项
  • 中文分词、OpenSearch 集成(Phase 2 提前项)未开始

2.17 风险与备选方案

风险 应对
过早引入多租户/微服务导致过度设计 Phase 1/2 保持 Monolith,指标驱动再拆分
国内备案周期拖慢上线(通常 7-20 个工作日) 项目启动即刻同步提交备案,不等开发完成
Elasticsearch/OpenSearch 中文分词效果不佳 提前验证 IK 分词插件,或评估阿里云开放搜索托管方案
StreamField Block 前后端字段不一致 建立 Block Schema 自动化一致性校验(CI)