Browse Source

docs: orphan auto-sweep is admin global config only (no env duplicate)

Made-with: Cursor
main
npmrun 9 hours ago
parent
commit
bf34c219a8
  1. 18
      docs/superpowers/specs/2026-04-18-post-media-assets-design.md

18
docs/superpowers/specs/2026-04-18-post-media-assets-design.md

@ -10,7 +10,7 @@
- 删改文章后易产生 **无人引用的孤儿文件**,磁盘只增不减。
- 缺少结构化元数据,难以做 **压缩、限宽、多格式** 等优化与后续 CDN 迁移。
本 spec 定义 **站内托管图片** 的元数据表、**保存文章时** 的引用同步、**孤儿文件的审查与清理**(默认 **不** 自动删除;**可配置** 自动清理;支持 **手动** 清理),以及 **上传后优化** 的首版约定。
本 spec 定义 **站内托管图片** 的元数据表、**保存文章时** 的引用同步、**孤儿文件的审查与清理**(默认 **不** 自动删除;**管理员全站开关** 控制是否自动清理;支持 **手动** 清理),以及 **上传后优化** 的首版约定。
## 2. 与既有 spec 的关系
@ -58,7 +58,7 @@
- **默认不自动删除**:系统 **不得** 在无人操作的情况下静默删除孤儿文件;须先满足「可删除」条件,且仅在 **自动清理已开启** 时由定时任务执行删除。
- **可审查**:提供固定入口(见 6.5)列出 **候选孤儿**(含预览信息、体积、`createdAt`、成为孤儿的时间等),供用户确认。
- **可配置自动清理**:通过配置项 **显式开启** 后,定时任务才对「已过宽限期的候选」执行与手动相同的删除逻辑。
- **可配置自动清理(全站)**:仅 **管理员** 可在后台切换 **全站** 自动清理开关(见 **6.4**);开启后定时任务才对「已过宽限期的候选」执行与手动相同的删除逻辑。普通用户不能为自己单独打开自动删
- **可手动清理**:在审查界面 **按条删除****批量删除当前筛选结果**(实现计划定义二次确认文案与权限)。
### 6.1 孤儿定义
@ -88,12 +88,15 @@
**顺序与失败**:单机首版可采用「删文件 → 删行」;若删文件失败应记录日志且 **不** 删行,便于重试。禁止删除仍被某 `post_media_refs` 引用的行。
### 6.4 自动清理配置与定时任务
### 6.4 自动清理配置与定时任务(管理员全站开关)
| 配置项 | 约定 |
|--------|------|
| **自动清理总开关** | **默认关闭**。仅当开启时,定时任务才执行 **6.3** 的删除。配置载体首选用 **环境变量**(如 `MEDIA_ORPHAN_AUTO_SWEEP_ENABLED=false`),若项目已有全局配置表/管理后台,实现计划可合并为同一真相源。 |
| **执行周期** | 可配置(如每小时);默认仅在开关开启时注册调度。 |
| **自动清理总开关** | **默认关闭**。**唯一真相源** 为站内 **全局配置**(与现网 `server/service/config/registry.ts` 注册项 + `PUT /api/config/global` + `requireAdmin` 一致)。实现计划新增布尔型 key(例如 `mediaOrphanAutoSweepEnabled`,名称以注册表为准),**不得** 再并行使用环境变量作为第二真相源(避免与后台显示不一致)。 |
| **谁可改** | 仅 **`role === 'admin'`** 可读写该 key;写入路径与现网管理端 **站点配置**(如 ` /me/admin/config`)一致,在实现计划中增加开关控件与说明文案(全站生效、误删风险、与审查页关系)。 |
| **谁可见** | 普通用户 **不** 需要看到该开关;若配置页仅管理员可进,则无需额外隐藏。 |
| **定时任务读配置** | 每次 sweep 前(或进程内短缓存,如 1 分钟)读取当前全局布尔值;为 `false`**不执行 6.3**。 |
| **执行周期** | 可由 **另一全局配置项**(如间隔分钟数,有上下限)或实现计划中的常量约定;**仅** 在开关为 `true` 时有意义。 |
| **范围** | 自动任务以 **系统内部 job** 身份运行,枚举 **全站** 满足「孤儿 + 已过宽限期」的 `media_assets`,对每一条调用与 **手动删除** 相同的 **6.3** 例程(含引用重检、用户隔离不得误删他人文件)。审查页仅展示 **当前登录用户** 自己的候选;**不得** 因「仅我的列表」而限制自动任务的全站职责(多租户下每行仍有 `userId`)。 |
**关闭自动清理时**:定时任务 **不跑删除**,或空转仅写指标;审查与手动删除 **不受影响**
@ -152,12 +155,13 @@
- 上传 → DB 有 `media_assets`;保存带图文章 → `post_media_refs` 正确;删图改文保存 → ref 更新。
- **默认**:自动清理关闭时,即使存在可删孤儿,**定时任务不得删除** 磁盘或行。
- **管理员开关**:非管理员无法将 `mediaOrphanAutoSweepEnabled`(或最终实现 key)设为 `true`;管理员关闭开关后,下一周期 sweep 即停止删除。
- **审查页**:列表与筛选正确;冷却中项不可删;可删项可单条/批量手动删除,且二次确认生效。
- **自动清理开启**:仅对已过宽限期且无引用的记录执行删除,逻辑与手动删除一致。
- **自动清理开启(全站)**:仅对已过宽限期且无引用的记录执行删除,逻辑与手动删除一致。
- 宽限期内 **不** 允许手动或自动删除刚上传未引用文件。
- 大图超宽被限宽;输出为 WebP;体积小于原图(典型 JPEG/PNG 样例)。
- 外链图片 URL 出现在正文中 → 无 DB 行、不被误删。
## 13. 后续流程
实现前另建 **`writing-plans` 实现计划**(迁移、上传与优化、引用同步、`/me` 审查页与删除 API、自动清理配置与可选 cron、Sharp 依赖与错误处理、与现有编辑器契约)。
实现前另建 **`writing-plans` 实现计划**(迁移、上传与优化、引用同步、`/me` 审查页与删除 API、**config registry 新 key + 管理端站点配置 UI**、读取该 key 的 cron、Sharp 依赖与错误处理、与现有编辑器契约)。

Loading…
Cancel
Save