Files
cms-website/SiteForge_主题与板块设计方案_V1.0.md
浅念 d60123ba41 docs: SiteForge 规划文档基线 + 纵向切片设计规格 V1
- V3.0 总体方案、主题与板块设计、实施计划
- cms 现状差距分析 V2.0(V1.0 已标注作废)与复用评估 V1.0
- 纵向切片设计规格(路线 C:全新架构 + 白名单资产移植)
- .gitignore 先行(storage/artifacts/env 永不入库)

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-20 16:10:34 +08:00

26 KiB
Raw Permalink Blame History

SiteForge 主题与板块设计方案

版本:V1.0
日期:2026-10-20
目标:支持每个网站拥有独立设计,同时让内容可以在后台结构化编辑并生成纯静态页面。


1. 设计结论

主题和板块必须解耦:

  • **主题(Theme)**负责页面结构、视觉风格、HTML、CSS、动画和响应式实现。
  • **板块(Block)**负责内容字段及其顺序,例如标题、图片、按钮、产品参数、FAQ。
  • **模板(Template)**规定一类页面默认由哪些区域组成,以及允许使用哪些板块。
  • **页面(Page)**保存所选模板和实际板块数据。

推荐模式是:

统一板块数据协议 + 每个主题自己的板块渲染器

例如后台都保存 hero 数据,但汽车站可以显示全屏视频,工业站可以显示左文右图。两者共享内容语义,不共享强制布局。

V1 不做任意坐标、任意嵌套的低代码编辑器,只提供:

  • 选择板块。
  • 表单编辑字段。
  • 调整板块顺序。
  • 启用或隐藏板块。
  • 选择少量经过主题声明的样式变体。
  • PC/移动端静态预览。

这样既能快速维护,又不会让自由配置破坏设计、响应式和 SEO。


2. 四层结构

flowchart TB
  CONTENT[内容:产品/文章/页面/媒体]
  BLOCK[板块实例:type + data + settings]
  TEMPLATE[页面模板:区域与板块约束]
  THEME[主题:组件、样式、交互]
  HTML[静态 HTML/CSS/JS]

  CONTENT --> BLOCK
  BLOCK --> TEMPLATE
  TEMPLATE --> THEME
  THEME --> HTML

2.1 内容层

保存可复用的业务数据,例如产品名称、参数、文章正文和媒体资源。内容不应该写死在主题代码里。

2.2 板块层

保存某个页面中的展示内容和顺序。板块数据尽量不包含颜色、像素、CSS 类名等主题实现细节。

2.3 模板层

定义首页、产品详情、新闻详情、普通页面等页面类型及允许的区域。模板可以自动插入由业务数据驱动的系统区域。

2.4 主题层

每个主题提供自己的 Astro 页面、组件、样式和板块渲染器,最终生成静态文件。


3. 板块分类

3.1 全局板块

全站复用,单独管理:

  • Header
  • Footer
  • 顶部通知条
  • 全局询价 CTA
  • 联系方式
  • 社交媒体链接
  • Cookie/隐私提示

修改全局板块后,会重建所有引用它的页面;V1 可以直接触发该站全量构建。

3.2 页面内容板块

由管理员在页面中新增、排序和编辑:

  • Hero
  • Rich Text
  • Image + Text
  • Image Gallery
  • Video
  • Feature List
  • Statistics
  • Logo/Brand List
  • Product Grid
  • Article List
  • Specification Table
  • Download List
  • FAQ
  • Testimonials
  • CTA
  • Contact Information
  • Map Embed

3.3 模板系统板块

由模板根据当前内容自动生成,通常不允许页面编辑者删除:

  • 面包屑
  • 产品主信息
  • 产品参数
  • 文章标题、日期和正文
  • 分类列表与分页
  • 相关推荐
  • SEO Head

管理员可以在允许范围内控制显示、顺序或样式变体,但不直接维护其核心业务数据。

3.4 站点专属板块

某些页面效果只属于一个站点,可以由主题声明自定义板块,例如:

vehicle-360-view
charging-calculator
factory-process-timeline
dealer-map

站点专属板块仍需提供数据 schema 和后台表单定义,不能只在代码中写死内容。

3.5 Legacy HTML 板块

用于暂时无法结构化的历史内容:

  • 只接受清洗后的 HTML。
  • 删除脚本、事件属性和危险 URL。
  • 使用隔离样式容器。
  • 后台醒目标记为“待结构化”。
  • 不能作为新页面的默认编辑方式。

