From 8c33f4dcb02a6a6d67f9c1a26e9d90ccc22f1708 Mon Sep 17 00:00:00 2001 From: lzy Date: Thu, 23 Jul 2026 18:45:51 +0800 Subject: [PATCH] =?UTF-8?q?chore:=20=E5=88=9D=E5=A7=8B=E5=8C=96=E5=AE=98?= =?UTF-8?q?=E7=BD=91=E7=99=BD=E6=A0=87=E5=9F=BA=E5=BA=A7=E9=A1=B9=E7=9B=AE?= =?UTF-8?q?=EF=BC=88=E5=90=AB=E8=AE=BE=E8=AE=A1=E6=96=87=E6=A1=A3=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 32 +++ README.md | 42 +++ .../2026-07-23-official-site-cms-design.md | 268 ++++++++++++++++++ 3 files changed, 342 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 docs/specs/2026-07-23-official-site-cms-design.md diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b8b8114 --- /dev/null +++ b/.gitignore @@ -0,0 +1,32 @@ +# ===== 依赖 ===== +node_modules/ + +# ===== 构建产物 ===== +dist/ +.output/ +.astro/ + +# ===== 日志 ===== +*.log +npm-debug.log* +yarn-debug.log* +pnpm-debug.log* + +# ===== 环境变量与密钥(含阿里云 AK/SK,切勿提交)===== +.env +.env.* +!.env.example +.ossutilconfig +ossutil_config* + +# ===== 客户专属内容(每个客户独立,不入基座仓库)===== +clients/*/ + +# ===== 系统 ===== +.DS_Store +Thumbs.db + +# ===== 编辑器 ===== +.vscode/ +.idea/ +*.swp diff --git a/README.md b/README.md new file mode 100644 index 0000000..2488cb3 --- /dev/null +++ b/README.md @@ -0,0 +1,42 @@ +# Official Site Base · 官网白标基座 + +一人公司「[产品线 E · 快速官网](../../一人公司开源项目选型清单.md)」的可复用基座。 + +## 一句话 + +**Astro + Sveltia CMS + 自建 Gitea + 阿里云 OSS/CDN** —— 客户在 `/admin` 可视化自助改内容、客户侧零服务器、一套基座复制给多客户。 + +## 目标 + +- 客户在可视化后台自助改内容(公司 / 产品 / 新闻 / 案例 / 招聘 / 下载 / 留言) +- 客户侧零服务器(访客访问 OSS + CDN 纯静态站) +- 一套基座复制给多客户(换设计 token + 换内容) + +## 文档 + +- **设计文档**:[docs/specs/2026-07-23-official-site-cms-design.md](docs/specs/2026-07-23-official-site-cms-design.md) +- **上游选型清单**:工作区根《一人公司开源项目选型清单.md》§5 / §9-E + +## 技术栈(全部 MIT / 商业,已原文核实) + +| 层 | 选型 | +|----|------| +| 官网框架 | Astro(SSG) | +| 官网主题 | Astro Wind 起步,逐步沉淀自有主题 | +| 自助 CMS | Sveltia CMS | +| Git 后端 + CI | 自建 Gitea(+ Gitea Actions) | +| 表单后端 | 自研轻量微服务(复用 Gitea 那台轻量云) | +| 对象存储 + CDN | 阿里云 OSS + CDN | + +## 实施阶段 + +| 阶段 | 目标 | +|------|------| +| Phase 0 | 技术验证:最小链路跑通(Astro + Sveltia + Gitea → 构建 → OSS) | +| Phase 1 | 基座化:沉淀自有主题 + Content Collections + 白标脚本 | +| Phase 2 | 首客户上线 | +| Phase 3(可选) | 加 Payload 适配器,接富后台客户 | + +## 状态 + +📋 设计已确认,待出实施计划(Phase 0 技术验证)。 diff --git a/docs/specs/2026-07-23-official-site-cms-design.md b/docs/specs/2026-07-23-official-site-cms-design.md new file mode 100644 index 0000000..2c4cf02 --- /dev/null +++ b/docs/specs/2026-07-23-official-site-cms-design.md @@ -0,0 +1,268 @@ +# 官网 + 轻量自助 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)