# 架构与开发模式 ## 技术栈 | 层 | 技术 | 说明 | |----|------|------| | 框架 | Laravel 12.65 | PHP ^8.2,`declare(strict_types=1)` 全量启用 | | 后台 | Filament 5.7 | admin panel,zh_CN,资源/页面/组件 | | 前台交互 | Livewire 4 | Filament 依赖 | | 数据库 | MySQL 8(生产)/ SQLite(测试 :memory:) | | | 缓存/队列 | database / redis | 队列默认 database,可切 redis | | Markdown | league/commonmark(GFM)+ html-to-markdown | 内容双格式 | | 附件 | S3 兼容(R2/COS/OSS)+ spatie/laravel-medialibrary | 零落盘 | | 异步 | Workerman 5 常驻(队列消费者 + WebSocket) | 复用 Laravel Queue Worker | | 支付 | yansongda/pay(支付宝/微信) | 沙箱模式内置 | | 权限 | spatie/laravel-permission | admin/editor/member | ## 目录分层 ``` app/ Blog/ # 前台域模块(与 Laravel 默认 app/ 分离) Controllers/ # 前台控制器(theme_view() 渲染) Jobs/ # AI 异步任务(AiJob 接口) Services/ # 领域服务:渲染、支付、导入、S3 同步、LLM 客户端 Support/ # 基础设施:ThemeManager、PluginManager、SlugGenerator、MediaDisk、WorkermanBroadcaster Providers/ # ThemeServiceProvider、PluginManagerServiceProvider View/Composers/ # 侧边栏数据共享 Filament/ # 后台(Resources/Pages/Widgets) Console/Commands/ # sablog:import / attachments:sync-s3 / workerman:serve / content:convert / theme:publish Models/ # Post/Category/Comment/Link/Setting/User... themes/ # 皮肤(theme.json + views + assets) plugins/ # 插件(plugin.json + ServiceProvider + 迁移/路由/视图) ``` ## 核心设计决策 1. **内容双格式**:`posts.content_format`(markdown/html)。新文章默认 Markdown;老数据导入标记 html 原样保留,`content:convert` 可批量转 Markdown。渲染管线 `PostContentRenderer::render()` 统一输出 HTML,再经 `post.rendered` 过滤器(付费内容等)。 2. **附件短代码**:HTML 内容 `[attach=1]`/`[img=1]`;Markdown 内容用 `{{attach:1}}`/`{{img:1}}` 令牌(`[]` 是 Markdown 保留字符)。渲染时按**全局** legacy_attachmentid 解析,找不到媒体自动清理残留。 3. **主题系统**:激活主题的 views 目录前置到全局视图路径(View Finder),主题覆盖同名视图、缺失回退默认视图。header 打开的容器由页面视图自闭合(避免 footer 错位)。资产开发期流式返回、生产 `theme:publish`。 4. **插件系统**:目录即插件(`plugins/{vendor}.{name}/plugin.json`),钩子(action/filter)解耦。后台页面/资源通过 manifest 的 `filament_pages`/`filament_resources` 由 `PluginPages` 汇总注册。插件迁移自动加载。 5. **S3 附件**:上传磁盘 = s3(R2/COS/OSS endpoint),新上传零落盘;未配置 S3 时回退本地 public(开发友好)。`attachments:sync-s3` 幂等同步(含大文件 Multipart),损坏文件降级 pending 不中断。 6. **异步 LLM**:任务实现 `AiJob` 接口,Workerman 常驻进程复用 Laravel `Queue\Worker` 消费(database/redis 统一),`sleep=0` + 1s Timer 不阻塞 event loop;失败重试 `failed_jobs` 表。 7. **URL 兼容**:canonical 前台 URL 统一 `.shtml` 后缀(`/posts/{slug}.shtml`);无后缀版本 301;sablog 老 URL(伪静态/查询串/PHP 入口)全部 301;trackback 类垃圾功能直接 410 废弃。 8. **迁移保 ID**:`sablog:import` 用 `DB::table()->updateOrInsert` 保留老主键(Eloquent insertGetId 会忽略显式自增 id),老 MD5 密码登录时自动升级 bcrypt。 ## 开发模式 - **本地**:Herd 托管 `laralog.test`(PHP 8.2 + MySQL 8);无 S3 时附件落本地 public - **测试**:PHPUnit,SQLite `:memory:`(`phpunit.xml`),`RefreshDatabase` + `seed()`;MySQL 专属 SQL(syncCounters)在 sqlite 兼容 - **常用命令**: - `php artisan sablog:import --fresh --convert-markdown`(老库迁移) - `php artisan workerman:serve start|stop` - `php artisan test` - `php artisan theme:publish` / `content:convert --all` / `attachments:sync-s3` ## 配置速查 | 配置 | 说明 | |------|------| | `config/blog.php` | 站点/每页数/附件磁盘 | | `config/themes.php` | 主题目录/默认主题 | | `config/plugins.php` | 插件目录/内置启用列表 | | `config/workerman.php` | 消费者数/队列连接/队列名/重试 | | `config/media.php` | S3 配置(R2/COS/OSS)与 Multipart 阈值 | | `config/market.php` | 插件/主题市场远程源 | ## 已知边界 - AI 审核/润色需要真实 LLM Key(OpenAI 兼容);支付需真实网关密钥(沙箱已验证) - 插件/主题市场客户端已就绪,市场服务端需另行部署(接口约定见 `App\Blog\Services\MarketplaceClient`) - 自动配图(封面生成)为后续迭代项:封面媒体集合与主题展示已就位,生成器走队列/脚本