## [ERR-20260430-008] cleanupByPrefix 不适合有 ON DELETE RESTRICT FK 的模块

### 现象

试图把 meeting-attendance 集成测试从 `cleanupDatabase` 切到 `cleanupByPrefix(prisma)`：
- 单跑 meeting-attendance：3 个测试套件 17/17 全过 ✅
- site-attendance + meeting-attendance 串跑：legacy-cutover-reports 测试 3 报 `expected 200, got 500`

### 根因

cleanupByPrefix 工作流：
1. `SET session_replication_role = 'replica'` 禁 FK
2. DELETE 命中前缀的行（含 `users` 表里 `t_*` 用户）
3. `SET session_replication_role = 'origin'` 恢复 FK

问题：`platform_meeting_attendance.meetings.creator_id` FK 到 `users.id`，**ON DELETE RESTRICT**。但 `meetings.title` / `meetings.location` 等都不是 cleanupByPrefix 默认扫的列名 → 测试跑过留下的 meeting 行**不被清**。

下一个测试 cleanupByPrefix 删 user 时 FK 禁用所以删得动 → meeting 留 dangling `creator_id` 指向不存在的 user → 后续报告类 API 做 JOIN meeting↔users 直接 500。

### 该模块为什么不能迁

meeting-attendance 测试**严格依赖** `cleanupDatabase` 内部的 `cleanupMeetingAttendanceDataForUsers` —— 它先按 creatorId 级联清理 meeting/series/attendance/required-attendees，然后才删 user。这是 schema-aware 逻辑，cleanupByPrefix 的 schema-agnostic 设计无法替代。

修法选项（都不好）：
- A. afterEach 手动 `prisma.meeting.deleteMany({}); prisma.meetingSeries.deleteMany({})...` —— 又回到硬编码表，违背前缀过滤初衷
- B. 给 cleanupByPrefix 加 `cascadeMode: { meetingTables: true }` 选项 —— 引入模块感知，违背通用性
- C. 不迁，meeting-attendance 继续用 cleanupDatabase（**当前选择**）

### 复用建议

**判断模块能否迁 cleanupByPrefix 的简单清单**：
1. 测试 fixture 创建的所有表都有 `code`/`name`/`username`/`email`/`slug` 之一列吗？
2. 表与表之间的 FK 是 `ON DELETE CASCADE`/`SET NULL`/`NO ACTION` 吗？（不能是 RESTRICT）
3. 没有依赖父表 user/role 删除时级联清子表 meeting/order/transaction 等的隐式行为吗？

**任一不满足，就别迁**。issue #165 的"4 模块都迁"目标在 meeting-attendance 上行不通。

### 实际影响

- meeting-attendance 保留 cleanupDatabase ✅ 正常工作
- robot-manager / organization 因其他原因（fixture 命名/共享 helper）也建议保留
- issue #165 实际只能 close site-attendance migration（PR #203），其余推迟或 wontfix

### 上下文

- 分支 `refactor/cleanup-helper-meeting-attendance` 已弃
- 关联 issue #165
- 关联 [ERR-20260430-007](ERR-20260430-007.md) - 期间发现的 cleanupByPrefix boolean LIKE bug
