# LaraBlog 平台一期

## 状态
- 状态：已定稿
- 创建：2026-08-11 17:14
- 最近更新：2026-08-11 17:53

## 背景
SaBlog-X 1.6（约二十年前设计）需迁移到现代 Laravel 栈。迁移目标不是「功能克隆」，而是：**保留有价值的内容、SEO 权重与核心写作/阅读体验**，用当代博客实践替换过时、产垃圾或维护成本不合理的设计。

参考源：https://github.com/neatstudio/sablog-archive

## 现代化取舍原则
1. **内容与 SEO 优先**：文章/分类/标签 ID 与关键旧 URL 保留，避免权重归零
2. **不迁垃圾协议与死技术**：Trackback/Pingback、WAP、旧 searchindex、旧 PHP Admin、Feedsky 等一律不实现
3. **用当代能力替换**：AI 评论审核代替巨型敏感词表为主力；对象存储代替本地附件目录；Workerman 承载 LLM；Filament 后台
4. **导入可跳过废弃表**：`sablog_trackbacks` / `sablog_trackbacklog` / `sablog_searchindex` / `sablog_sessions` 等只记录「已跳过」，不入新库
5. **旧入口若被爬虫打到**：对明确废弃路径返回 **410 Gone**（不实现业务）

## 目标
- 可运行的现代博客：前台阅读/评论/搜索/归档 + Filament 5 后台
- 严格兼容 sablog **内容向**伪静态与关键 query URL；导入后文章/分类 ID 一致
- 多主题、插件框架、SEO/GEO、S3 兼容附件、Workerman AI 运行时
- `sablog:import`：内容与附件上云；跳过过时模块并报告

## 范围

### In scope
1. Laravel 12 + Livewire 4 + Filament 5 + Spatie（permission、settings、feed、sitemap、activitylog）
2. 博客核心：文章、分类、标签、评论、附件、友情链接、用户/角色、站点片段（stylevars）
3. Legacy **内容 URL** + 新 canonical（见 URL 矩阵）
4. 主题引擎 + `default` + 示例主题（主题 zip 存本地 `themes/`）
5. 插件框架 + payment / membership / plugin-marketplace / theme-marketplace（骨架）+ ai-comment-moderation（可运行管道）
6. SEO/GEO：meta、OG、JSON-LD、sitemap、rss（含 ?cid）、`llms.txt`
7. 对象存储附件全链路 + legacy `/attachment.php` 与 `/attachments/{path}`
8. Workerman：`ai-content`、`ai-moderation`
9. `sablog:import` 幂等 upsert + 跳过废弃表报告
10. 防刷：rate limit；XSS purifier；附件 MIME 白名单
11. 可选现代增强：文章 `slug`（不取代 `/show-{id}.shtml`）
12. **正文格式双轨**：`content_format = html|markdown`；站点默认新作为 Markdown；导入默认保留 HTML；可选 HTML→Markdown 转换开关

### Out of scope（明确不迁移 / 不复刻）
- **Trackback / Pingback**（含表、后台、前台、开启开关）；`/tburl.php`、`/trackback.php` 仅 410
- WAP、旧 `searchindex` 搜索缓存表、自建 sessions 表、Feedsky/旧 JS 挂件
- 旧 `/admin/*` PHP 后台原样兼容（新后台 Filament `/admin`；旧路径 410）
- 旧主题静态 `/templates/default/*` 原样托管
- 真实支付/会员计费/远程商城结算；多站点 SaaS
- Workerman 替代主站 HTTP；绑定单一 LLM 厂商；应用侧长期存附件
- 以巨型政治/广告敏感词表为唯一防垃圾手段（可保留极简词表作预过滤，主力为 AI + rate limit）

### 延期（二期+，本期只预留）
**自动配图 / 由正文生成封面**（老 sablog 无现代「特色图」概念）：
- 能力意向：
  1. **自动配图**：从正文首图 / 附件图 / OG 候选中选封面
  2. **生成配图**：用标题+摘要（或 LLM 提示）调用文生图 / 模板渲染，产出封面，写入对象存储
