# 数据库变更：ai_cache.chk_ai_cache_type 约束放开 app2a_finance_area

> 日期：2026-04-23
> 迁移脚本：[db/zqyy_app/migrations/20260423__ai_cache_allow_app2a.sql](../../db/zqyy_app/migrations/20260423__ai_cache_allow_app2a.sql)
> 相关设计：[docs/ai/app2_finance_multi_app_design.md](../ai/app2_finance_multi_app_design.md) · Phase F
> 涉及库：`zqyy_app`（biz schema）
> 风险等级：**低**（仅放开约束，不影响已有数据）

---

## 1 · 变更说明

### 约束变更

| Schema.Table | 约束名 | 变更类型 | 允许值 |
|---|---|---|---|
| `biz.ai_cache` | `chk_ai_cache_type` | **替换**（DROP + CREATE） | 旧 7 项 + 新增 `app2a_finance_area` |

**新约束完整定义**：
```sql
CHECK (cache_type IN (
    'app2_finance',
    'app2a_finance_area',        -- 新增
    'app3_clue',
    'app4_analysis',
    'app5_tactics',
    'app6_note_analysis',
    'app7_customer_analysis',
    'app8_clue_consolidated'
))
```

### 其他检查

- `ai_run_logs.app_type` · **无 CHECK 约束**（VARCHAR(30)），无需改动
- `ai_trigger_jobs.*` · **无相关 CHECK 约束**，无需改动

---

## 2 · 兼容性影响

### 对已有数据

- 旧 7 项 cache_type 值全部保留，现有数据不动
- 无需数据迁移

### 对后端代码

- `CacheTypeEnum.APP2A_FINANCE_AREA` 枚举已在 `apps/backend/app/ai/schemas.py` 添加
- `AICacheService.write_cache(cache_type='app2a_finance_area', ...)` 本约束放开后即可成功写入
- `_SUPPORTED_APP_TYPES` / `dispatcher.run_single_app` / `build_app2a_area_prompt` 链路在 Phase C 已完成

### 对小程序

- [board-finance.ts](../../apps/miniprogram/miniprogram/pages/board-finance/board-finance.ts) `_loadAIInsights` 已按 area 动态选 `cache_type`
- 后端 xcx API `/api/ai/cache/{cache_type}` 白名单自动涵盖（基于 `CacheTypeEnum`）

---

## 3 · 回滚策略

### 回滚前置条件

**必须先删除所有 `cache_type = 'app2a_finance_area'` 的记录**，否则 CHECK 会拒绝。

```sql
-- 回滚预备
DELETE FROM biz.ai_cache WHERE cache_type = 'app2a_finance_area';

-- 回滚 DDL
BEGIN;
ALTER TABLE biz.ai_cache DROP CONSTRAINT IF EXISTS chk_ai_cache_type;
ALTER TABLE biz.ai_cache ADD CONSTRAINT chk_ai_cache_type
  CHECK (cache_type IN (
    'app2_finance', 'app3_clue', 'app4_analysis', 'app5_tactics',
    'app6_note_analysis', 'app7_customer_analysis', 'app8_clue_consolidated'
  ));
COMMIT;
```

---

## 4 · 验证 SQL

### 验证 1 · 约束允许值包含 app2a_finance_area

```sql
SELECT pg_get_constraintdef(oid)
  FROM pg_constraint
 WHERE conname = 'chk_ai_cache_type';
-- 期望：返回的 CHECK 中含 'app2a_finance_area'
```

### 验证 2 · 插入新 cache_type 应成功

```sql
INSERT INTO biz.ai_cache (cache_type, site_id, target_id, result_json, status, expires_at)
VALUES ('app2a_finance_area', 1, 'test__all', '{}'::jsonb, 'valid', NOW() + INTERVAL '1 day');
-- 期望：成功插入
-- 清理：
DELETE FROM biz.ai_cache WHERE cache_type = 'app2a_finance_area' AND site_id = 1 AND target_id = 'test__all';
```

### 验证 3 · 旧 cache_type 插入仍正常

```sql
INSERT INTO biz.ai_cache (cache_type, site_id, target_id, result_json, status, expires_at)
VALUES ('app2_finance', 1, 'test__backward_compat', '{}'::jsonb, 'valid', NOW() + INTERVAL '1 day');
-- 期望：成功插入
DELETE FROM biz.ai_cache WHERE cache_type = 'app2_finance' AND site_id = 1 AND target_id = 'test__backward_compat';
```

---

## 5 · 变更记录

| 日期 | 操作 | 执行人 |
|---|---|---|
| 2026-04-23 | 迁移脚本产出 + 测试库执行通过 | Claude + Neo |
| 待定 | 生产库执行 | Neo（上线 checklist） |
