# 开发规范

面向所有为 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 |

> `Schema::components()` / `Table::columns()` 是**替换**语义：表单用 `[...$schema->getComponents(), Section::make(...)]` 合并，表格用 `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. 常用命令速查

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