4. 板块数据协议

4.1 板块实例

export interface BlockInstance<TData = Record<string, unknown>> {
  id: string;
  type: string;
  schemaVersion: number;
  variant?: string;
  data: TData;
  settings?: {
    anchorId?: string;
    themeMode?: 'default' | 'light' | 'dark';
    spacing?: 'none' | 'small' | 'medium' | 'large';
  };
  visibility: {
    enabled: boolean;
    locales?: string[];
  };
}

4.2 页面内容示例

{
  "contentId": "page_home",
  "templateKey": "home",
  "blocks": [
    {
      "id": "block_hero_01",
      "type": "hero",
      "schemaVersion": 1,
      "variant": "image-right",
      "data": {
        "eyebrow": "New Energy Vehicles",
        "title": "Build Your Next Journey",
        "description": "A short introduction.",
        "mediaId": "asset_1001",
        "primaryAction": {
          "label": "View Products",
          "href": "/products/"
        }
      },
      "settings": {
        "spacing": "large",
        "themeMode": "dark"
      },
      "visibility": {
        "enabled": true
      }
    }
  ]
}

4.3 内容和样式边界

建议保存在板块数据中的字段:

  • 标题、描述和按钮文案。
  • 媒体资源引用。
  • 内部/外部链接。
  • 产品、文章、分类等内容引用。
  • 允许的语义变体,例如 featured、compact。

不建议保存:

  • 任意 CSS。
  • Tailwind/CSS 类名。
  • 像素坐标。
  • 随意输入的颜色值。
  • 主题组件文件路径。
  • 可执行 JavaScript。

颜色、字体和间距默认由主题控制。如果确实需要运营配置,只允许主题 manifest 中声明的有限选项。


5. 板块定义与表单生成

每个板块类型包含两份声明:

  1. schema:数据校验规则。
  2. uiSchema:后台如何展示编辑表单。

5.1 Hero Schema 示例

{
  "$id": "siteforge://blocks/hero/v1",
  "type": "object",
  "required": ["title"],
  "properties": {
    "eyebrow": { "type": "string", "maxLength": 80 },
    "title": { "type": "string", "minLength": 1, "maxLength": 160 },
    "description": { "type": "string", "maxLength": 500 },
    "mediaId": { "type": "string" },
    "primaryAction": {
      "type": "object",
      "properties": {
        "label": { "type": "string", "maxLength": 40 },
        "href": { "type": "string" }
      },
      "required": ["label", "href"]
    }
  },
  "additionalProperties": false
}

5.2 UI Schema 示例

{
  "title": { "widget": "text", "label": "主标题" },
  "description": { "widget": "textarea", "label": "说明" },
  "mediaId": { "widget": "media-picker", "label": "主视觉" },
  "primaryAction.href": { "widget": "link-picker", "label": "按钮链接" }
}

管理后台根据这些声明生成表单,不需要为每个主题重复开发一套内容编辑页面。

推荐使用 JSON Schema 作为跨前后端协议,并使用 Ajv 校验。主题内可以生成对应 TypeScript 类型,避免重复维护接口。


6. 主题协议

6.1 主题清单

{
  "id": "automotive-premium",
  "name": "Automotive Premium",
  "version": "1.0.0",
  "engine": "astro",
  "siteConfigSchema": "./schemas/site-config.schema.json",
  "templates": {
    "home": {
      "entry": "src/templates/HomePage.astro",
      "allowedBlocks": ["hero", "feature-list", "product-grid", "cta"],
      "requiredBlocks": ["hero"],
      "maxPerType": { "hero": 1 }
    },
    "product": {
      "entry": "src/templates/ProductDetail.astro",
      "allowedBlocks": ["gallery", "specification-table", "download-list", "faq", "cta"]
    },
    "page": {
      "entry": "src/templates/GenericPage.astro",
      "allowedBlocks": ["hero", "rich-text", "image-text", "gallery", "faq", "cta"]
    }
  },
  "blocks": {
    "hero": {
      "renderer": "src/blocks/HeroBlock.astro",
      "schema": "siteforge://blocks/hero/v1",
      "variants": ["fullscreen", "image-right", "minimal"]
    },
    "product-grid": {
      "renderer": "src/blocks/ProductGridBlock.astro",
      "schema": "siteforge://blocks/product-grid/v1",
      "variants": ["cards", "editorial"]
    }
  }
}

6.2 主题目录