- 执行方式：Workerman / 队列 Job + 可重跑 Artisan 脚本，**批量慢生成**，不堵发布主路径
- 本期只做：表字段与状态枚举预留、`GenerateArticleCoverJob` 空壳、SPEC/清单占位；**不做**真实选图/生图对接
- 封面文件同样只存对象存储，规则同附件

## 方案要点

### 技术栈
| 层 | 选型 |
|---|---|
| 框架 | Laravel 12、PHP 8.2+、Livewire 4 |
| 后台 | Filament 5 |
| Spatie | permission、settings、feed、sitemap、activitylog |
| 附件 | 自建 `attachments` + S3 disk（不用 medialibrary） |
| AI | Workerman + Redis；`LlmProvider`（OpenAI 兼容 + Stub） |
| 净化 / 图 | mews/purifier；Intervention Image（临时处理后退对象存储） |

### 数据模型
- `articles`：id、category_id、user_id、title、content、**content_format(`html`|`markdown`)**、description、keywords、slug(nullable)、published_at、views、comments_count、stick、visible、close_comment、read_password(nullable，兼容旧私密文)、ai_summary、ai_suggestions、legacy_attachments、**cover_***（二期配图预留，见下）
- 封面预留字段：`cover_disk`、`cover_path`、`cover_source`（`none`|`manual`|`attachment`|`content_image`|`generated`）、`cover_status`（`none`|`pending`|`ready`|`failed`）、`cover_generated_at`
- **无** `trackbacks` 表；**无** `close_trackback` / `trackbacks_count`

### 正文格式（HTML / Markdown）
- **原则**：旧 sablog 正文是 HTML；**新写作默认 Markdown**（未来主路径）
- **文章级开关**：`articles.content_format`；后台编辑器按格式切换（Markdown 文本域 / HTML 富文本）
- **导入双模式**（两份能力，同一命令开关）：
  1. **`raw`（默认）**：正文保持 HTML，`content_format=html`，保留 sablog `[attach=id]`
  2. **`markdown`**：HTML→Markdown，`content_format=markdown`；因 `[]` 是 Markdown 保留字符，**导入时把 `[attach=id]` 改写成 Markdown 安全引用**，不把对象存储 URL 写进库
- **附件引用策略（已定）**：
  | 场景 | 数据库保存 | 预览/前台输出 |
  |---|---|---|
  | raw/HTML | `[attach=123]`（原样） | 渲染期解析为 `<img>`/`<a>`，href/src 用稳定入口 `/attachment.php?id=123`（再 302 到 S3） |
  | markdown | 图片 `![name](attach:123)`；文件 `[name](attach:123)` | CommonMark 后把 `attach:123` 换成 `/attachment.php?id=123` |
- **不在导入时写死 S3/CDN 路径**：避免换桶/换域名后正文失效；**平时 DB 只存引用，输出时转换**
- **站点设置**：`default_content_format=markdown`；导入模式由 CLI `--mode=raw|markdown` 决定（可覆盖 settings）
- **渲染**：`ContentRenderer::toHtml()` = 格式转换 + attach 水合 + Purifier
- `categories`、`comments`（moderation_status：`pending`|`pending_ai`|`approved`|`rejected`|`needs_human`）、`tags` + `article_tag`、`attachments`、`links`、`stylevars`、`plugins`、`users`（password + password_legacy）
- Settings：站点、SEO、active_theme、LLM、存储、正文格式默认/导入策略（**无** trackback_enabled）

