概述
本博客配套一套本地管理后台,运行在 pnpm dev 开发环境的 /admin 路径下,用于集中处理文章的写作、加密、上下线与云端同步,替代「开 IDE 改文件 → 开终端提交 → 开浏览器看效果」的多窗口流程。
它不是博客线上服务的一部分:
- 页面(
public/admin/)与本地接口(server/routes/admin-local/)均已加入.gitignore,不进入仓库,也不会被部署; - 它操作的对象是本地文件与本地 git 仓库,发布动作等价于常规的
git commit+git push; - 复用范围:本项目及其同源模板(上游 L33Z22L11/blog-v3,即纸鹿 Clarity 系)可按安装一节接入。
线上环境访问 /admin 不会得到任何东西:仓库克隆中不存在这些文件,生产构建里该接口也恒返回 404(详见下文安全模型)。
安全模型
后台没有账号、密码或 Token,其安全性完全建立在「只存在于本机 dev 进程」这一前提上,具体由以下措施保证:
| 措施 | 说明 |
|---|---|
| 不入库 | 后台两个目录与日志文件 .admin-log.jsonl 均被 git 忽略,仓库克隆与部署产物中都不存在 |
| 生产守卫 | 本地接口在 NODE_ENV === 'production' 时对所有请求返回 404 |
| 路径白名单 | 文件读写仅允许 content/posts/** 与 content/previews/** 下的 .md,拒绝目录穿越 |
| git 范围限定 | 提交与暂存只作用于 content/ 范围内的变更,项目其他文件不会被后台误提交 |
| 参数化调用 | git 与外部程序一律经 execFile 以数组参数调用,不经 shell 拼接,无命令注入面 |
作为交换,需要接受两点约束:
- 后台无鉴权——因此只在受信任的本机环境开启 dev 时使用它;
- 推送即部署——本站 push main 即触发线上部署,发布操作没有缓冲区,所以删除与推送都设置了确认环节。
git 推送复用本机已有的 git 凭据,后台自身不存储任何密钥。
安装
面向使用同源模板的博主,共三步:
- 将 kit 中的
public/admin/与server/routes/admin-local/复制到你项目的相同路径; - 在
.gitignore追加三行:
public/admin/ server/routes/admin-local/ .admin-log.jsonl
- 重启
pnpm dev,访问http://localhost:3000/admin。
kit 内附 INSTALL.md(含验收清单与 FAQ),也可以把整个 kit 交给 AI 助手,要求「按 INSTALL.md 安装」。
功能说明
后台由两个页面组成:列表页 /admin 与编辑页 /admin/edit.html,共用同一个本地接口。
列表页
顶部工具栏:
| 按钮 | 作用 |
|---|---|
| 「⇅ 同步云端」 | 打开本地与远端的对账视图(见「发布与同步」) |
| 「⬆ 批量导入 md」 | 选择多个本地 .md 文件,写入草稿区 content/previews/,同名文件跳过 |
| 「+ 新建草稿」 | 选择版式(tech / story)后进入编辑页,首次保存时创建 content/previews/<slug>.md |
| 「刷新」 | 重新扫描文章与操作日志 |
文章列表默认按 front matter 的 date 降序排列,每行展示真实标题(非文件名)、文件路径与修改时间,并以徽章标注状态:
- 🔒 加密:front matter 存在非空
password字段; - 草稿:
draft: true或位于草稿区content/previews/; - 已发布:其余情况。
勾选行首复选框后出现批量操作条:全选、上线、下线(转草稿)、删除、取消选择。
列表底部是「最近操作」卡片,展示本地日志 .admin-log.jsonl 的最新记录(操作类型、时间、目标文件与详情)。该日志为追加式 JSONL 文件,仅存本机,可作为后台操作的审计记录。
编辑页
点击列表行先进入详情视图(标题、封面预览、发布/修改时间、分类标签、加密状态、正文规模、文件路径),再显式选择操作,避免误触编辑:
- 「✎ 编辑正文与预览」:进入编辑模式;
- 「✎ Typora 打开」:调用本机 Typora 编辑当前文件(自动探测常见安装路径,未安装时给出提示,不影响其他功能);在 Typora 中保存后点「↺ 重读」同步回页面(详情页与编辑模式顶栏均有该按钮);
- 「删除」:需输入「删除」二字才能确认。删除仅作用于本地文件,已提交过 git 的内容仍可从历史找回。
编辑模式分三个标签:
① 正文与预览。左侧为 Markdown/MDC 原文,右侧为实时预览,输入停顿 400ms 后自动渲染。预览的目标是对齐博客的真实渲染,而非近似:
- 排版内嵌博客
article.scss,tech / story 双版式随文章类型切换; - MDC 组件按博客 SSR 产物的 DOM 结构复刻:
::alert五型配色、::tab可点击切换、::folding折叠、:quote[]引语卡、::pic图注、::link-card、::video-embed,以及行内:tip:blur:badge; - 未识别的 MDC 组件渲染为带组件名标注的虚线回退盒,不静默丢弃内容;
- 渲染区右上角有自检角标:
渲染 ✓ 12ms表示正常;自动补全标题空格时以黄字提示数量;渲染异常时以红字给出原因; - Markdown 标准要求
#与标题文字之间有空格,漏写的####标题会被自动补全——预览与保存共用同一修正逻辑,保证线上解析一致。
渲染使用的 markdown-it 与 highlight.js 已本地化到 public/admin/vendor/,离线可用;在线字体加载失败时回退系统字体。
② 文章信息。结构化编辑 front matter:
| 字段 | 说明 |
|---|---|
| 标题 | 必填,留空不能保存 |
| 发布时间 | 必填,「⏱ 现在」一键填入当前时间 |
| 摘要 / 封面图 URL | 对应 description / image |
| 分类 / 标签 | 逗号分隔,对应 categories / tags |
| 版式 | tech(技术)或 story(生活) |
| 自定义路径 | 对应 permalink |
| 草稿 | 勾选后不出现在线上文章列表 |
| 保存时更新 updated | 默认勾选,每次保存自动写入当前时间 |
③ 加密管理。顶部横幅实时显示当前文件的加密状态;三个输入框对应 front matter 的 password / passwordHint / passwordNote(密码留空即为普通文章);「一键解除加密」清空三项。加密原理与线上效果见《博客文章加密教程》。
编辑模式工具栏的其余动作:
| 按钮 | 作用 |
|---|---|
| 「保存(写入本地文件)」 | 写入本地文件,dev 热更新立即生效,不产生 git 提交 |
| 「☁️ 推送上线」 | 预检 → 确认 → 保存、提交并推送(见下文) |
| 「↺ 重读」 | 重新读取磁盘文件,同步 Typora 等外部修改;编辑器有未保存修改时会先要求确认 |
| 「↻ 刷新预览」 | 立即重新渲染右侧预览(通常无需手动,输入停顿 400ms 后自动渲染) |
| 「← 返回列表」 | 返回列表页 |
发布与同步
单篇推送上线
「☁️ 推送上线」按以下流程执行:
- 预检:
git ls-remote检查 GitHub 连通性与本地/远端的领先落后关系,连不通时确认按钮不可用; - 确认:模态框列出目标文件与预检结果;
- 执行:保存 →
git add该文件 → 有变更才提交(message 为content: 更新《标题》(管理后台推送))→git push origin main;若远端领先,自动pull --rebase --autostash后重试一次; - 反馈:显示 commit hash;push main 触发 Vercel 自动部署,约 1~2 分钟后线上生效。
批量上线 / 下线
勾选多篇文章后,「上线 / 下线」一次完成三件事:改写各文件的 draft 字段 → 提交(message 注明「博客后台上线/下线《标题》…」)→ 推送部署。下线后线上列表即隐藏这些文章,重新「上线」即可恢复;git 历史完整记录每一次操作。
同步云端
「⇅ 同步云端」是发布前的对账视图,先检查、后操作:
- 状态:GitHub 连通性(网络抖动自动重试一次)+ 本地与远端的领先/落后关系;
- 明细:列出
content/范围内未提交的变更(修改、新增、删除分色标注)与本地领先的提交(hash、说明、日期),推送前明确「将要推送的是什么」; - 操作:本地领先时用「⬆ 推送变更到云端」(仅暂存
content/范围);云端领先时(例如曾在 GitHub 网页端修改)用「⬇ 拉取云端更新」(pull --rebase --autostash,保护未提交的本地修改)。
典型工作流
新写一篇文章:「+ 新建草稿」选择版式 → 左写右看实时预览 → 「保存」写入草稿区 content/previews/ → 定稿后将文件移入 content/posts/<年份>/ → 「☁️ 推送上线」。
当前版本暂未提供草稿区到正式区的移动界面(本地接口已预留 move 动作,界面待接入),迁移文件这一步需在文件管理器或 IDE 中完成。
下线一批旧文:列表勾选 → 「下线(转草稿)」→ 确认。需要恢复时重新勾选「上线」。
在其他设备改了文章(如手机上的 GitHub 网页 / App):回到本机打开「⇅ 同步云端」,状态显示云端领先时点「⬇ 拉取云端更新」。
技术实现
- 本地接口:一个 nitro 服务路由(
server/routes/admin-local/action.post.ts)承载 13 个动作:list/get/write/delete/move/openTypora/push/precheck/batchDraft/log/syncCheck/syncPush/syncPull。全部文件操作经路径白名单校验,全部 git 调用经execFile数组参数执行。 - 预览保真方法:以 dev 服务器的 SSR 产物为真值,逐组件比对 DOM 结构与类名,而不是照组件源码推断。行内
:quote[]实际渲染为块级引语卡这类差异,只有对照真值才能发现。 - SQLite 锁:预览期高频写文件会触发内容监听器并发写
.dataSQLite 库,曾导致database is locked崩溃;已通过 pnpm 补丁为 db0 连接器启用 WAL 与busy_timeout,写库由报错改为等待。 - 已知取舍:代码高亮用 highlight.js 近似博客的 Shiki 双主题(观感接近,但不是同一实现);表格滚动吸附特效未复刻。预览终归是辅助手段,最终效果以线上为准。
边界
- 后台只管理本机文件与本地 git。它没有也不需要鉴权,前提是仅在受信任的本机 dev 环境使用;远程场景(手机等)请使用 GitHub 网页 / App 修改,回到本机后通过「⇅ 同步云端」拉取。
- 「推送」即触发线上部署,没有预发布环节;因此删除需要输入确认词,推送需要通过预检并手动确认。
- 预览是高保真近似而非等价实现,正式发布前可在真实路由(草稿文章在
/preview页)做最终确认。

评论区
评论加载中...