关于 unopim-code-review
面向 UnoPim 代码变更审查的技能,依据 `unopim-standards` 检查新增或修改的行。清单覆盖安全、规模、可移植性和本地化等阻断风险,并规定了审查结论格式。
主要功能
- 01聚焦差异的审查范围
- 02十个维度的阻断项
- 03高优先级规范检查
- 04要求引用规范与示例
- 05结构化审查结论格式
适用场景
- 01审查 UnoPim 拉取请求
- 02检查新增路由是否符合 ACL 规则
- 03审计数据库查询的规模与可移植性
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ unopim/ agent-skills --skill unopim-code-review安装后在 Claude Code 中输入/unopim-code-review确认已加载。
详细介绍
UnoPim 代码审查
背景要求: 使用 unopim-standards——其参考文件(laravel13.md、security.md、performance.md、scale.md、extensibility.md、localization.md、comments.md)是规则手册。本技能是将这些规则应用于差异内容的检查清单。
范围——逐步收紧,而非考古
审查本次变更新增或修改的行。未改动行中的历史违规最多只能作为备注,绝不能作为阻止合并的问题——若阻止整个文件的修改,所有历史代码改动都会停滞。新引入的违规始终属于审查范围,即使它模仿了相邻的历史代码也不例外。
阻止性问题(命中任意一项 = 要求修改)
1. 注释噪音——开发者投诉的头号问题
- 在方法体、对象/数组字面量、路由组或 Blade 标记中新增的任何注释都是阻止性问题——包括单行“原因”注释、分节线(
// Views、// ----)和{{-- --}}说明。 - 项目的基准是零注释:
packages/Webkul/Product/src/Repositories/ProductRepository.php(18 个方法)和packages/Webkul/Product/src/Type/AbstractType.php(988 行)均不包含行内注释。 - 确实不明显的原因应写在类/方法 PHPDoc 或提交说明中。方法 PHPDoc:一行祈使句式摘要;仅在没有原生类型提示时使用
@param/@return。 - 机械检查:对每条符合
^\+\s*(//|/\*|\{\{--)的git diff -U0新增行,均记为问题。
2. 硬编码颜色
- 阻止性问题:十六进制/rgb 字面量、
style="..."、<style>块、任意值(bg-[#...])、默认意图色阶(violet-*、purple-*、red-*、green-*、blue-*),以及新代码中的旧版cherry-*/sky-*/unopim-primary-*。 - 必须使用语义令牌:仅限
primary(+50–900)、primary-hover、success、warning、danger、info——这些 CSS 变量定义于packages/Webkul/Admin/src/Resources/assets/css/app.css(:root+.dark),并映射于packages/Webkul/Admin/tailwind.config.js。字面量无法跟随.dark变量切换,因此会导致深色模式显示异常。 - 中性色必须配有深色模式对应类,例如
text-primary-700 dark:text-primary-400。
3. 存在 x-admin:: 组件时使用原始 HTML
- 管理界面视图中的原始
<input>、<select>、<textarea>、<label>均为阻止性问题:应使用x-admin::form.control-group及.label/.control/.error。 - 手工构建的列表表格均为阻止性问题:应使用
x-admin::datagrid。自定义固定/遮罩层 div 均为阻止性问题:应使用x-admin::modal(+modal.confirm)或x-admin::drawer。 packages/Webkul/Admin/src/Resources/views/components下有约 140 个组件 Blade 文件——接受手工编写的标记前,先检查此目录(switcher、flat-picker、tinymce、tabs、accordion、dropdown、tree、badge、shimmer)。- 选择框使用
:options="json_encode(...)",并搭配track-by/label-by——绝不要用@foreach遍历<option>。
4. 重复代码
- 同一代码块(逻辑或标记)出现 2 次或以上时,必须提取为方法、组件或局部模板。指出可复用的现有位置。
5. 扩展性——假设有数百万行数据
- 对目录表无界调用
->all()/->get()/->pluck()= 阻塞项。批量扫描使用chunkById()/lazyById()(packages/Webkul/Completeness/src/Jobs/BulkProductCompletenessJob.php)。 - **钩子无法覆盖此维度的大部分情况——请检查差异内容,不要假设退出代码能做到这一点。**只有
Model::all()、$someRepository->all()和select('*')会被钩子拦截。以裸->get()结尾的流式调用链、foreach中的查询、缺少预加载、Blade 模板中的查询,以及控制器循环遍历目录而不是分发ShouldQueue作业的情况,全部都不会被门禁检测到,在此处均属于阻塞项。 - 批量查找:使用
array_chunk($keys, 1000)+whereIn(packages/Webkul/DataTransfer/src/Helpers/Importers/Product/SKUStorage.php)——切勿在循环中逐行查询。 - 导出数据源通过基于 ID 游标的键集分页进行流式处理(
packages/Webkul/DataTransfer/src/Helpers/Sources/Export/ProductCursor.php);AbstractExporter 的source->all()默认实现仅适用于小型实体。 - 多批次处理应使用
ShouldQueue作业,绝不能在请求中内联执行。数据迁移也应采用流式处理(cursor/chunkById)。 - 新增的
where/orderBy/可筛选 DataGrid 列需要建立索引。不要在循环或 Blade 中执行查询。遍历到的每个关联都要预加载。
6. 可移植性——MySQL + PostgreSQL、表前缀、可选 Elasticsearch
- 原始 SQL 片段(
DB::raw、selectRaw、whereRaw、orderByRaw)中如果指定表名,必须加上DB::getTablePrefix()前缀(packages/Webkul/Measurement/src/DataGrids/UnitDataGrid.php)。硬编码wk_= 阻塞项——不存在这样的前缀;DB_PREFIX默认值为空。 - 仅支持 MySQL 的 SQL(GROUP_CONCAT、反引号、DATE_FORMAT、CAST AS SIGNED)= 阻塞项。跨数据库兼容应使用
DB::rawQueryGrammar()(packages/Webkul/Core/src/Helpers/Database/Grammars/MySQLGrammar.php、packages/Webkul/Core/src/Helpers/Database/Grammars/PostgresGrammar.php),或使用DB::getDriverName() === 'pgsql'分支。 - 未通过
config('elasticsearch.enabled')判断是否启用且没有数据库回退的任何 Elasticsearch 调用,均属于阻塞项(packages/Webkul/Product/src/Factories/ProductQueryBuilderFactory.php)。
7. 安全
- ACL 按路由名称采用失败开放策略(
packages/Webkul/User/src/Http/Middleware/Bouncer.php):写入路由——store、update、destroy、mass_*(snake_case 键)、test-connection——若未出现在任何acl.php中,所有已登录管理员都可以访问 = 阻断项。通过'also_authorizes'绑定写入路由(packages/Webkul/Core/src/Tree.php)。 - 每个端点都使用 FormRequest;内联
request()->validate()= 阻断项。仅当路由名称受 ACL 控制时,才使用authorize(): true;否则应在authorize()中进行 bouncer 检查(packages/Webkul/Admin/src/Http/Requests/TinyMCEUploadRequest.php)。共享或无路由端点应在控制器中进行权限控制(packages/Webkul/Admin/src/Http/Controllers/MagicAI/MagicAIController.php)。 - 上传:使用 mimes 允许列表 + 最大大小限制 +
FileMimeExtensionMatch(packages/Webkul/Core/src/Rules/FileMimeExtensionMatch.php);接受 svg/html = 阻断项(脚本载体)。 - 批量赋值:使用显式的
#[Fillable]允许列表,且其中不得包含权限列;$guarded = []= 阻断项。静态存储的机密信息必须同时使用'encrypted'cast +#[Hidden]+$auditExclude(packages/Webkul/AiAgent/src/Models/Credential.php)——单独使用$auditExclude并不会加密。 - 出站 URL 必须通过 SSRF 验证(
packages/Webkul/Webhook/src/Validators/SafeWebhookUrl.php);CSV 导出必须转义公式运算符(packages/Webkul/DataTransfer/src/Helpers/Formatters/EscapeFormulaOperators.php)。不得将请求输入插入 SQL 或 DataGrid 闭包 HTML。 - 上述阻断项中有两项没有钩子,必须由你亲自检查:ACL 路由覆盖(这是跨文件问题——必须同时阅读路由文件和每个
acl.php,单文件检查无法做到)以及orderByRaw("$column $direction")(它与产品筛选器中合法的whereRaw("$column IS NULL")在同一行,外观完全相同)。 每次 PR 新增写入路由时,都要打开acl.php并与路由文件逐项核对;不要把“钩子检查通过”当作这两项已通过的证据。
8. 本地化
- 任何硬编码的面向用户字符串 = 阻断项,包括占位符、工具提示、JS 提示,以及“Loading…”状态文本。先在
Resources/lang/en_US/中使用trans()/@lang并添加键,再覆盖全部 33 种语言环境,确保译文自然(不照搬英文),并保留:placeholders。 - 将键放在名为
en的目录中 = 阻断项——这些键永远不会加载;回退语言环境为en_US。
9. Octane 安全性
- 持有请求或凭据状态的
singleton()绑定 = 阻断项;应改用scoped()(packages/Webkul/Core/src/Providers/CoreServiceProvider.php、packages/Webkul/Core/src/RequestMemo.php)。singleton()仅用于无状态基础设施。
10. 验证证据
- PR 必须证明这些检查确实运行过:
vendor/bin/pint --test、composer test(Pest v5、MySQL 和 PgSQL)、composer phpstan、composer rector-dry、UI/管理员变更的 Playwright 测试、php artisan unopim:translations:check。只说“应该能通过”却没有输出 = 未验证——应要求提供运行结果。 - 为了让检查通过而新增
ignoreErrors或withSkip条目 = 阻断项。
高优先级(合并前修复,不会立即阻断)
- 新模型没有 Concord 代理/契约,或在已有 repository 时直接使用
new Model();repository 未继承Webkul\Core\Eloquent\Repository。 - 未采用 Laravel 13 / PHP 8.4 惯用写法:缺少提升式构造函数属性、返回类型、枚举、
casts()方法,或模型上的#[Fillable]/#[Table]属性。 - 迁移文件位于错误目录——核心包使用
src/Database/Migrations/(复数);只有插件式包使用根目录下的Database/Migration/(单数)。 - Provider 未加载路由、配置合并(菜单位于
'menu.admin'、ACL、导入器/导出器)、迁移,或翻译/视图命名空间。 - 新行为没有测试;缺少
assertDatabaseHas/assertDatabaseMissing;未采用 Pest 的it()/describe()风格。 - 事件名称不符合
{domain}.{entity}.{action}.{before|after}格式;路由名称未使用点分隔。
判定格式
[Dimension] [Blocker|High|Medium]: one-sentence statement of the violation
Location: file:line (added/changed line)
Standard: unopim-standards/<reference file> e.g. comments.md, security.md, scale.md
Pattern: a real exemplar path under packages/Webkul showing the correct form
Fix: the minimal change
每项判定都必须引用标准参考文件和真实示例路径。将相关问题归为一组;用一个分句说明标准存在的原因,不要写成一段。
评论
支持 Markdown