themes/automotive-premium/
  theme.json
  schemas/
    site-config.schema.json
  src/
    templates/
      HomePage.astro
      ProductDetail.astro
      ArticleDetail.astro
      GenericPage.astro
    blocks/
      HeroBlock.astro
      RichTextBlock.astro
      ProductGridBlock.astro
      FaqBlock.astro
    components/
      Header.astro
      Footer.astro
      Breadcrumb.astro
    layouts/
      BaseLayout.astro
    styles/
      tokens.css
      global.css
    lib/
      block-renderers.ts
  public/

6.3 不使用主题继承

V1 不建议建立复杂的父主题/子主题覆盖机制。公共能力通过普通包复用:

packages/theme-runtime
packages/seo-components
packages/block-contracts
packages/media-components

每个主题仍然明确拥有自己的模板和 CSS。这样升级公共包时更可控,也避免多层覆盖难以追踪。

6.4 四层组件化复用架构

为了提高新主题和新网站的开发速度,组件按复用程度分为四层:

flowchart TB
  C1[第一层:数据契约与工具]
  C2[第二层:无样式基础组件]
  C3[第三层:业务逻辑与 Headless 组件]
  C4[第四层:主题展示组件]
  PAGE[页面模板]

  C1 --> C2
  C1 --> C3
  C2 --> C4
  C3 --> C4
  C4 --> PAGE

第一层:数据契约与工具,完全复用

  • Block、Page、Media、Menu、SEO 类型。
  • JSON Schema 和数据验证。
  • 内部链接解析。
  • 图片地址、srcset 和尺寸计算。
  • URL、Canonical、Hreflang 和结构化数据生成。
  • HTML 净化、日期格式化和多语言工具。

这一层不包含任何主题样式。

第二层:无样式基础组件,高度复用

  • Container
  • Grid
  • Stack
  • Media
  • Picture
  • Link
  • Button 基础行为
  • Dialog
  • Accordion
  • Tabs
  • Carousel 控制逻辑
  • Pagination

组件提供语义、可访问性和交互状态,不固定颜色、字体和视觉效果。主题通过 CSS、自定义属性和组合方式决定最终外观。

第三层:业务逻辑与 Headless 组件,高度复用

  • 产品列表查询与分页。
  • 文章列表查询。
  • 产品参数分组。
  • 菜单树解析。
  • 面包屑生成。
  • FAQ 展开状态。
  • 表单校验和提交状态。
  • 搜索数据适配。
  • 相关推荐规则。

这类组件输出数据或状态,不直接决定最终 DOM 结构。例如 createProductGridModel() 负责得到产品卡片数据,汽车主题和工业主题分别决定如何渲染卡片。

第四层:主题展示组件,按主题独立

  • Header、Footer、Mega Menu。
  • Hero 的具体布局。
  • Product Card 的视觉结构。
  • 首页各板块的组合方式。
  • 动画、颜色、字体和响应式细节。

这一层允许完全不同,避免为了复用而把所有网站做成同一种风格。

6.5 公共组件包结构

packages/
  content-contracts/        # Page、Block、Product、Post 等类型
  block-contracts/          # 板块 schema、版本和迁移
  theme-runtime/            # 主题加载、模板解析、渲染上下文
  ui-primitives/            # 无样式基础组件
  headless-components/      # 菜单、分页、Tabs、Accordion 等逻辑
  content-resolvers/        # 产品/文章/分类引用解析
  media-components/         # Picture、Video、资源地址与 srcset
  seo-components/           # Meta、Canonical、Hreflang、JSON-LD
  form-runtime/             # 表单 schema、校验和提交适配
  design-tokens/            # 公共 token 协议,不存具体品牌值

主题只引用公共包的正式入口,不能跨主题引用另一个主题内部文件。

允许:theme-a → packages/ui-primitives
禁止:theme-a → themes/theme-b/src/components/ProductCard.astro

如果多个主题确实重复使用一个展示组件,应先将其中的通用行为和结构抽到公共包,再由各主题提供外观;不要直接复制后形成多个无法同步的版本。

6.6 设计令牌

公共组件只使用语义化 token,不使用某个网站的品牌颜色:

:root {
  --sf-color-primary: #1f4b7a;
  --sf-color-accent: #e8792e;
  --sf-color-text: #1b1f24;
  --sf-color-surface: #ffffff;
  --sf-radius-control: 0.5rem;
  --sf-space-section: clamp(4rem, 8vw, 8rem);
  --sf-container-width: 75rem;
}

