Files
goukiandCursor debead72a5
Build and Deploy / verify (push) Failing after 15m18s
Build and Deploy / deploy (push) Skipped
feat: add frontend admin shortcut for staff
Let admin and editor open /admin in a new tab from the public header and profile, so they can jump to the backend without leaving the site.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-21 23:42:54 +00:00

6.3 KiB
Raw Permalink Blame History

开发规范

面向所有为 LaraLog 写代码的人(核心 / 插件 / 主题作者)。教程见 tutorial-plugin.md、tutorial-theme.md,配套示例见 plugins/demo.hello-world/、themes/demo/。

1. 代码规范

  • PHP 8.2+,所有文件以 declare(strict_types=1); 开头
  • 命名空间:核心 App\...;插件 Plugins\{Vendor}\{Name}\...(Vendor/Name 用 Str::studly 规则)
  • 文件命名:类文件与类名一致(PSR-4 自动加载)
  • 方法/属性/变量:camelCase;常量:UPPER_SNAKE;数据库表:snake_case
  • 中文文案直接写在代码/语言包中(本项目默认中文,不硬编码英文 UI)
  • 不写无意义注释;只在「为什么」不明显处加一行注释
  • 安全红线:不提交 .env、密钥、证书;用户输入一律 e() 转义或框架验证;数据库操作用 Eloquent/查询构造器(防注入)

2. 目录约定

app/Blog/          # 前台域模块:Controllers / Jobs / Services / Support / View
app/Filament/      # 后台资源与页面
plugins/           # 插件,目录名 vendor.name
themes/            # 主题,目录名即主题名
routes/web.php     # 前台规范路由;routes/legacy.php 老 URL 301(新增老入口兼容放这里)

3. 插件规范(详见 docs/plugins.md)

  • 目录 plugins/{vendor}.{name}/,目录名是插件唯一标识
  • 类自动加载:系统启动时扫描 plugins/*/src 注册 PSR-4(Plugins\{Vendor}\{Name}),无需改 composer.json
  • plugin.json 必填:title/version/description/author/type/provider;可选 usage/requires/filament_pages/filament_resources
  • 入口类 src/ServiceProvider.php 继承 App\Blog\Support\PluginServiceProvider,不要命名为 PluginServiceProvider
  • 依赖声明在 requires(vendor.name),系统强制校验:依赖未启用不能启用本插件;停用/卸载被依赖者阻止
  • 后台扩展一律走钩子注入(filament.post_form / filament.post_table),禁止改核心资源文件
  • 可购买实体约定:实现 payableLabel(): string 与 payableUrl(): ?string 即接入订单展示(支付插件零改动)
  • 插件视图放插件目录并用 loadViews() 注册命名空间;前台页面用 @include('partials.header') 复用主题公共片段

钩子清单

Hook 类型 参数 用途
post.rendered filter (string $html, Post): string 文章渲染后处理
comment.created action Comment 新评论创建
payment.paid action Payment 支付成功分发
filament.post_form action Schema 文章表单注入
filament.post_table action Table 文章表格注入
seo.structured_data filter (array): array JSON-LD 扩展
theme.inject.{point} filter (string): string 注入点追加 HTML

文章表单是左 2 右 1:插件用 PostForm::appendToSidebar() / PostForm::appendToAccessSection() 注入,不要往根节点追加整行 Section。表格仍用 pushColumns()。

4. 主题规范(详见 docs/themes.md)

  • 目录 themes/{name}/,theme.json 必填;views 前置到全局视图路径,同名覆盖、缺失回退
  • 语义化 HTML(header/nav/main/aside/footer/article/time)是 SEO 要求,不是可选项
  • 保留注入点 @stack('theme:xxx'),并尽量在 theme.json 声明 inject_points
  • 必须有移动端断点(≤768px 两栏改单栏)
  • 资产开发期流式返回、生产 theme:publish

5. 队列任务规范

  • 实现 App\Blog\Jobs\AiJob 接口(handle(LlmClient) 由容器注入)+ ShouldQueue
  • 入队 dispatch(new XxxJob($id))->onQueue('ai')
  • 消费者二选一:php artisan workerman:serve(常驻+WS)或 php artisan queue:work --queue=default,ai(等价,见 docs/deploy.md)
  • LLM 一律走 LlmClient(OpenAI 兼容,base_url/key/model 可配),不要直连第三方 SDK

6. 测试规范

  • 新增功能必须配 Feature 测试(tests/Feature/),跑 php artisan test 全绿再提交
  • 示例参照:PluginDependencyTest(依赖校验)、PostFormInjectionTest(表单注入)、MarketPurchaseTest(商城购买流)、MembershipFlowTest(会员/支付流)
  • 测试用 RefreshDatabase + 沙箱,不触碰真实支付/真实 LLM 凭据

7. 提交规范

  • 一次提交一件事,信息用中文描述「做了什么 + 为什么」
  • 不提交:.env、密钥/证书、storage/media-library/temp/、构建产物
  • 完成后更新对应 docs/ 文档

8. 后台导航约定

  • 顶栏 网站 打开前台新窗口,写文章 进新建文章
  • 前台登录后,管理员/编辑导航里有 管理,新窗口打开 /admin。会员不要显示这条链接
  • 管理 → 页面缓存:查看/清理前台整页缓存,不要只藏在用户菜单里
  • 管理 → 语言:只展示当前 APP_LOCALE 和已有语言包。文章还没有多语言版本,不要假装已经做了
  • 文章置顶用 sticky_level(0/1/2/3),列表排序 orderedForList()。3 = 置顶头条,永远最前
  • 前台 RSS / Sitemap / llms.txt 开新窗口。/llms.txt 和 /posts/{slug}.md 是核心路由,不要做成静态文件,新文章要马上出现
  • 首页浏览模式:home_view_mode + ?view=list|full + cookie ll_home_view。分页用 blog_paginate()(onEachSide(1))
  • 老 sablog 正文清洗放 SablogHtmlNormalizer,导入 / 渲染 / sablog:fix-content 共用,不要各写一套 strip_tags
  • 广告位用 partials.theme-inject。保存主题注入要清页面缓存。stylevars 跟 theme_vars_{theme} 走,不要再忽略这张表

9. 常用命令速查

php artisan test                    # 全量测试
php artisan dev:watch               # 开发热重载(改插件/核心代码自动重启 workerman)
php artisan migrate                 # 插件迁移自动加载
php artisan workerman:serve start   # 队列消费者 + WebSocket
php artisan theme:publish           # 主题资产发布到 public