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