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

98 lines
6.3 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 开发规范
面向所有为 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. 常用命令速查
```bash
php artisan test # 全量测试
php artisan dev:watch # 开发热重载(改插件/核心代码自动重启 workerman)
php artisan migrate # 插件迁移自动加载
php artisan workerman:serve start # 队列消费者 + WebSocket
php artisan theme:publish # 主题资产发布到 public
```