#### 导入映射（摘要）
| 源 | 目标 | 规则 |
|---|---|---|
| articles 核心字段 | articles.* | 保留 id/cid/uid/views/close_comment/read_password 等 |
| articles.content | content + content_format | 默认 `html`；若开启转换则转为 Markdown 且 format=`markdown` |
| articles.trackbacks / closetrackback | — | **忽略** |
| articles.attachments serialize | legacy_attachments + attachments 表 | 文件上云 |
| comments.visible | moderation_status | 1→approved，0→pending |
| tags.aids | article_tag | 拆 pivot |
| users.password | password_legacy | 无盐 MD5 → 登录升级 bcrypt |
| attachments.* | attachments.* | 逐条上云，保留 downloads |
| links / stylevars / settings | 对应表/Settings | 直通或键映射 |
| sablog_trackbacks / trackbacklog / searchindex / sessions | — | **跳过并计入报告** |

### 附件与对象存储
- 一律 S3 兼容；临时文件用完即删
- `/attachment.php?id=`、`/attachments/{path}` → 去重计数后 302
- 正文 `[attach=id]` 解析为对象存储 URL

### URL 矩阵

#### Legacy 内容向（必须业务可达）
`/`、`/index.php?action=…`、`/show-{id}[-{page}].shtml`、`/category-{cid}[-{page}].shtml`、`/archives…`、`/tagslist…`、`/index.php?action=tags&item=`、`/comments…`、`/search…`、`/links.shtml`、`/reg.shtml`、`/login.shtml`、`/rss.xml[?cid=]`、`/sitemap.xml`、`/attachment.php`、`/attachments/{path}`、`/post.php`（登录/注册/评论/搜索）

#### 新 canonical
- `/tag/{name}`（自旧 tags query 301）
- `/llms.txt`
- 可选 `/posts/{slug}`（不取代 show-id）

#### 明确废弃（410，无业务）
- `/tburl.php`、`/trackback.php`
- 旧 `/admin/*.php`（非 Filament 面板）
- WAP 相关路径（若出现）

### 主题 / 插件 / Workerman / 导入
同前：主题回退、插件生命周期、AI 双队列、`sablog:import` 幂等与「跳过废弃表」报告；不删源数据。

## 验收标准
- [x] 内容向 Legacy URL 可达；文章/分类 ID 与源一致（`upsertWithId` + fixture 回归）
- [x] **无** Trackback 功能/表/设置；tb 入口 410
- [x] 导入报告含「跳过 trackbacks/searchindex/sessions」计数
- [x] 正文：新建默认 Markdown；导入默认可为 HTML；格式开关可切换；Markdown/HTML 渲染正确；`--mode=markdown`
- [x] 前台评论闭环（含 AI 管道 stub）；仅 approved 展示
- [x] Filament 管理内容与配置（含 content_format；无 trackback 菜单）
- [x] 附件对象存储（生产 S3；开发 local）；双入口 302；主题可切换；插件可启停
- [x] SEO/GEO 正常；Web 无同步 LLM；legacy MD5 可升级登录
- [x] 导入幂等且不改源

## 开放问题
- [x] 现代化：剔除 Trackback 等过时能力 — 已定
- [ ] 部署环境对象存储凭据；开发可用 MinIO / fake

## 变更记录
| 时间 | 原因 | 变更 |
|------|------|------|
| 2026-08-11 17:14 | 初稿 | 创建 SPEC |
| 2026-08-11 17:20 | qodercli A1–A8 | URL/附件/映射等 |
| 2026-08-11 17:25 | qodercli 映射缺口 | 补字段 |
| 2026-08-11 17:26 | 三轮无阻塞；用户确认 | 定稿 |
| 2026-08-11 17:35 | 用户：勿迁 trackback 等过时设计 | 增加现代化取舍；删除 Trackback 全链路；废弃入口 410；导入跳过垃圾表 |
| 2026-08-11 17:42 | 用户：HTML 旧文 / Markdown 未来 | 增加 content_format 双轨、站点/导入开关、可选 HTML→MD 转换 |
| 2026-08-11 17:50 | 用户：导入双份 + attach 与 MD 保留字 | 明确 DB 存引用、渲染期解析；`--mode=raw|markdown`；attach: 协议 |
| 2026-08-11 17:53 | 用户：自动配图/生成配图可后推 | 延期章节 + cover 字段/Job 空壳预留 |
