Files
official-site-base/docs/specs/2026-07-23-official-site-cms-design.md
T

269 lines
14 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.
# 官网 + 轻量自助 CMS 白标基座 设计文档
> **产品线**:一人公司开源项目选型清单 §5「建站(官网)」升级方案(产品线 E)
> **日期**2026-07-23
> **状态**:设计已确认,待写实施计划
> **关联**:升级自 [一人公司开源项目选型清单](../../../一人公司开源项目选型清单.md) §5 / §9-E
---
## 一、背景与目标
### 1.1 原方案的三个缺口
一人公司选型清单中,官网搭建(产品线 E)原方案是「Astro + Astro Wind」纯 SSG,存在三个缺口:
1. **基座复用没落地** —— 文档第③条选型原则「一套基座吃多客户」在官网线未体现,每次都 fork 第三方模板,变成一锤子买卖。
2. **缺「官网 + 自助 CMS」混合方案** —— 纯 SSG 客户改内容只能走你,内容代维护变成长期负担,吃掉利润。
3. **未覆盖国内部署** —— 文档建议的 Vercel / Cloudflare Pages 在国内访问慢且常被墙,国内客户官网必须备案 + 国内 CDN。
### 1.2 目标
打造一套**可复用的官网白标基座**:
- 客户在可视化后台**自助改内容**(公司 / 产品 / 新闻 / 案例 / 招聘 / 下载 / 留言)
- **客户侧零服务器** —— 访客访问的是 OSS + CDN 纯静态站
- **一套基座复制给多客户** —— 换设计 token + 换内容即可交付新客户
- **国内合规上线** —— ICP 备案 + 阿里云 OSS/CDN
### 1.3 非目标(YAGNI 边界)
- ❌ 多语言 i18n(除非客户明确付费要求)
- ❌ 电商 / 支付(那是产品线 A,CRMEB)
- ❌ 会员 / 工单 / 审批(那是产品线 B,若依 / 低代码)
- ❌ 富后台 / 多角色 CMS(预留 Payload 适配器接口,遇到高预算客户再加,不在首期实现)
---
## 二、已确认的关键决策
| # | 决策点 | 结论 |
|---|--------|------|
| 1 | 定位 | 白标基座 + 首客户驱动(先跑通一个真实客户,再沉淀复用资产) |
| 2 | Git 后端 + CI | **自建一台 Gitea**(含 Gitea Actions),所有客户共用,多租户 |
| 3 | 内容板块 | company / products / news / cases / pages + **jobs(招聘)/ downloads(下载)/ messages(留言表单)** |
| 4 | 云厂商 | **阿里云**OSS + CDN + 域名 + ICP 备案) |
---
## 三、技术栈选型(License 全部原文核实)
| 层 | 选型 | License | 核实来源 | 选型理由 |
|----|------|---------|----------|----------|
| 官网框架 | **Astro**SSG | ✅ MIT | withastro/astro LICENSE | 零运行时、SEO 满分、Content Collections 类型安全 |
| 官网主题 | **Astro Wind** 起步,逐步沉淀**自有主题** | ✅ MIT | onwidget/astrowind LICENSE | 半天换皮;基座化后替换为自有 token 主题 |
| 自助 CMS | **Sveltia CMS** | ✅ MIT | sveltia/sveltia-cms `LICENSE.txt` + 官方 FAQ | Decap 的现代替代、原生支持 Gitea、活跃;Keystatic 锁 GitHub 不适合国内 |
| Git 后端 + CI | **自建 Gitea**+ Gitea Actions | ✅ MIT | go-gitea/gitea LICENSE | 单二进制极轻、被 Sveltia 原生支持、一台服务多客户、完全自控 |
| 表单后端 | **自研轻量微服务** | 自研(MIT | — | 复用 Gitea 那台轻量云,零额外服务器 |
| 对象存储 + CDN | **阿里云 OSS + CDN** | 商业 | — | 国内访问快、抗刷、备案友好 |
| 域名 / 备案 | 阿里云域名 + ICP 备案 | 商业 | — | 国内合规必须 |
> **技术验证结论(已查实)**Sveltia CMS / Decap CMS 都**不原生支持 Gitee**(要走自建 git-gateway + OAuth 代理,复杂且脆);GitHub 国内 OAuth 不稳。**Gitea 是两大 CMS 都原生支持**的国内可用后端,且自带 Actions CI,故选自建 Gitea。
全部为 🟢 MIT / 商业服务,**无 AGPL / GPL / BSL 传染风险**,白标转售安全。
---
## 四、整体架构
```
① 客户编辑 ② 构建发布 ③ 访客访问
┌────────────┐ 提交 ┌─────────────────┐ 同步 ┌──────────────┐
│ Sveltia │────────▶│ 自建 Gitea │────────▶│ 阿里云 │
│ /admin │ │ + Gitea Actions │ │ OSS + CDN │
│ (可视化) │◀────────│ (构建 Astro) │ │ (纯静态) │
└────────────┘ OAuth └─────────────────┘ └──────────────┘
│ │
│ ┌────────┴────────┐
└──────────────┤ 一台轻量云 │
表单提交 │ ① Gitea + CI │
│ ② 表单微服务 │ ← 服务【所有客户】
│ ③ SQLite 留底 │ 多租户共用
└─────────────────┘
```
**三层职责**
- **编辑层**:客户在 `https://<客户域名>/admin`Sveltia CMS 单页应用)可视化编辑,OAuth 登录自建 Gitea。
- **构建 / 存储层**:自建 Gitea(一台轻量云)。客户提交 → Gitea Actions 自动构建 Astro → `ossutil` 同步到该客户的 OSS bucket → 刷新 CDN。表单微服务也跑在这台机上。
- **访客层**:阿里云 OSS 托管静态站 + CDN 加速,访客全程不碰服务器,快、稳、抗刷。
---
## 五、内容模型(Astro Content Collections
每个集合配 Zod schema 校验,客户在 Sveltia 填错会自动报错。
| 集合 | 类型 | 字段 | 说明 |
|------|------|------|------|
| `company` | 单例 | name / intro / logo / phone / email / address / icp | 全站公共信息(页头页脚) |
| `products` | 集合 | title / cover / summary / body / category / sort | 产品或服务 |
| `news` | 集合 | title / date / category / cover / body | 新闻动态(带分页 + RSS |
| `cases` | 集合 | client / industry / cover / result / body | 客户案例 |
| `pages` | 集合 | slug / title / body / showInNav | 关于我们、联系等静态页 |
| `jobs` | 集合 | title / location / department / requirement / body | 招聘岗位 |
| `downloads` | 集合 | name / description / fileUrl / category / size | 下载资源(文件存 OSS,见 §七) |
| `messages` | 表单 | name / phone / email / message / createdAt | 留言(见 §六,由表单微服务写入) |
> `messages` 不由客户手动编辑,而是由访客提交的留言表单经微服务写入(通过 Gitea API 落成 Markdown 文件到该集合),客户在 `/admin` 查看,同时收到邮件通知。
---
## 六、留言表单方案(messages
纯静态站(OSS + CDN)无法处理后端逻辑,故**复用 Gitea 那台轻量云**,跑一个自研的极轻表单微服务。
### 6.1 技术栈
- **运行时**Node.js + Hono(或 Express
- **写内容**:通过 Gitea API 把留言写成 Markdown 提交到 `messages` 集合(Git 即留底,无需额外数据库)
- **邮件**nodemailer + 阿里云邮件推送(DirectMailSMTP,或腾讯企业邮 SMTP
- **失败兜底**:Gitea 写失败时记本地日志文件,保证不丢留言
- **部署**systemd 或 docker,跑在 Gitea 同机
- **凭据**:微服务持有一个专用 Gitea token,仅对该客户仓库有写权限(最小权限)
### 6.2 处理流程
```
访客填表 → POST https://forms.<你的服务域名>/api/submit
→ ① 蜜罐字段检查(机器人会填隐藏字段 → 丢弃)
→ ② IP 限流(每 IP 每分钟 ≤5 次)
→ ③ 字段校验(Zod)
→ ④ 经 Gitea API 写入 `messages` 集合(Markdown,客户在 /admin 查看)
→ ⑤ SMTP 发邮件通知客户(含留言内容)
→ 返回成功页
```
### 6.3 多租户
一个微服务服务所有客户:配置文件映射 `form_id → { 客户邮箱, 跳转页 }`。新客户加一行配置即可。前端表单的 `action` 带上该客户的 `form_id`
### 6.4 防垃圾
- 蜜罐字段(必填陷阱)
- IP 限流
- 可选:阿里云验证码 / hCaptcha(垃圾严重时再加,YAGNI
---
## 七、下载文件方案(downloads
下载文件(PDF 手册、驱动、视频)**不进 Git 仓库**(大文件不友好),统一存 OSS:
- 文件手动或脚本上传到该客户 OSS bucket 的 `/downloads/` 目录
- `downloads` 内容集合只记录元信息:`name / description / fileUrlOSS URL/ category / size`
- 客户在 Sveltia 编辑下载项的描述,文件本身由你或客户用 OSS 工具上传(Sveltia 的媒体库只给图片用,不混用)
> 小文件(<2MB 的 PDF)可直接 Sveltia 上传到 Gitea 仓库;大文件走 OSS。以 OSS 为主,避免仓库膨胀。
---
## 八、白标复用(新客户上线流程)
基座 = 一个 Astro 主题仓库(含组件区段 + Content Collections schema + Sveltia 配置模板 + Gitea Action 工作流)。
新客户交付 = 7 步:
1. **fork 基座** → 在自建 Gitea 建新仓库(独立组织/权限隔离)
2. **改设计 token** → 改一个 CSS 变量文件(主色 / 字体 / 圆角),整站换皮
3. **配 Sveltia** `config.ts` → 勾选该客户需要的内容板块(如纯展示型客户去掉 jobs/downloads
4. **客户填内容** → 在 `/admin` 用 Sveltica 录入
5. **域名 + 备案** → 阿里云买域名 + ICP 备案(约 7-20 工作日)
6. **建 OSS bucket + CDN** → 配静态站托管 + 绑定自定义域名
7. **配 Gitea Action** → 构建后 `ossutil` 上传 + 刷新 CDN → 上线,转月度维护续费
> 每个客户 = 一个 Gitea 仓库 + 一个 OSS bucket + 一个域名 + 一行表单配置;**基座代码复用、配置隔离**。
---
## 九、国内部署(阿里云)
- [ ] **ICP 备案**:客户域名必须备案,否则 CDN / 解析受阻(备案约 7-20 工作日,提前启动)
- [ ] **OSS 静态站托管**:开 bucket 的静态网站托管 + 绑定自定义域名(HTTPS)
- [ ] **CDN 加速**:回源 OSS,缓存策略 —— HTML 短缓存(1-5 分钟,便于内容更新生效)、JS/CSS/图片长缓存 + 文件名 hash
- [ ] **CI 发布脚本**Gitea Action 构建后用 `ossutil cp -rf dist/ oss://<bucket>/` 上传 + 调 OpenAPI 刷新 CDN
- [ ] **HTTPS**:阿里云免费 SSL 证书(或 Let's Encrypt),绑 OSS / CDN
- [ ] ⚠️ **不要用 Vercel / Cloudflare Pages**(国内访问慢 / 常被墙)
---
## 十、成本测算
| 项 | 金额 | 说明 |
|----|------|------|
| 固定:轻量云(Gitea + CI + 表单微服务) | ≈ 60-100 元/月 | **所有客户共用**2H2G 推荐 |
| 每客户:OSS + CDN | ≈ 5-15 元/月 | 按量,企业官网流量小 |
| 每客户:域名 | ≈ 55 元/年 | — |
| 每客户:备案 | 0 | 阿里云免费备案 |
| 每客户:邮件推送 | 极低 | DirectMail 按发信量,几毛/月 |
| **客单价**(参考文档 E 线) | **5k-2 万 + 月度维护续费** | 半天换皮、长期续费 |
**结论**:新增一个客户的边际成本 ≈ 60-100 元/年(域名 + OSS/CDN),客单价 5k 起,毛利极高。
---
## 十一、风险与先验证点(Phase 0 必须跑通)
| # | 风险 / 验证点 | 应对 |
|---|--------------|------|
| 1 | Gitea Actions 能否跑 Astro 构建 | 兼容 GitHub Actions 语法,Phase 0 用 node runner 镜像验证 |
| 2 | Sveltia + Gitea OAuth 登录 / 提交全链路 | Phase 0 配 Gitea OAuth App 跑通 |
| 3 | CDN 刷新延迟 | 秒-分钟级,HTML 配短缓存可接受 |
| 4 | 多租户 Gitea 权限隔离 | 每客户独立组织 / 仓库权限 |
| 5 | 表单微服务防垃圾 / 可用性 | 蜜罐 + 限流先上,验证码按需 |
| 6 | 备案周期长阻塞交付 | 合同里写明备案周期,提前启动或先用临时域名 |
---
## 十二、实施阶段
| 阶段 | 目标 | 产出 |
|------|------|------|
| **Phase 0** 技术验证 | 最小链路跑通:Astro + Sveltia + 自建 Gitea → 构建 → OSS → 访问;表单微服务跑通 | 一个可编辑、可留言的 demo 站 |
| **Phase 1** 基座化 | 沉淀自有主题 + Content Collections7 个集合)+ Sveltia 配置模板 + 白标脚本(换 token / 建 bucket | 可复用基座仓库 |
| **Phase 2** 首客户上线 | 用真实客户驱动,验证商业闭环 + 续费 | 第一个交付 + 月度维护合同 |
| **Phase 3**(可选) | 加 Payload 适配器,接富后台 / 多角色高预算客户 | 双档产品线(轻量 / 富后台) |
---
## 十三、CMS 适配器(预留,兼容未来 Payload)
把内容获取抽象成统一接口,保护 Astro 层不随 CMS 变化:
```ts
// 概念接口
interface ContentAdapter {
getCollection<T>(name: string): Promise<T[]>;
getSingleton<T>(name: string): Promise<T>;
}
```
- **默认实现**`MarkdownAdapter` —— 读本地 MarkdownGitea + Sveltia 路线,首期实现)
- **预留实现**`PayloadAdapter` —— 调 Payload REST/GraphQL APIPhase 3,遇到富后台客户再加)
切换 CMS 只换适配器,Astro 页面层与 Content Collections schema 不变。
---
## 十四、交付前检查清单(沿用选型清单 §十)
每个客户上线前:
- [ ] 该客户仓库的 LICENSE 文件原文我读了吗?(基座 + 依赖)
- [ ] 有没有子目录独立 LICENSEee/ / server/ / enterprise/)?
- [ ] 我的交付方式(私有部署 / SaaS / 转售)会触发哪个条款?
- [ ] Sveltia / Gitea / Astro 的 License 变更记录复查了吗?
**把 LICENSE 原文 + 近 3 年 license 变更记录存档到客户合同附件。**
---
## 参考资料
- [一人公司开源项目选型清单](../../../一人公司开源项目选型清单.md)
- [Astro 官网](https://astro.build/) · [Astro Wind](https://github.com/onwidget/astrowind)
- [Sveltia CMS 官网](https://sveltiacms.app/) · [Sveltia CMS Backends 文档](https://sveltiacms.app/en/docs/backends) · [官方 FAQMIT](https://sveltiacms.app/en/docs/faq)
- [Gitea 官网](https://gitea.io/) · [Gitea Actions 文档](https://docs.gitea.com/usage/actions/overview)
- [阿里云 OSS 静态网站托管](https://help.aliyun.com/product/31815.html) · [阿里云 CDN](https://help.aliyun.com/product/27099.html) · [阿里云邮件推送 DirectMail](https://help.aliyun.com/product/29412.html)
- [Decap CMS Backend 概览](https://decapcms.org/docs/backends-overview/)(对照为何选 Sveltia + Gitea 而非 Gitee