- docs/install.md:全新安装指南(环境要求/.env/验收清单/常见问题) - docs/import.md:Sablog 导入全解(命令参数表/数据映射/附件短代码/301 兼容/S3 同步/幂等重跑/检查清单) - docs/deploy.md:补生产迁移顺序、上线前检查清单、调度器实际内容 - Workerman 进程文件(pid/status/log)统一写入 storage/framework 与 storage/logs,不再出现在项目根目录;.gitignore 排除并清理根目录残留 - README 文档导航补 install/import
168 lines
8.6 KiB
Markdown
168 lines
8.6 KiB
Markdown
# LaraLog
|
||
|
||
基于 **Laravel 12 + Filament 5 + Livewire 4 + Spatie 生态** 的现代化博客系统,从 SaBlog-X 1.6 完整迁移而来:
|
||
|
||
- **脚本迁移**:`php artisan sablog:import` 一键从老库迁入全部数据(文章/分类/评论/标签/友链/用户/附件),保留原始 ID,老 URL 全部 301 兼容
|
||
- **多主题**:`themes/` 目录即皮肤,后台一键切换/上传 ZIP;内置 sablog 经典风 + modern 简约风两套
|
||
- **插件系统**:`plugins/` 目录 + 钩子系统(action/filter),ZIP 安装 + 可选远程市场
|
||
- **内置插件**:SEO & GEO(JSON-LD/OG/llms.txt/Markdown 导出)、AI 评论审核 + 内容润色(Workerman 异步)、支付(支付宝/微信/沙箱)、会员(套餐订阅 + 付费文章)
|
||
- **附件全走 S3**:R2 / COS / OSS 兼容,新上传零落盘,`attachments:sync-s3` 一键同步老附件(大文件 Multipart)
|
||
|
||
## 技术栈
|
||
|
||
| 组件 | 版本 | 说明 |
|
||
|------|------|------|
|
||
| Laravel | ^12.0 | 应用框架 |
|
||
| Filament | ^5.7 | 后台面板(zh_CN) |
|
||
| Livewire | ^4.4 | 前台交互 |
|
||
| Workerman | ^5.2 | 常驻进程:队列消费者 + WebSocket 进度推送 |
|
||
| yansongda/pay | ^3.7 | 支付宝 / 微信支付 |
|
||
| spatie 库 | — | permission / medialibrary / sitemap / robots / tags / backup |
|
||
| league/commonmark | ^2.9 | Markdown 渲染(GFM) |
|
||
| league/html-to-markdown | ^5.1 | 老 HTML 内容转换 |
|
||
| MySQL | 8.x | 数据库 |
|
||
|
||
## 快速开始
|
||
|
||
```bash
|
||
# 1. 安装依赖
|
||
composer install
|
||
cp .env.example .env
|
||
php artisan key:generate
|
||
|
||
# 2. 配置 .env(MySQL 8)
|
||
DB_DATABASE=laralog
|
||
DB_USERNAME=root
|
||
DB_PASSWORD=
|
||
|
||
# 3. 迁移 + 种子(创建 admin@laralog.test / password)
|
||
php artisan migrate --seed
|
||
|
||
# 4. 启动(Herd 或 artisan serve)
|
||
php artisan serve
|
||
|
||
# 5. 后台:http://laralog.test/admin
|
||
```
|
||
|
||
## 迁移老 Sablog
|
||
|
||
```bash
|
||
# 原始导入(内容保持 HTML,[attach=xx] 渲染时解析)
|
||
php artisan sablog:import \
|
||
--database=sablog --host=127.0.0.1 --port=3306 \
|
||
--username=root --password=xxx \
|
||
--attachments-dir=/path/to/old/attachments --sync-attachments
|
||
|
||
# 同时把内容转换为 Markdown([attach=xx] 转为 {{attach:xx}} 令牌)
|
||
php artisan sablog:import ... --convert-markdown
|
||
|
||
# 事后单独转换 / 同步附件到 S3
|
||
php artisan content:convert --all
|
||
S3_ACCESS_KEY=... S3_BUCKET=... S3_ENDPOINT=... php artisan attachments:sync-s3 --legacy-dir=/path/to/old/attachments
|
||
```
|
||
|
||
> 不迁移的过时功能:trackback(引用通告,垃圾来源)、搜索缓存表、验证码(由 AI 审核 + 蜜罐 + 频控取代)、WAP、广告位变量。
|
||
|
||
## 主题
|
||
|
||
- 目录:`themes/{name}/`,含 `theme.json`(标题/版本/描述/作者)+ `views/**` + `assets/`
|
||
- 激活主题的 views 目录前置到全局视图路径:主题覆盖同名视图,缺失自动回退默认视图
|
||
- 资产开发期由 `/themes/{name}/assets/...` 流式返回;生产可 `php artisan theme:publish`(见 docs/deploy.md)
|
||
- 后台「主题管理」可激活 / 上传 ZIP / 删除
|
||
|
||
## 插件
|
||
|
||
- 目录:`plugins/{vendor}.{name}/`,含 `plugin.json` + `src/ServiceProvider.php`(继承 `App\Blog\Support\PluginServiceProvider`)+ 可选 `database/migrations`、`routes/web.php`、`views/`
|
||
- 钩子:`addAction(hook, cb)` / `addFilter(hook, cb, priority)`,核心钩子:
|
||
- `comment.created`(AI 审核)、`payment.paid`(按 payable 分发订阅激活/解锁)、`post.rendered`(付费内容过滤/paywall)、`seo.structured_data`
|
||
- `filament.post_form` / `filament.post_table`(后台文章表单/表格注入)
|
||
- 插件依赖 `requires` 强制校验:启用需依赖已启用,停用/卸载会被依赖者阻止;启动时依赖不满足的插件跳过
|
||
- 订单商品化:`Payment` 多态 `payable` 关联购买实体,实体实现 `payableLabel()` / `payableUrl()` 接入订单展示(详见 docs/plugins.md)
|
||
- 后台「插件管理」:启停 / 上传 ZIP 安装 / 卸载 / 市场拉取(配置 `MARKET_URL` 后可用)
|
||
- 插件自带迁移由 `migrate` 自动加载(`app/Providers/AppServiceProvider` 注册 plugins/*/database/migrations)
|
||
|
||
## 内容格式
|
||
|
||
- 每篇文章有 `content_format`(markdown / html),新文章默认 Markdown
|
||
- 老数据导入标记为 html 原样保留;`content:convert` 批量转 Markdown
|
||
- 附件短代码:HTML 内容用 `[attach=1]` / `[img=1]`,Markdown 内容用 `{{attach:1}}` / `{{img:1}}`(`[]` 是 Markdown 保留字符),渲染时统一解析
|
||
- 付费内容:`[paid]...[/paid]` 短代码,非会员/未解锁访客隐藏(会员插件)
|
||
|
||
## 异步处理(Workerman)
|
||
|
||
```bash
|
||
php artisan workerman:serve start # 队列消费者 × N + WebSocket :8787
|
||
php artisan workerman:serve stop
|
||
```
|
||
|
||
- 消费者复用 Laravel `Queue\Worker`,**database / redis 队列统一支持**,常驻进程内框架只启动一次(省去每个任务的启动开销)
|
||
- 任务统一实现 `App\Blog\Jobs\AiJob` 接口(`handle(LlmClient)`),依赖由容器自动注入
|
||
- 队列选择:
|
||
- database(默认):`WORKERMAN_QUEUE_CONNECTION=database`
|
||
- redis:`WORKERMAN_QUEUE_CONNECTION=redis` 并确保 `QUEUE_CONNECTION=redis`、`REDIS_*` 配置正确;`redis` 连接的 `block_for` 建议设为 `0`(配合 1s 轮询,避免阻塞 Workerman event loop)
|
||
- 消费队列:`WORKERMAN_QUEUES=default,ai`(ai 队列为 AI 审核/润色任务)
|
||
- 失败重试:`WORKERMAN_MAX_TRIES`(默认 3),超时 `WORKERMAN_TIMEOUT`(默认 60s),重试耗尽进 `failed_jobs` 表
|
||
- 降级路径:`php artisan queue:work` 照常可用(同一队列)
|
||
|
||
## 外链中转(/go,内置插件)
|
||
|
||
内置插件 `neatstudio.link-tracker`(外链中转):
|
||
- 正文外链、评论正文 URL、评论作者网址、友链统一改写为 `/go/{hash}`:302 跳转 + **点击统计**、可**停用拦截**(返回 410)、隐藏真实链接、为未来广告位预留
|
||
- 站内链接/相对路径/mailto/tel/锚点不中转;同一 URL 复用同一短码
|
||
- 后台「管理 → 外链中转」可查看点击量、启停、删除
|
||
- **插件化设计**:核心提供 `tracked_url()` 钩子(`link.redirect` 过滤器)+ 正文 `post.rendered` 过滤器接入点,停用插件后链接恢复直连、不影响内容显示
|
||
|
||
## 前台缓存
|
||
|
||
- 匿名 GET 页面整页缓存(首页/列表/文章/归档/标签等),TTL 默认 300 秒(`PAGE_CACHE_TTL`),命中时零数据库查询
|
||
- 文章浏览量由独立 `/track-view` 端点统计,不受整页缓存影响(实时)
|
||
- 后台「缓存管理」:清空页面/侧边栏/设置/全部缓存、重建编译缓存
|
||
- 侧边栏数据与站点设置另有 1 小时缓存
|
||
|
||
## 对外 API
|
||
|
||
- 交互式文档(OpenAPI/Swagger 风格):`GET /docs/api`
|
||
- 端点:`/api/site`、`/api/posts`、`/api/posts/{slug}`、`/api/categories`、`/api/tags`、`POST /api/comments`、`/api/me`(Bearer Token)
|
||
- 供小程序 / 第三方平台接入,详见 `docs/api.md`
|
||
|
||
## 测试
|
||
|
||
```bash
|
||
php artisan test # 84 个用例:迁移/老路由 301/主题/插件/会员支付流/AI 审核/商城购买
|
||
```
|
||
|
||
## 开发者文档
|
||
|
||
| 文档 | 内容 |
|
||
|------|------|
|
||
| [docs/install.md](docs/install.md) | 安装指南(环境/配置/验收清单) |
|
||
| [docs/import.md](docs/import.md) | Sablog 老数据导入(命令/映射/附件/301 兼容) |
|
||
| [docs/deploy.md](docs/deploy.md) | 部署(nginx/systemd/workerman/cron/上线清单) |
|
||
| [docs/development.md](docs/development.md) | 开发规范(代码/插件/主题/队列/测试/提交) |
|
||
| [docs/tutorial-plugin.md](docs/tutorial-plugin.md) | 插件开发教程(10 分钟上手,配套 demo) |
|
||
| [docs/tutorial-theme.md](docs/tutorial-theme.md) | 主题开发教程(10 分钟上手,配套 demo) |
|
||
| [docs/plugins.md](docs/plugins.md) | 插件 API 详解(钩子/依赖/商品化/市场契约) |
|
||
| [docs/themes.md](docs/themes.md) | 主题 API 详解(视图解析/注入点/变量) |
|
||
| [docs/architecture.md](docs/architecture.md) | 架构与设计决策 |
|
||
| [docs/api.md](docs/api.md) | 对外 API(小程序/第三方) |
|
||
|
||
**上手示例**:
|
||
- 插件:`plugins/demo.hello-world/`(短代码 / 钩子 / 路由 / 后台页 / 迁移 / 表单注入,全演示)
|
||
- 主题:`themes/demo/`(最小可运行主题,绿色系,覆盖 partials 即可换肤)
|
||
|
||
## 目录结构
|
||
|
||
```
|
||
app/
|
||
Blog/ # 前台域模块(Controllers/Jobs/Services/Support/View)
|
||
Filament/ # 后台资源与页面
|
||
Console/Commands # sablog:import / attachments:sync-s3 / workerman:serve / content:convert
|
||
themes/ # 主题(sablog / modern / demo 示例)
|
||
plugins/ # 内置插件(blog-seo / ai-moderation / payment / membership)+ demo.hello-world 示例
|
||
docs/ # 全部文档(见上文表格)
|
||
```
|
||
|
||
## 许可
|
||
|
||
MIT
|