Files
ChuBlog/PLAN.md
T

226 lines
14 KiB
Markdown
Executable File
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.
# 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 元数据索引。这样即使数据库研发推迟,博客仍可独立推进。