补齐后端最小功能和前端
This commit is contained in:
1 parent
a8c22b1b07
commit
a6179aba6a
56 files changed
+8126
-326
No files matched your search
+100
-67
@@ -16,92 +16,125 @@
|
||||
- 设回 `reader` 或 `enabled:false` 会撤回发布授权,并使现有网站会话失效。
|
||||
- 禁止管理员停用自己或取消自己的管理角色。
|
||||
|
||||
## 本地 Git 工作流
|
||||
## 克隆个人文章仓库
|
||||
|
||||
- 先通过可信渠道核对服务器 Ed25519 主机密钥指纹;不要禁用主机密钥检查。
|
||||
- 主机密钥保存在独立持久卷,重建容器不会更换。
|
||||
- 所有发布者使用同一个 OS 账户 `git`,身份由对应公钥的强制命令绑定,不由 Git author/email 决定。
|
||||
先通过可信渠道核对服务器主机密钥指纹,再在本机 `~/.ssh/config` 配置连接:
|
||||
|
||||
```sh
|
||||
# ~/.ssh/config
|
||||
```sshconfig
|
||||
Host chublog
|
||||
HostName blog.example.com
|
||||
Port 2222
|
||||
User git
|
||||
IdentityFile ~/.ssh/id_ed25519
|
||||
IdentitiesOnly yes
|
||||
```
|
||||
|
||||
# 无论作者是谁,别名都是 content.git;服务端按认证身份映射个人仓库。
|
||||
# 首次 clone 自动创建服务器裸仓库,作者无须自己创建裸仓库。
|
||||
将域名、端口和私钥路径替换为部署者提供的值。主机密钥检查应保持开启。服务器根据公钥识别作者,不使用 Git 的 author/email 判定身份。
|
||||
|
||||
```sh
|
||||
git clone chublog:content.git my-articles
|
||||
cd my-articles
|
||||
# 仓库已有内容时,每轮编辑前先 git pull --ff-only。
|
||||
# 创建 index.txt 和正文,格式见下文。
|
||||
git add index.txt posts/first
|
||||
```
|
||||
|
||||
每位作者都使用 `content.git` 别名。服务器将别名映射到该作者的独立仓库,并在首次访问时创建裸仓库,作者无需服务器 shell。仓库已有提交时,每轮编辑前先执行 `git pull --ff-only`。
|
||||
|
||||
## 创建 TOML 索引
|
||||
|
||||
在仓库根目录创建 UTF-8 文件 `index.toml`,每篇文章使用一个 `[[articles]]` 表:
|
||||
|
||||
```toml
|
||||
[[articles]]
|
||||
id = "first"
|
||||
folder = "posts/first"
|
||||
title = "第一篇文章"
|
||||
description = "文章简介"
|
||||
tags = ["Rust", "随笔"]
|
||||
public = true
|
||||
# cover = "cover.png"
|
||||
# entry = "main.md"
|
||||
```
|
||||
|
||||
`id` 和 `folder` 用于标识文章及其目录。文章元信息仅接受以下字段:
|
||||
|
||||
| 字段 | 含义与默认值 |
|
||||
| --- | --- |
|
||||
| `title` | 必填标题,最多 240 字节 |
|
||||
| `description` | 简介,省略时为空,最多 1000 字节 |
|
||||
| `tags` | 标签,默认空数组,最多 12 项,每项最多 80 字节 |
|
||||
| `cover` | 可选封面,填写同文章目录中的图片文件名 |
|
||||
| `public` | 是否公开,默认 `false` |
|
||||
| `entry` | 入口文档名,默认 `main.md` |
|
||||
|
||||
作者身份由 SSH 公钥绑定的账户确定。创建时间、首次公开时间和修改时间由服务端生成,以 UTC 时间保存。索引不接受 `author`、`date`、`updated`、精华或权限等额外字段。正文不再使用 Frontmatter。
|
||||
|
||||
文章 ID 在作者内唯一,允许 1 到 40 位小写字母、数字和中间短横线。目录为 `posts/<目录名>`,目录名最多 80 字节并遵循 slug 规则。ID 和目录名不能使用保留名称,例如 `admin` 或 `api`。同一目录不能登记多次。
|
||||
|
||||
文件名只允许 ASCII 字母、数字、短横线、下划线和点,最多 100 字节,不能以点开头或含 `..`。入口允许 `.md`、`.markdown` 和 `.txt`,扩展名须为小写。索引最多 64 KiB、1000 篇文章。要撤回全部文章,明确写入 `articles = []`;空文件缺少文章字段,会暂存并保留原文章。
|
||||
|
||||
## 编写多页文章
|
||||
|
||||
示例目录:
|
||||
|
||||
```text
|
||||
index.toml
|
||||
posts/
|
||||
└── first/
|
||||
├── main.md
|
||||
├── chapter.md
|
||||
└── cover.png
|
||||
```
|
||||
|
||||
`main.md` 内容:
|
||||
|
||||
```markdown
|
||||
# 第一篇文章
|
||||
|
||||
[阅读第二页](chapter.md#details)
|
||||
|
||||

|
||||
```
|
||||
|
||||
`chapter.md` 内容:
|
||||
|
||||
```markdown
|
||||
# 第二页
|
||||
|
||||
## Details
|
||||
|
||||
[返回入口](./main.md)
|
||||
```
|
||||
|
||||
服务端从入口沿文章内相对链接收集页面,允许循环链接,每篇最多 64 个可达页面。链接目标必须是同目录的文本文件,可以带 `#锚点`,不支持子目录、`../`、编码路径和查询参数。相对链接缺少目标文件时,整份索引暂存,原文章不更新。普通 HTTP、HTTPS、mailto 和站内绝对链接继续受安全检查。
|
||||
|
||||
未登记目录、从入口无法到达的文档,以及未被页面引用的图片不进入阅读快照或数据库。封面即使未在正文引用,也作为文章资源导入。所有上传文件仍受白名单、安全检查和仓库配额约束。`.txt` 页面通过 `format: text` 返回,阅读端须作为纯文本显示。
|
||||
|
||||
参考[索引样例](../content/index.toml)、[入口样例](../content/posts/welcome/main.md)和[第二页样例](../content/posts/welcome/chapter.md)。
|
||||
|
||||
## 提交并验证发布
|
||||
|
||||
```sh
|
||||
git add index.toml posts/first
|
||||
git commit -m 'Publish first article'
|
||||
git push -u origin main
|
||||
```
|
||||
|
||||
## 文章目录与清单
|
||||
服务端会校验提交并自动导入。站内文章 ID 为 `作者名~文章ID`,例如 `/api/posts/alice~first`。文章 API 返回入口正文、页面列表和资源地址;页面通过 `/api/posts/alice~first/pages/chapter.md` 读取。前端需将文档相对链接映射到返回的页面 URL,并保留锚点。
|
||||
|
||||
仓库结构示例:
|
||||
|
||||
```text
|
||||
index.txt
|
||||
posts/
|
||||
└── first/
|
||||
├── article.md
|
||||
└── cover.png
|
||||
```
|
||||
|
||||
`index.txt` 为 UTF-8 三列文本,以空格或 Tab 分隔,无表头,允许空行:
|
||||
|
||||
```text
|
||||
first posts/first article.md
|
||||
notes posts/my-notes notes.markdown
|
||||
```
|
||||
|
||||
- 三列依次为**文章 ID、相对文件夹、正文文件名**。
|
||||
- ID 在作者内唯一,支持 1–40 位小写字母、数字及中间短横线,另须避开保留名称。
|
||||
- 目录必须是 `posts/<目录名>`,目录名遵循 slug 规则,最多 80 字节;文件名只允许 ASCII 字母、数字、短横线、下划线与点,不能以点开头或含 `..`。
|
||||
- 同一目录不能重复登记;正文可以任意命名,扩展名为 `.md`、`.markdown` 或 `.txt`。
|
||||
- 索引所指目录和正文必须存在,路径穿越和子目录正文被拒绝。
|
||||
- 索引上限 64 KiB、1000 项。
|
||||
|
||||
## 正文与图片
|
||||
|
||||
- 正文沿用 YAML Frontmatter(参考[正文样例](../content/posts/welcome/index.md)),包含 `title/date/updated/status/tags/description`;`slug` 可省略,如填写则必须等于索引 ID。
|
||||
- `.txt` 正文也需要 Frontmatter,API 通过 `format: text` 表明正文应作为纯文本展示;其他正文为 `format: markdown`。
|
||||
- 图片置于同一目录,通过 `` 引用。
|
||||
|
||||
## 新增、修改与撤回
|
||||
|
||||
| 作者操作 | 系统处理 |
|
||||
| 提交内容 | 结果 |
|
||||
| --- | --- |
|
||||
| 新建正文并在索引新增一行 | 校验后导入文章,在 ChuSQL 创建作者、ID、正文路径、状态等元信息 |
|
||||
| 修改正文或索引中的目录/文件名,保留 ID | 更新同一文章;站内 ID 不随目录移动而变化 |
|
||||
| 删除索引中的一行 | 移除当前阅读内容、图片入口及对应数据库元信息,无需先删除本地正文 |
|
||||
| 把索引清空 | 移除该作者所有当前文章,不影响其他作者 |
|
||||
| 有效索引、新增文章且入口存在 | 导入文章并创建数据库元信息与页面记录 |
|
||||
| 有效索引、修改正文或元信息 | 更新文章,保留首次公开时间;内容实际变化时更新修改时间 |
|
||||
| 有效索引、删除文章表 | 撤回文章、页面、资源入口及数据库派生记录 |
|
||||
| 有效索引、入口文件或目录缺失 | 将该文章视为不存在,撤回旧版本;其他有效文章仍可导入 |
|
||||
| TOML 缺失、语法错误、未知字段或元信息无效 | Git 提交暂存,不修改该作者原有文章,等待修复后的下一次推送 |
|
||||
| 脚本、非法文件类型、危险路径或内容超限 | 拒绝整个推送,远端分支不前进 |
|
||||
|
||||
- 未被索引选中的正文及目录视为无效内容,不导入阅读快照或数据库;图片只有被选中正文引用才作为公开资源导入;仍计算仓库容量并执行安全校验。
|
||||
- 删除正文但保留其索引项属于错误,整次推送会被拒绝。
|
||||
- `status: draft` 可保留登记但不公开;物理删除文件和撤回文章均不会擦除 Git 历史。
|
||||
`public = false` 的内容不会由公共文章、页面或资源接口返回。登录后查看内部文章的功能仍在待办中。删除和撤回不擦除个人 Git 历史,也不收回作者已克隆的副本。
|
||||
|
||||
## 提交与并发限制
|
||||
## 提交限制与状态查询
|
||||
|
||||
- MVP 每次只接受**一个直接继承个人远端 main 的提交**,首次仅允许一个根提交。
|
||||
- 禁止 merge、force push、删除 main、标签及其他分支;多次本地提交应先整理为一次提交,再变基到最新远端。
|
||||
- 同一作者在多台电脑操作仍需处理并发冲突,不同作者互不争用同一个仓库锁。
|
||||
每次推送只接受一个直接继承个人远端 `main` 的提交,首次必须是根提交。禁止 merge、force push、删除 `main`、标签和其他分支。多次本地提交须先整理为一次提交,再变基到最新远端。同一作者在多台电脑操作仍需处理冲突,不同作者使用不同仓库锁。
|
||||
|
||||
## 作者隔离与文章地址
|
||||
管理员通过 `GET /api/admin/status` 查看状态。`commit` 是当前生效作者提交映射的集合摘要,`indexed_commit` 是数据库已同步的集合版本。`pending` 按作者返回暂存提交和索引错误。暂存提交不会替换生效版本,API 重启后仍保留原文章和暂存状态。
|
||||
|
||||
- 站内文章 ID 为 `作者名~文章ID`,例如 Alice 的 `first` 对应 `/api/posts/alice~first`;不同作者可以使用相同的本地 ID。
|
||||
- 服务端分别保存每位作者的 Git 对象与历史,SSH 不能指定别人的仓库路径;作者无法通过 clone 或按提交哈希 fetch 读取其他作者草稿。
|
||||
- 作者自己已克隆的历史仍可在本地保留,不能靠撤回收回副本。
|
||||
|
||||
## 发布状态
|
||||
|
||||
- API 自动同步,一般约 2 秒,数据库重建、失败重试或较多作者可能延迟。
|
||||
- `GET /api/admin/status` 的 `commit` 是作者提交映射的集合摘要,不是任一作者 Git 提交;`indexed_commit` 表示数据库已同步的集合版本。
|
||||
- Git 接受表示接收校验完成,不保证数据库已同步。
|
||||
- 当前不做站长内容审核,审核计划见 [TODO](../TODO.md)。
|
||||
同步通常在下一轮后台处理时完成。数据库失败至少间隔 30 秒重试,作者较多或索引重建时可能延迟。Git 接受不代表文章已公开或数据库已同步。站长审核尚未启用,计划见 [TODO](../TODO.md)。
|
||||
Reference in new issue
Block a user