# 官网 + 轻量自助 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 + 阿里云邮件推送(DirectMail)SMTP,或腾讯企业邮 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 / fileUrl(OSS 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:///` 上传 + 调 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 Collections(7 个集合)+ Sveltia 配置模板 + 白标脚本(换 token / 建 bucket) | 可复用基座仓库 | | **Phase 2** 首客户上线 | 用真实客户驱动,验证商业闭环 + 续费 | 第一个交付 + 月度维护合同 | | **Phase 3**(可选) | 加 Payload 适配器,接富后台 / 多角色高预算客户 | 双档产品线(轻量 / 富后台) | --- ## 十三、CMS 适配器(预留,兼容未来 Payload) 把内容获取抽象成统一接口,保护 Astro 层不随 CMS 变化: ```ts // 概念接口 interface ContentAdapter { getCollection(name: string): Promise; getSingleton(name: string): Promise; } ``` - **默认实现**:`MarkdownAdapter` —— 读本地 Markdown(Gitea + Sveltia 路线,首期实现) - **预留实现**:`PayloadAdapter` —— 调 Payload REST/GraphQL API(Phase 3,遇到富后台客户再加) 切换 CMS 只换适配器,Astro 页面层与 Content Collections schema 不变。 --- ## 十四、交付前检查清单(沿用选型清单 §十) 每个客户上线前: - [ ] 该客户仓库的 LICENSE 文件原文我读了吗?(基座 + 依赖) - [ ] 有没有子目录独立 LICENSE(ee/ / 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) · [官方 FAQ(MIT)](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)