每个主题覆盖这些 token,也可以增加自己的 token。公共包不得依赖只有某个主题才存在的 token。

6.7 组合优于大量 Variant

公共组件保持小而稳定,通过组合形成页面板块:

<Section>
  <Container>
    <SplitLayout>
      <HeroContent data={block.data} />
      <ThemeHeroMedia media={media} />
    </SplitLayout>
  </Container>
</Section>

不要给一个公共 Hero 增加几十个布尔属性来适应所有网站,例如 rounded、centered、overlay、video、reverse、compact 的任意组合。稳定的数据协议可以复用,最终板块应由主题组合基础组件实现。

6.8 组件复用矩阵

能力 公共包复用 主题独立
数据类型与 Schema 是 否
SEO Head 是 可提供少量站点配置
Picture/srcset 是 可控制画面比例和样式
菜单树和展开逻辑 是 Header 结构和动画独立
产品查询与分页 是 产品卡片独立
FAQ 数据与交互状态 是 排版和图标独立
表单校验与提交 是 字段布局和视觉独立
Hero 内容协议 是 Hero 渲染完全独立
页面模板 否 是
品牌色、字体、间距 仅协议 是

6.9 组件版本与兼容

  • 公共包遵循语义化版本。
  • 破坏性变更必须提供迁移说明或兼容适配层。
  • 主题 manifest 记录公共运行时的兼容范围。
  • 每个公共组件提供最小、完整、异常三个测试 fixture。
  • 公共组件升级后,自动构建所有示范主题并执行截图回归。
  • 发布 release 锁定公共包和主题版本,回滚时不能自动升级依赖。

6.10 组件预览与文档

建立独立的组件预览页,展示:

  • 基础组件的状态和可访问性。
  • 每种板块的最小/完整数据。
  • 同一板块在不同主题中的效果。
  • 桌面、平板和手机断点。
  • 空数据、超长标题、图片缺失等异常状态。

预览页可以采用 Storybook 或项目内 Astro 组件目录。V1 的重点是可查看和自动截图,不强制依赖某个文档工具。


7. 模板约束

模板除了渲染页面,还负责约束后台可配置范围。

export interface TemplateDefinition {
  key: string;
  contentTypes: string[];
  allowedBlocks: string[];
  requiredBlocks?: string[];
  maxPerType?: Record<string, number>;
  lockedRegions?: string[];
}

示例:

  • 首页必须有一个 Hero,最多一个。
  • 产品详情固定显示产品标题、价格/询价入口和核心参数。
  • FAQ、下载、CTA 可以由管理员添加、删除和排序。
  • SEO Head、Header、Footer 是锁定区域,不出现在自由排序列表里。

后台新增板块时,只显示当前主题、当前模板支持的类型和变体。


8. 数据库存储

推荐将板块实例按修订版本独立存储,而不是直接写入已发布页面。

