Files
ChuBlog/PLAN.md
T

225 lines
14 KiB
Markdown
Raw Normal View History

# ChuBlog — 项目规划
> 状态:规划草案 v1.0 · 2026-10-15
> 定位:自托管个人技术博客;Markdown 文件是内容源,Git 管理版本,ChuSQL 提供可重建的内容索引。
## 1. 目标与原则
- 面向个人作者,支持公开阅读、文章归档、标签、代码高亮、目录、SEO、RSS 和深色模式。
- 管理员可在经过认证的后台上传 Markdown、预览、修改元数据、发布、撤回与删除文章;也支持本地 Git 工作流。
- **Git 仓库内的 Markdown 与资源文件是唯一权威内容源**;ChuSQL 不保存唯一一份正文,只维护可重建索引。
- 未授权用户不得发布页面、提交到内容仓库或触发任意服务器 Git 命令。
- 保持 MVP 小而可靠;不引入公共用户注册、评论、插件市场、队列/微服务或复杂角色系统。
- ChuSQL 暂不视为已通过生产验证的数据库;博客即使索引丢失,也能从 Git 恢复文章。
## 2. 技术栈
| 层 | 选型 | 职责 |
| --- | --- | --- |
| 站点 | Astro + TypeScript | 内容页面、按需服务端渲染、SEO、RSS |
| 样式 | Tailwind CSS | 响应式设计、暗色模式 |
| Markdown | Astro Markdown 管线(remark/rehype、Shiki) | Markdown/Frontmatter 解析、代码高亮 |
| 后端 | Rust + Axum + Tokio + Serde | 管理员接口、认证、上传校验、Git 操作、索引同步 |
| 数据库 | ChuSQL | 已发布文章元数据、标签、搜索索引(按当前能力逐步实现) |
| DB 客户端 | `chusql-rs`(独立 crate) | ChuSQL 网络协议连接、查询、错误处理 |
| 反向代理 | Caddy | HTTPS、请求体限制、路由 |
| 运行 | Debian + Docker Compose | 管理服务与持久卷 |
| 版本控制 | Git | 文章与图片的版本记录、审计与恢复 |
不自行编写 Markdown 语法解释器。MVP 禁止文章中的原始 HTML 或采用严格清理策略;默认不启用任意 MDX/JS 组件,因为上传文档不能成为服务器执行代码的入口。
## 3. 系统架构
```text
读者浏览器 ── HTTPS ── Caddy ── Astro(公共页面)
│
├─ 只读文章文件 / content(挂载)
└─ Axum 只读 API(必要时)── ChuSQL(索引)
管理员浏览器 ── HTTPS ── Caddy ── Axum(后台 API)
│
├─ 管理员认证 / CSRF / 限流
├─ Markdown 校验及暂存
├─ 受控 Git 内容仓库
└─ 索引同步 ── chusql-rs ── ChuSQL
管理员本地编辑器 ── Git 受保护分支 / 仓库同步流程 ── 内容仓库
```
- 只暴露 80/443 TCP;Axum、Astro 与 ChuSQL 使用私有 Docker 网络。
- 现有 P2P 服务可独立继续使用 UDP 7001,互不影响。
- **不允许用户请求决定任意磁盘路径、Git 仓库地址、Git 参数或 shell 命令。**
- Astro 若需上传后立即生效,使用按需 SSR 读取受控的内容快照;不要依赖仅构建时扫描的静态内容集合。若改用纯静态生成,则明确采用“提交后重新构建并原子部署”的发布策略。MVP 选择 **SSR + 已发布内容快照**。
## 4. 内容模型与存储布局
```text
chublog/
├── apps/
│ ├── web/ # Astro 站点
│ └── api/ # Axum 后台与只读 API
├── crates/
│ └── chusql-rs/ # 若尚无独立仓库,可先工作区开发再拆分
├── content/ # 独立 Git 仓库或子目录(受控工作树)
│ ├── posts/
│ │ └── haskell-monad/
│ │ ├── index.md
│ │ └── cover.webp
│ └── .gitignore
├── deploy/
│ ├── compose.yaml
│ └── Caddyfile
└── PLAN.md
```
文章 Frontmatter 规范示例:
```md
---
title: "Haskell Monad 入门"
slug: "haskell-monad"
date: "2026-10-15"
updated: "2026-10-15"
status: "published"
tags: ["Haskell", "Functional Programming"]
description: "Monad 的基础概念"
---
# Haskell Monad 入门
正文……
```
- `slug` 是唯一的 URL 标识,仅允许小写英文字母、数字、短横线,校验长度和保留名称。
- 文件路径由服务端基于已校验 slug 固定计算;禁止 `../`、绝对路径、符号链接和路径穿越。
- `status` 取 `draft | published`;草稿不可被未授权访问或从公开索引枚举。
- 图片仅允许必要类型(如 PNG/JPEG/WebP),按真实文件内容与尺寸校验,限制单文件和文章总大小。SVG 暂不开放后台上传。
- 内容文件和 Frontmatter 是权威信息;ChuSQL 中的记录可由全量扫描重新建立。
## 5. Git 内容管理工作流
### 5.1 后台上传与发布
1. 管理员登录,上传 `.md` 与附属图片;后端检查会话、CSRF 与限流。
2. 在隔离的暂存目录校验文件、解析 Frontmatter、检查重复 slug、限制大小和 Markdown 语法范围。
3. 展示预览;管理员明确点击“发布”。预览默认不公开。
4. 服务端通过受控文件操作写入仓库指定目录,创建 Git commit(提交者为固定服务身份,日志可附管理员操作 ID)。
5. 提交成功后生成/切换已发布内容快照,并更新 ChuSQL 索引;公开页面仅读取已发布快照。
6. 若索引更新失败,保留 Git 提交和待同步状态,由可重复执行的扫描任务恢复,不得静默显示“全部成功”。
### 5.2 本地 Git 编写
- 管理员可以在本地仓库编辑 Markdown,向受保护的主分支推送,或通过 PR 合并。
- 推荐在 CI 检查 Frontmatter、路径、大小、图片、链接及危险内容;只有已认证维护者可合并。
- 服务器采用**只读拉取/受控部署**,不接受互联网匿名推送;可使用带最小权限的部署凭证。
- **双入口写入存在冲突风险**:MVP 应只开放一个写入主入口。建议首先采用“后台上传写入本地 Git 仓库”,后续引入远端同步时再明确由 CI 部署作为唯一发布入口;或者反过来完全让后台创建 PR。禁止两个入口不加协调地向同一工作树写入。
### 5.3 更新、撤回、删除
- 更新是新的 Git commit;保留文章稳定 slug,必要时配置显式重定向。
- 撤回把 `status` 改为 `draft`,新快照不可公开访问。
- 删除从当前版本移除,但 Git 历史可能仍含内容;对于秘密泄露需要额外执行历史清理与凭证轮换,不能认为删除 commit 就彻底清除。
- 上传的草稿与私有资源必须与公开静态目录隔离,避免直链泄露。
## 6. 身份认证与抗垃圾页面
**MVP 采用单管理员、无公开注册、无公开投稿。** 未登录者没有任何创建、编辑、上传或 Git 写权限。这比单纯依靠验证码或限流更能从根源上避免垃圾页面泛滥。
安全控制:
1. 管理员账户配置在受保护的服务端环境或安全存储中;口令以 Argon2id 等成熟密码哈希存储,绝不保留明文。
2. 登录成功后发放服务端会话;Cookie 使用 `HttpOnly`、`Secure`、`SameSite`,设置到期时间和退出失效机制。生产建议支持 TOTP 2FA 或使用成熟身份代理实现 MFA。
3. 所有状态变更接口强制验证身份与 CSRF(包括上传、提交、发布和删除);校验 `Origin`,设置合理 CORS 策略。
4. 登录端点按 IP 与账户维度限流、失败退避和审计;上传限制文件大小、数量、总磁盘配额、请求频率、并发和执行耗时。
5. 反向代理和 API 分层限制请求体大小;服务仅接受预期 MIME 与文件结构;禁止 HTML/脚本执行、可疑链接协议与不受控资源嵌入。
6. Git 命令通过固定参数的进程 API 执行,**不用拼接 shell 字符串**;Git 工作树不允许访问任意仓库 hook,服务运行身份权限最小化。
7. 公开内容启用合理 CSP、HTML 清理、链接安全属性;后台不暴露到不必要的外部域名。
8. 采用日志审计:谁在什么时候上传、预览、发布、撤回、删除,以及对应 commit hash;不要记录口令或会话令牌。
若以后支持访客投稿:所有投稿必须进入**待审核区**,经管理员人工批准后才能进入正式 Git 分支;不得让访客直接触发公开发布。
## 7. API 草案
| 方法 | 路径 | 权限 | 说明 |
| --- | --- | --- | --- |
| `POST` | `/api/admin/login` | 公共、限流 | 管理员登录 |
| `POST` | `/api/admin/logout` | 管理员 + CSRF | 注销会话 |
| `GET` | `/api/posts` | 公共 | 查询已发布文章元数据 |
| `GET` | `/api/posts/:slug` | 公共 | 已发布文章信息(或由 Astro 直接读取文件) |
| `POST` | `/api/admin/uploads` | 管理员 + CSRF | 上传临时文件、验证 |
| `POST` | `/api/admin/posts/preview` | 管理员 + CSRF | 安全预览 |
| `POST` | `/api/admin/posts/publish` | 管理员 + CSRF | 固定目录落盘并 Git 提交 |
| `PATCH` | `/api/admin/posts/:slug` | 管理员 + CSRF | 更新元数据/内容 |
| `POST` | `/api/admin/posts/:slug/unpublish` | 管理员 + CSRF | 撤回文章 |
| `DELETE` | `/api/admin/posts/:slug` | 管理员 + CSRF | 删除当前版本 |
| `POST` | `/api/admin/index/rebuild` | 管理员 + CSRF | 从 Git 内容重建 ChuSQL 索引 |
API 路由仅为计划,后续以实现的最小接口为准;对发布、更新、删除操作加互斥与幂等处理,防止并发提交损坏仓库状态。
## 8. ChuSQL 集成与一致性
MVP 仅需要 `posts` 元数据与 `tags`,字段例如 `slug, title, description, status, published_at, updated_at, path, git_commit`。字段类型、DDL、过滤和分页查询应按现有 ChuSQL 协议确定,不能预设兼容 PostgreSQL 或 SQLx。
- `chusql-rs` 第一版支持:连接、超时、查询/执行、结果与类型映射、错误处理、断线识别、集成测试。
- 不依赖目前未实现或未经验证的 ChuSQL 多语句事务;应用端以 Git 快照为权威,数据库仅做派生索引。
- 每次发布记录 Git commit hash,索引带对应内容版本号。建立独立的 `rebuild-index` 命令与定期一致性检查。
- ChuSQL 不可用时,已生成的公开内容快照仍能被读取;列表、标签等可从文件快照构建简易只读索引。禁止在数据库错误时覆盖或删除文章文件。
- 上传发布时采用严格顺序和可恢复状态:校验 → 暂存 → Git commit → 更新已发布快照 → 尝试索引同步;出错后可依据 commit 重新同步。
- 文章页面不要因 ChuSQL 宕机而泄露内部错误或凭证。
## 9. 实施阶段与验收
### Phase 0 — 先验证接口
- [ ] 检查 ChuSQL 服务端网络协议、查询语法和持久化行为。
- [ ] 决定 Astro SSR 在容器内读取哪个受控内容目录。
- [ ] 确定 Git 仓库部署路径、最小权限和快照切换方式。
### Phase 1 — 纯文件博客 MVP
- [ ] Astro 页面:首页、文章详情、标签、归档、404、暗色模式。
- [ ] Markdown + Frontmatter 校验、Shiki 代码高亮、文章目录。
- [ ] Astro SSR 读取已发布内容快照;提供 RSS、sitemap 和 SEO 元信息。
- [ ] 测试异常文件、超大文件和 XSS 内容不会被执行。
### Phase 2 — 后台 + Git 发布
- [ ] 单管理员认证、会话与 CSRF。
- [ ] 上传、预览、发布、编辑、撤回、删除。
- [ ] 每次发布产生可追踪的 Git commit;冲突与重复提交有明确错误反馈。
- [ ] 通过限流、文件配额、路径校验和无公开注册测试。
### Phase 3 — ChuSQL 驱动与索引
- [ ] 开发 `chusql-rs` 最小客户端及协议测试。
- [ ] 建立文章元数据表、查询接口与索引同步。
- [ ] 完成从 Git 仓库重建索引的命令与故障注入测试。
- [ ] 验证 ChuSQL 故障期间公开阅读不中断、恢复后索引一致。
### Phase 4 — 部署与运维
- [ ] Docker Compose、Caddy TLS、仅开放必要公网端口。
- [ ] 持久化 Git 内容与资源;数据库卷、日志独立管理。
- [ ] 备份 Git 仓库(含远端镜像)与上传资源;定期进行真实恢复演练。
- [ ] 监测磁盘、接口错误、登录失败、索引同步延迟。
- [ ] 更新依赖、最小容器权限、限制容器挂载与网络访问。
**MVP 完成判定**:未经认证无法写入或发布;管理员可上传并发布一篇 Markdown,页面即刻可读,Git 中有对应提交;重启容器后内容存在;故意停止 ChuSQL 后仍可浏览已发布文章;重新建立数据库后可重建索引;恶意路径、超大文件和脚本注入测试均不能成功。
## 10. 生产就绪与风险边界
- **文章内容生产可用性**来自 Git、可恢复的文件快照、访问控制、备份及恢复演练,不取决于 ChuSQL 当前成熟度。
- **ChuSQL 仍按实验性组件管理**:在事务原子性、并发控制、进程崩溃恢复、备份/恢复、认证与长时间稳定性未经验证前,不作为任何不可重建数据的唯一存储。
- 文件与数据库之间不追求假想的跨系统原子事务,而采用幂等同步和可回放 Git 提交恢复一致性。
- 不把管理员凭证、Git 写入凭证或 ChuSQL 密码写入 Git 仓库、镜像层和日志。
## 11. 暂不纳入 MVP
- 访客注册、公开投稿、评论、点赞与复杂权限角色。
- 前端在线富文本编辑器、协同编辑和复杂草稿工作流。
- 全文搜索引擎、消息队列、分布式部署、对象存储、多租户。
- 自建 Markdown 解释器、通用插件机制和 ChuSQL ORM/SQLx 适配。
## 12. 近期第一步
优先确认 ChuSQL 现有协议,同时创建 Astro 静态界面与 Axum 认证/上传原型。先跑通**管理员上传 → 校验 → Git 提交 → 公开页面读取文件**,之后再接入 ChuSQL 元数据索引。这样即使数据库研发推迟,博客仍可独立推进。