# ERR-20260501-001 — Prisma JSON `path: ['$'] + array_contains` 在 PostgreSQL 下永不命中

## 现象
`form-management/services/webhook.service.ts::triggerEvent()` 写出来后从未真正投递过事件——
查询 `enabled: true` 的 webhook 永远返回 0 条，即便表里明明有匹配的订阅记录。

## 调试过程
1. L1 测试中创建 webhook（`events: ['form.instance.submitted']`），调用 `triggerEvent('form.instance.submitted', ...)`
2. 接收方 HTTP server 没收到任何请求；`form_webhook_logs` 表也没新增日志
3. 在测试里加 `console.log` 直接复现 service 同款 findMany：
   ```ts
   prisma.formWebhook.findMany({
     where: {
       enabled: true,
       events: { path: ['$'], array_contains: ['form.instance.submitted'] },
     },
   })
   ```
   返回 0 条；而表里 `events` 列实际是 `['form.instance.submitted']`，应当命中

## 根因
`path: ['$']` 是 **MongoDB jsonpath** 写法（`$` = 根文档）。
Prisma 的 PostgreSQL JSON 过滤里 `path` 用于"导航到嵌套 key"，会被当成 `'$'` 字面量 key 查找——而 jsonb 里根本没有名为 `$` 的 key，于是永远不命中。

PostgreSQL 的"数组包含元素"原生操作符是 `@>`，对应 Prisma 写法是：
```ts
events: { array_contains: 'form.instance.submitted' }   // 查 events @> '"form.instance.submitted"'
// 或
events: { array_contains: ['form.instance.submitted'] } // 查 events @> '["form.instance.submitted"]'
```
**不要带 path**。

## 修复
本次 PR 修了 3 处同样的死写法：
- `backend/src/engines/form/form-management/services/webhook.service.ts::triggerEvent`
- `backend/src/engines/form/form-engine/services/form-identifier-resolver.service.ts::resolveByIdentifier`（两处：aliases / slugHistory）
- `backend/src/engines/form/form-engine/services/form-definition.service.ts::validateAliases`

补 L1 集成测试覆盖（`testing/backend/integration/form-management/webhook.api.test.ts`）。

## 教训
- Prisma 文档对 PostgreSQL JSON 过滤说得不算清楚，`path: ['$']` 看着像 jsonpath 语法但 PG 后端不识别——只有 MongoDB connector 才支持 `$` 根
- **凡是涉及 jsonb 数组成员判断，第一反应应该是 `array_contains`（不带 path）**，path 留给 nested object 字段访问
- Code review 时见到 `path: ['$']` 应当怀疑——这是个红旗，**几乎可以肯定是从 MongoDB 文档拷过来的或被 LLM 幻觉出来的写法**
- 只有当业务路径上从未有人手工触发过这条查询，bug 才会潜藏这么久；本次是 webhook 投递功能"实现 + 浅验"上线，业务侧从来没真用过

## 适用范围
所有 PostgreSQL + Prisma + jsonb 数组列的"包含元素"过滤。