CREATE TABLE page_blocks (
  id UUID PRIMARY KEY,
  site_id UUID NOT NULL REFERENCES sites(id),
  revision_id UUID NOT NULL REFERENCES content_revisions(id),
  block_type TEXT NOT NULL,
  schema_version INTEGER NOT NULL,
  variant TEXT,
  position INTEGER NOT NULL,
  data JSONB NOT NULL DEFAULT '{}'::jsonb,
  settings JSONB NOT NULL DEFAULT '{}'::jsonb,
  visibility JSONB NOT NULL DEFAULT '{"enabled":true}'::jsonb,
  created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

CREATE INDEX idx_page_blocks_revision_position
  ON page_blocks(revision_id, position);

全局板块可以使用:

global_fragments
global_fragment_revisions
global_fragment_usages

发布时锁定内容修订和全局板块修订,确保历史 release 可以准确回滚。


9. 后台编辑体验

9.1 页面编辑器布局

┌────────────────────────────────────────────────────────────┐
│ 页面标题 / URL / 模板 / 保存 / 预览 / 发布                 │
├──────────────────────┬─────────────────────────────────────┤
│ 板块列表             │ 当前板块表单                        │
│                      │                                     │
│ 1. Hero              │ 标题       [________________]       │
│ 2. Product Grid      │ 描述       [________________]       │
│ 3. FAQ               │ 图片       [选择媒体]               │
│ 4. CTA               │ 样式变体   [image-right ▼]          │
│                      │                                     │
│ [+ 添加板块]         │                                     │
└──────────────────────┴─────────────────────────────────────┘

首版功能:

  • 点击新增板块。
  • 拖动调整纵向顺序。
  • 复制、隐藏和删除板块。
  • 编辑结构化字段。
  • 从媒体库、产品、文章和内部路由中选择引用。
  • 保存草稿。
  • 创建静态预览。
  • 显示字段和模板校验错误。

9.2 不在 V1 实现

  • 画布上任意拖动位置。
  • 任意列宽和像素级布局。
  • 无限层级嵌套板块。
  • 管理员输入 CSS/JavaScript。
  • 在一个主题中自由调用另一个主题的组件。

10. Astro 渲染实现

10.1 渲染器注册

import HeroBlock from '../blocks/HeroBlock.astro';
import RichTextBlock from '../blocks/RichTextBlock.astro';
import ProductGridBlock from '../blocks/ProductGridBlock.astro';

export const blockRenderers = {
  hero: HeroBlock,
  'rich-text': RichTextBlock,
  'product-grid': ProductGridBlock,
} as const;

10.2 页面循环

---
import { blockRenderers } from '../lib/block-renderers';

const { page } = Astro.props;
const blocks = page.blocks.filter((block) => block.visibility.enabled);
---

{blocks.map((block) => {
  const Renderer = blockRenderers[block.type];
  return Renderer
    ? <Renderer block={block} page={page} />
    : null;
})}

实际构建前必须已经验证所有板块类型。生产构建发现未知板块时应失败,不能静默生成空白区域;后台预览可以显示“当前主题不支持该板块”的占位提示。

10.3 数据解析顺序

读取发布快照
→ 获取页面与内容引用
→ 获取模板定义
→ 验证允许的板块和数量
→ 按 schema 校验每个板块
→ 解析媒体与内部链接
→ 选择主题渲染器
→ 生成 HTML
→ 执行 SEO/链接/资源验收

10.4 客户端 JavaScript

Astro 默认输出静态 HTML。只有轮播、菜单、筛选等确需交互的组件才使用客户端 hydration,并选择合适的加载策略。普通文本、产品参数和 FAQ 不应无条件加载完整前端框架。


11. 主题切换策略

11.1 可以直接切换的条件

  • 新主题支持当前页面模板。
  • 新主题支持页面使用的全部板块类型。
  • 每个板块的 schema 版本兼容。
  • 主题所需站点配置完整。

11.2 切换前检查

系统先生成兼容报告:

支持的模板
缺失的板块渲染器
不支持的 variant
缺失的站点配置
需要迁移的数据版本

存在不支持板块时,不允许直接用于生产构建。可以:

  • 为新主题增加渲染器。
  • 将板块转换为兼容类型。
  • 由管理员明确删除或替换。

11.3 主题切换不是主要目标

平台需要支持主题版本升级和兼容检查,但不必把“任何网站一键换任意主题”作为 V1 目标。不同网站设计差异很大,强行互换会让板块协议变得臃肿。


12. 板块版本与数据迁移

板块必须携带 schemaVersion。

type BlockMigration = {
  blockType: string;
  fromVersion: number;
  toVersion: number;
  migrate: (oldData: unknown) => unknown;
};

例如 Hero V2 将 buttonText 和 buttonUrl 合并为 primaryAction:

v1 data
→ 运行纯函数迁移
→ v2 data
→ schema 校验
→ 生成新的内容修订

禁止直接批量覆盖已发布修订。迁移失败的板块进入人工处理列表,旧版本数据继续保留。


13. API 建议

GET    /api/v1/themes
GET    /api/v1/themes/:themeId/manifest
GET    /api/v1/sites/:siteId/theme
PUT    /api/v1/sites/:siteId/theme

GET    /api/v1/sites/:siteId/pages/:pageId/blocks
POST   /api/v1/sites/:siteId/pages/:pageId/blocks
PATCH  /api/v1/sites/:siteId/pages/:pageId/blocks/:blockId
DELETE /api/v1/sites/:siteId/pages/:pageId/blocks/:blockId
POST   /api/v1/sites/:siteId/pages/:pageId/blocks/reorder
POST   /api/v1/sites/:siteId/pages/:pageId/validate
POST   /api/v1/sites/:siteId/pages/:pageId/preview

GET    /api/v1/sites/:siteId/fragments
POST   /api/v1/sites/:siteId/fragments
PATCH  /api/v1/sites/:siteId/fragments/:fragmentId

后端负责验证模板、板块类型、schema、variant、媒体和内部链接;不能只在管理后台进行校验。


14. 测试策略

14.1 契约测试

  • 每个主题 manifest 格式正确。
  • 模板引用的板块都有渲染器。
  • 板块数据能通过对应 schema。
  • 主题声明的 variant 都能渲染。
  • 必需板块和最大数量约束有效。

14.2 渲染测试

  • 每个模板至少有一份标准 fixture。
  • 每个板块测试最少字段、完整字段和异常字段。
  • 生成 HTML 不包含预览域名、危险脚本和无效资源。
  • 核心内容在输出 HTML 中真实存在,而非仅客户端加载。

14.3 视觉测试

  • 为首页、产品详情、文章详情和普通页面生成桌面/移动截图。
  • 主题版本变化时对比关键页面。
  • 视觉差异由超级管理员确认后才能用于生产发布。

14.4 性能与可访问性

  • 图片包含宽高并使用合适尺寸。
  • 交互组件按需加载。
  • 标题层级、链接、按钮和表单具有正确语义。
  • 颜色对比、键盘操作和焦点状态在主题验收中检查。

15. V1 实现顺序

Sprint 1:契约和最小渲染

  • 建立 block-contracts。
  • 建立 ui-primitives、theme-runtime 和 content-resolvers 的最小公共包。
  • 定义 Hero、Rich Text、Image Text、Gallery、CTA、FAQ 六个基础板块。
  • 建立主题 manifest 和模板协议。
  • 使用固定 JSON 生成一个静态首页。

Sprint 2:数据库和后台编辑

  • 建立 page_blocks 和内容修订。
  • 根据 schema 生成表单。
  • 支持新增、编辑、删除、排序和隐藏。
  • 支持媒体和内部链接选择。

Sprint 3:主题与预览

  • 完成第一套主题的首页、普通页面、产品详情和文章详情。
  • 建立预览构建。
  • 增加模板与板块兼容检查。

Sprint 4:第二主题验证

  • 使用相同基础板块数据开发视觉完全不同的第二主题。
  • 验证哪些字段真正通用,哪些需要站点专属板块。
  • 将两个主题中重复的非视觉逻辑提取到公共组件包。
  • 固化主题 SDK、测试 fixture 和开发文档。

Sprint 5:生产质量

  • 板块版本迁移。
  • 全局板块。
  • 视觉回归、可访问性和性能检查。
  • 与发布门禁和不可变 release 集成。

16. 首版基础板块清单

建议首版只实现以下 12 个,真实试点需要后再增加:

板块 核心字段
Hero eyebrow、title、description、media、actions
Rich Text content
Image Text title、content、media、mediaPosition、action
Gallery title、items
Feature List title、items、icon/media
Statistics title、items(value/label)
Product Grid title、productRefs/query、limit、action
Article List title、category/query、limit、action
Specification Table title、groups/rows 或 product field binding
Download List title、assetRefs
FAQ title、items(question/answer)
CTA title、description、media、actions

Header、Footer、Breadcrumb、产品主信息和文章主内容作为全局/模板系统组件单独实现,不计入可自由添加板块。


17. 开发验收标准

主题与板块模块达到以下条件即可视为 V1 完成:

  1. 超级管理员能为页面选择模板。
  2. 能新增、编辑、排序、隐藏和删除模板允许的板块。
  3. 后台字段由 schema 驱动,并在前后端双重验证。
  4. 相同板块数据能被两套主题渲染成明显不同的设计。
  5. 主题不支持某板块时,生产构建会被阻止并给出明确错误。
  6. 产品详情和文章详情能混合系统板块与可配置板块。
  7. 全局 Header/Footer 修改后能够重新构建站点。
  8. 所有发布版本锁定主题版本和板块修订,可准确回滚。
  9. 页面输出为静态 HTML,核心内容无需 JavaScript 即可读取。
  10. 主题和板块变更进入现有 URL、SEO、内容和视觉发布门禁。
  11. 两套主题复用相同的数据契约、媒体、SEO 和 Headless 逻辑,但最终页面视觉明显不同。

18. 最终建议

首版主题系统的重点不是“让管理员设计网页”,而是让开发者能够快速制作不同主题,让管理员安全地维护结构化内容。

必须守住三个边界:

  1. 内容数据中不写 CSS 和组件路径。
  2. 主题不能自己决定历史 URL 和 SEO。
  3. 未知或不兼容板块不能在生产构建中静默消失。

按“统一协议、独立渲染、有限配置、严格校验”实现,既能保留每个网站的设计自由度,也能让后续内容维护和新站迁移真正复用同一套系统。