# 需求变更日志 (Changelog)

> 按日期倒序记录每次需求变更。每条记录在开发完成、测试验收通过后归档。

---

## 2026-05-12 — v0.20.1: 7 批次小修复 + 中等功能(主管bug/封面帧/api_prompt/站内通知/团管重置密码/reEdit prompt/Safari 自适应根因)

**状态**: ✅ 本地完成 | **验收**: vitest 71/162 基线 0 回归 + 3 套 smoke (25+8+11) 全过 + 后端 curl 验证 4 通知 endpoint 全过 + 团管重置 6 项权限矩阵全过

### 变更内容

| # | 批次 | Commit | 关键改动 |
|---|------|--------|----------|
| A | 主管bug | `e86e3d4` | TeamsPage 主管 badge 加 onClick,后端早就支持 `is_team_admin=false` 同时清 `is_team_owner` |
| B | 封面帧前端 | `72f351d` | admin/team/profile 三个 records view 回传 `thumbnail_url`,三处 `<video>` 加 `poster=` |
| C | api_prompt 留痕 | `6ee5c8f` | `GenerationRecord.api_prompt` 字段 + migration 0021 + view 写入 + 详情弹窗"调试信息"折叠区(▸/▾) |
| D | 站内通知 | `c53144b` | 新 app `apps.notifications`(model + 4 API + admin) + Sidebar 铃铛(用户 76px + 超管 220px) + 通知中心页 + 60s 轮询 + anomaly_detector 自动封禁触发通知 |
| G | 团管重置密码 | `ed67a27` | 新 endpoint `team_reset_member_password_view` + 严格权限矩阵(主管→副管+成员,副管→成员)+ TeamMembersPage 重置按钮 + 结果 modal 显示一次新密码 |
| H | reEdit prompt | `11c1cdf` | VideoDetailModal fallback 跟 generation.ts:reEdit 对齐,关键补 `editorHtml: task.editorHtml \|\| task.prompt` |
| I | Safari 自适应根因 | `6b13cff` | AdminLayout `100dvh` + `min-height: 0` + 4 个 admin 页 `.pagination padding-bottom: 8px` + ProfilePage 同款 dvh fallback |

### 关键根因/设计要点

- **批次 I 不是 padding 补丁**:Safari 桌面 `100vh` 算的是含工具栏的 layout viewport,不是用户实际可见区;Flex `overflow-y: auto` 没有 `min-height: 0` 形同虚设。三件套 `100dvh + min-height: 0 + padding-bottom` 才是根因解
- **批次 G 权限服务端硬校验**:前端按钮 `canResetPasswordFor(m)` 只是 UX,后端 view 5 步逐层判 (同团队 / 不能改自己 / 主管须超管 / 副管只有主管能改 / 合法)
- **批次 D MySQL 严格模式守门**:Notification 所有 CharField 都加 `default=''`(memory `feedback_mysql_default`)
- **批次 D 用 `AppNotification` 类型名**:避免和浏览器 Web API `Notification` 全局类冲突

详见 `docs/todo/v0.20.1-完成报告.md`。

---

## 2026-04-17 — v0.18.3: 版权报错友好提示 + 图片删除即梦式连续重命名

**状态**: ✅ 已完成 | **验收**: 14 个自动化测试全过（11 单元 + 3 E2E）

### 变更内容

#### 后端
1. **版权限制错误友好提示** — `OutputVideoSensitiveContentDetected.PolicyViolation`（漫威等知名 IP 触发的版权拦截）加中文错误码映射："生成的视频涉及版权限制内容（如知名IP、名人肖像等），已被系统拦截，请修改提示词后重试"。精确匹配 API 返回的 code，不影响父级 `OutputVideoSensitiveContentDetected`（敏感内容）的现有提示

#### 前端
2. **图片删除即梦式连续重命名** — 现有逻辑：删图片2 后，图片3 保持原名称，再上传新图会出现"两个图片2"。修复后：
   - `inputBar.ts::removeReference` 删除后，同类型（图片/视频/音频）剩余引用按顺序连续重命名（图片1/图片2/图片3 连续无空位）
   - 用 `DOMParser` 解析 editorHtml，找到对应 `data-ref-id` 的 @mention span，更新 textContent（提示词栏里的 `@图片3` 自动变 `@图片2`）
   - 缩略图区和提示词栏视觉同步刷新

#### 测试覆盖
- **Vitest 单元测试 11 个**（test/unit/removeReferenceRelabeling.test.ts）：图片三场景、视频/音频独立编号、空 editorHtml、无 @mention、传入无效 id、部分 @、连续快速删除等边界
- **Playwright E2E 3 个**（test/e2e/bug2-rename.spec.ts）：真实浏览器验证上传 3 张图 → 删中间 → 再上传，编号不冲突

#### 文档整理
3. **AirDrama 根目录归档**：8 个过期 MD 文档移至 `archive/`（_settle_payment 双重结算/v0.15.1 部署/公告HTML/迁移到火山/全平台账务审计/火山耗时分析/图片上传blob/迭代需求_20260320）
4. **video-shuoshan/docs 归档**：6 个过期文档移至 `docs/archive/`（celery 轮询修复/design-review/PRD/test-report/两版旧 API 文档）
5. **新增 1080P Plan**：`AirDrama/1080P分辨率支持开发计划.md`，对照官方 API 文档完成 3 轮审查修正（21:9 像素值错误、_settle_payment 遗漏、VideoDetailModal 重新编辑、regenerate、API 响应 6 处、serializer 命名、GenerationRecord.resolution 字段已存在等），标注 5 项已知计费缺陷

### 变更文件
- `backend/utils/airdrama_client.py` — ERROR_MESSAGES 加 PolicyViolation 映射
- `web/src/store/inputBar.ts` — removeReference 重写（即梦逻辑 + editorHtml 同步）
- `web/test/unit/removeReferenceRelabeling.test.ts` — 11 个单元测试（新增）
- `web/test/e2e/bug2-rename.spec.ts` — 3 个 E2E 测试（新增）
- `AirDrama/1080P分辨率支持开发计划.md` — 1080P 开发 Plan（新增）
- `AirDrama/版本管理.md` — 添加 v0.18.3 记录
- `AirDrama/项目总览与待办.md` — 完成项 + 1080P P0 待办
- 16 个 MD 文档归档到两个 archive 目录

### 触发原因
- 用户反馈：漫威素材生成失败时显示英文错误，不友好
- 用户反馈：删除中间图片后再上传会出现重复编号（参考即梦交互）
- 火山 2026-04-16 1080P 上线，需提前规划开发

---

## 2026-04-13 — v0.18.2: 资产页修复 + 重新编辑素材泄漏 + 音频校验

**状态**: ✅ 已完成 | **验收**: 待测试

### 变更内容

#### 前端
1. **资产页素材库引用不可查看** — Admin/Team 资产页的 `assetVideoToTask` 直接用了 `asset://` 协议 URL 作为 `previewUrl`，浏览器无法加载。改为检测 `asset://` 后使用 `thumb_url`（真实 TOS 缩略图地址），并标记 `isAssetRef`。同步修复 `BackendTask` 和 `AssetVideo` 类型定义补 `thumb_url` 字段
2. **重新编辑素材泄漏** — `reEdit()` 把素材库引用混入 `references` 数组（注释写已过滤但实际没有），用户删除 @标签后旧素材仍通过 `filesToUpload` 路径发出。修复：`reEdit/regenerate` 加 `.filter(!isAssetRef)`；`PromptInput.extractText` 每次 DOM 变化时实时同步 `assetMentions` store
3. **音频不能作为唯一参考素材** — Seedance API 不支持"纯音频"和"文本+音频"。`canSubmit()` 去掉 `!hasText` 条件，同时检查 `references` 和 `assetMentions` 中的图片/视频；Toolbar 点击禁用按钮弹 toast 提示原因
4. **素材库引用缩略图烂图** — `pollStatus` 跨项目素材保护
5. **音频 ♫ 符号溢出** — 改用 CSS `::before` 渲染，不再污染 prompt 文本

### 变更文件
- `web/src/pages/AdminAssetsPage.tsx` — isAssetUrl + thumb_url 处理
- `web/src/pages/TeamAssetsPage.tsx` — 同上
- `web/src/types/index.ts` — BackendTask/AssetVideo 补 thumb_url
- `web/src/store/generation.ts` — reEdit/regenerate 过滤 isAssetRef
- `web/src/components/PromptInput.tsx` — extractText 同步 assetMentions
- `web/src/store/inputBar.ts` — canSubmit 音频校验增强
- `web/src/components/Toolbar.tsx` — 音频受限 toast 提示

---

## 2026-03-19 — v0.9.7: 登录风控第二期 — IP归属地解析 + 异常检测 + 飞书告警 + 自动封禁

**状态**: ✅ 已完成 | **验收**: ✅ 通过（本地验证，IP138 在线 API 需部署至阿里云后验证）

### 变更内容

#### 后端
1. **IP 归属地解析** — 新建 `geo_client.py`，主通道阿里云市场 IP138 API（精确到市），备通道 ip2region 离线库，60 秒熔断降级策略，私有 IP 自动跳过
2. **异常检测引擎** — 新建 `anomaly_detector.py`，5 条规则：
   - R1 登录地区不对（警告）— 单账号从非预期城市登录
   - R2 不可能的旅行（严重）— 单账号短时间内从两个不同城市登录，自动封禁该用户
   - R3 登录太频繁（警告）— 单账号短时间内登录次数过多
   - R4 团队遍地开花（严重）— 整个团队短时间内出现大量异地登录，自动封禁整个团队
   - R5 海外IP太杂（警告）— 整个团队短期内出现大量不同国家的登录
3. **飞书告警服务** — 新建 `alert_service.py`，通过飞书 Open API 发送 interactive 卡片私信，红色头=严重/橙色头=警告，附带辅助指标（7天并发踢出次数、非工作时间登录占比）
4. **告警冷却** — 同团队+同规则 30 分钟内不重复告警（可配置）
5. **封禁机制** — R2 封用户 + R4 封团队，封禁即踢下线（清 ActiveSession），前端拦截 user_disabled/team_disabled 错误码弹窗提示
6. **团队级阈值配置** — TeamAnomalyConfig 模型（OneToOne → Team），未配置时取全局默认值
7. **自动学习预期地区** — 统计团队最近 30 天登录城市，频次 ≥ 3 的城市纳入预期列表
8. **LoginRecord 扩展** — 新增 team FK、geo_country/province/city/source 字段
9. **SessionJWT 双重检查** — 认证层同时检查 user.is_active 和 team.is_active

#### 前端
10. **系统设置页** — 异常检测总开关、R1-R5 默认阈值编辑（三段按钮组 默认|开|关）、飞书接收人手机号+测试按钮、短信（灰色 Coming soon）、告警冷却时间
11. **团队管理页** — 预期登录城市编辑+自动学习按钮、R1-R5 团队级阈值覆盖、disabled_by 来源标签（系统/管理员）
12. **安全日志页面** — `/admin/security` LoginAnomaly 记录列表，按团队/规则/级别/时间筛选
13. **用户管理页** — disabled_by 来源标签（系统自动禁用/管理员手动禁用）
14. **管理员修改密码** — AdminLayout 侧栏底部新增修改密码入口+弹窗
15. **前端拦截器** — user_disabled/team_disabled 错误码弹窗提示后跳登录页

### 新增/变更 API
| Method | Endpoint | Description |
|--------|----------|-------------|
| GET | `/api/v1/admin/anomalies` | 登录异常记录（筛选：team/rule/level/date） |
| POST | `/api/v1/admin/test-feishu` | 发送飞书测试消息 |
| POST | `/api/v1/admin/teams/<id>/auto-learn` | 自动学习预期登录地区 |
| POST | `/api/v1/admin/teams/<id>/apply-learned-regions` | 应用学习到的预期地区 |

### 新增文件
| 文件 | 用途 |
|------|------|
| `backend/utils/geo_client.py` | IP 归属地解析（IP138 在线 + ip2region 离线） |
| `backend/utils/anomaly_detector.py` | 异常检测引擎（R1-R5 规则） |
| `backend/utils/alert_service.py` | 告警服务（飞书 interactive 卡片） |
| `backend/apps/accounts/migrations/0008_anomaly_detection_phase2.py` | 账号模型迁移 |
| `backend/apps/generation/migrations/0006_anomaly_detection_phase2.py` | 配额模型迁移 |
| `web/src/pages/AnomalyLogPage.tsx` | 安全日志页面 |

### 变更文件
| 文件 | 改动 |
|------|------|
| `CLAUDE.md` | 新增异常检测相关模型/API/路由/环境变量文档 |
| `backend/apps/accounts/authentication.py` | SessionJWT 认证增加 team.is_active 检查 |
| `backend/apps/accounts/models.py` | 新增 LoginAnomaly/TeamAnomalyConfig 模型，User/Team 新增 disabled_by |
| `backend/apps/accounts/views.py` | login_view 增加 geo 解析 + 异常检测调用 |
| `backend/apps/generation/models.py` | QuotaConfig 新增异常检测全局配置字段 |
| `backend/apps/generation/serializers.py` | 新增异常检测相关 Serializer |
| `backend/apps/generation/urls.py` | 新增 4 条路由 |
| `backend/apps/generation/views.py` | 新增 anomalies/test-feishu/auto-learn/apply-learned-regions 视图 |
| `backend/config/settings.py` | 新增 ALIYUN_IP_GEO_APPCODE / FEISHU_APP_SECRET 配置 |
| `backend/requirements.txt` | 新增 ip2region>=2.7.0 |
| `web/src/App.tsx` | 新增 /admin/security 路由 |
| `web/src/lib/api.ts` | 新增 getLoginAnomalies/testFeishu/teamAutoLearn/applyLearnedRegions |
| `web/src/pages/AdminLayout.tsx` | 侧栏新增"安全日志"导航 + 修改密码弹窗 |
| `web/src/pages/SettingsPage.tsx` | 新增异常检测配置卡片 |
| `web/src/pages/TeamsPage.tsx` | 预期地区编辑/自动学习 + 团队级阈值配置 |
| `web/src/pages/TeamsPage.module.css` | membersTitle 间距调整 |
| `web/src/pages/UsersPage.tsx` | disabled_by 来源标签 |
| `web/src/types/index.ts` | 新增 LoginAnomaly/TeamAnomalyConfig 接口 |

### 触发原因
- 火山引擎明确禁止 C 端使用 Seedance API，需要防止团队私自将账号开放给 C 端个人用户
- 第一期已完成并发会话限制 + Token 缩短 + 登录记录，第二期基于 IP 归属地做异常检测

### 关键设计决策
- 异常检测不阻塞登录（try/except 包裹）
- 在线 API 熔断 60 秒自动降级离线库
- R2 城市名直接比较（不算距离），空城市跳过（防误封）
- R4 只统计预期城市列表之外的城市
- R5 统计国家数而非 IP 数（VPN 轮换 IP 但出口国家固定）
- 飞书告警异步发送（daemon thread），不拖慢登录
- TeamAnomalyConfig 独立模型，不污染 Team

---

## 2026-03-16 — v0.9.1: 首页 + 播放器修复

**状态**: ✅ 已完成 | **验收**: ✅ 通过（本地验证）

### 变更内容
1. **首页音乐泄漏修复** — 登录跳转 `/app` 后 BGM 继续播放，添加组件卸载时 pause + reset
2. **自适应视频播放器比例修复** — `adaptive` 比例视频在详情弹窗中固定 16:9 容器，改为读取视频固有 `videoWidth/videoHeight` 自适应缩放
3. **自适应比例中文化** — 视频详情弹窗、生成卡片标签、详情 tooltip 中 `adaptive` 改为显示「自适应」
4. **登录弹窗提示语** — 登录按钮下方添加「目前仅限受邀创作者体验」提示

### 变更文件
| 文件 | 改动 |
|------|------|
| `web/src/pages/LandingPage.tsx` | 添加 useEffect 清理：组件卸载时暂停音乐 |
| `web/src/components/VideoDetailModal.tsx` | adaptive 比例读取视频固有尺寸 + 显示中文「自适应」 |
| `web/src/components/GenerationCard.tsx` | 两处 aspectRatio 显示改为中文「自适应」 |
| `web/src/components/LoginModal.tsx` | 添加受邀创作者提示文字 |
| `web/src/components/LoginModal.module.css` | 新增 `.hint` 样式 |

---

## 2026-03-16 — v0.9.0: 品牌首页（Landing Page）

**状态**: ✅ 已完成 | **验收**: ✅ 通过（本地验证）

### 变更内容
1. **5 层极光首页** — 全新单屏 Landing Page，Canvas 实现有机流动极光背景（暗角→胶片颗粒→极光光球→渐变遮罩→内容层）
2. **品牌标识** — 标题 "AIRFLOW STUDIO" + 副标题 "AI VISUAL NARRATIVE"，Space Grotesk 字体（300/400/500）
3. **双入口按钮** — Air Drama（品牌青色高亮）/ Air Spark（幽灵按钮），中文副标题移至按钮下方独立小字
4. **登录弹窗** — 点击 Air Drama 原地弹出登录 Modal（磨砂玻璃背景 + backdrop-filter: blur），替代独立登录页跳转
5. **Air Spark 全屏提示** — 毛玻璃遮罩 + 戏剧性大字 "别急，土豆🥔正在 coding 中"，点击任意位置关闭
6. **鼠标极光交互** — 鼠标靠近光球时轻推偏移（28px），lerp 缓动跟踪，离开后缓慢回归
7. **极光呼吸感** — 5 个光球各自不同位置/大小/亮度/呼吸频率，避免均匀蓝块，保持明暗对比
8. **彩蛋文字** — 底部 "Every frame was once just air." opacity 0.06，hover 2s 过渡到 0.25
9. **音乐彩蛋** — 右下角 SVG 音波图标，点击播放/暂停 BGM，竖线从中心向两端扩展跳动（JS 随机高度 + CSS transition）
10. **路由重构** — `/` → LandingPage, `/login` → LandingPage + 自动弹登录框, `/app` → VideoGenerationPage
11. **Logo 替换** — 全站 5 处 Logo 替换为品牌 Logo（favicon、侧栏、管理后台、团队管理、登录弹窗）

### 变更文件
| 文件 | 改动 |
|------|------|
| `web/src/components/AuroraCanvas.tsx` | 新建：Canvas 极光 + 胶片颗粒 + 暗角 + 鼠标交互 |
| `web/src/components/LoginModal.tsx` | 新建：登录弹窗组件 |
| `web/src/components/LoginModal.module.css` | 新建：磨砂玻璃弹窗样式 |
| `web/src/pages/LandingPage.tsx` | 重写：5 层架构 + 双按钮 + Air Spark 遮罩 + 音乐彩蛋 |
| `web/src/pages/LandingPage.module.css` | 重写：全新首页样式 |
| `web/src/App.tsx` | 路由重构：`/login` → `<LandingPage autoLogin />` |
| `web/index.html` | 添加 Space Grotesk 字体 + favicon |
| `web/src/components/Sidebar.tsx` | Logo 替换 + 导航 `/` → `/app` |
| `web/src/pages/AdminLayout.tsx` | Logo 替换 + 返回链接 `/app` |
| `web/src/pages/TeamAdminLayout.tsx` | Logo 替换 + 返回链接 `/app` |
| `web/src/pages/ProfilePage.tsx` | 返回链接 `/` → `/app` |
| `web/src/components/ProtectedRoute.tsx` | 未认证重定向 `/login` |
| `web/public/favicon.png` | 新增：品牌 favicon |
| `web/public/bgm.mp3` | 新增：首页背景音乐 |
| `web/src/assets/logo_32.png` | 新增：小尺寸 Logo |
| `web/src/assets/logo_128.png` | 新增：中尺寸 Logo |
| `web/src/assets/logo_512.png` | 新增：大尺寸 Logo |

### 触发原因
- 系统之前只有登录页，缺少品牌展示首页
- 需要对标 Runway/Pika 等 AI 视频平台的首页质感
- 两个子产品（Air Drama / Air Spark）需要统一入口

### 备注
- 旧 LoginPage.tsx 保留未删除，作为备用
- 极光效果使用 Canvas + `globalCompositeOperation: 'lighter'` + CSS `filter: blur(50px)`
- 移动端自动降级 Canvas 分辨率（0.5x DPR）

---

## 2026-03-16 — v0.8.5: 安全加固（CRITICAL + HIGH 修复）

**状态**: ✅ 已完成 | **验收**: 待线上验证

### 变更内容
1. **C1/C2: 密钥硬编码清除** — `settings.py` 移除数据库密码和 SECRET_KEY 默认值，`backend-deployment.yaml` 中 DB_PASSWORD/DB_HOST/DB_USER/DJANGO_SECRET_KEY 改为 K8s Secret 引用
2. **H1: DEBUG 默认改 False** — 防止生产环境遗漏配置时暴露调试信息
3. **H2: 登录限流** — DRF `ScopedRateThrottle` 实现 `login: 5/min`，全局匿名 30/min、认证用户 120/min
4. **H4: Django Admin 限制** — 仅在 `DEBUG=True` 时注册 `/admin/` URL
5. **H6: XSS 防护** — 安装 DOMPurify，`PromptInput.tsx` 的 `innerHTML` 赋值前进行 HTML 消毒
6. **H7: ALLOWED_HOSTS 收紧** — 从 `"*"` 改为 `airflow-studio-api.airlabs.art,localhost`
7. **H9: Nginx 安全头** — `server_tokens off` + X-Frame-Options/X-Content-Type-Options/X-XSS-Protection/Referrer-Policy/Permissions-Policy
8. **M1: 密码策略加强** — 最小 8 位 + 常见密码检测 + 纯数字密码检测
9. **M5: Django 安全头** — 生产环境启用 XSS Filter/Content-Type-Nosniff/X-Frame-Options/SSL Proxy Header
10. **L1: 登录 POST-only** — 移除 GET 方法支持

### 变更文件
| 文件 | 改动 |
|------|------|
| `backend/config/settings.py` | SECRET_KEY/DB 默认值清除、DEBUG 默认 False、密码策略加强、DRF 限流配置、生产安全头 |
| `backend/config/urls.py` | Django Admin 仅 DEBUG 模式注册 |
| `backend/apps/accounts/views.py` | 登录 POST-only + LoginRateThrottle |
| `k8s/backend-deployment.yaml` | DB/SECRET_KEY 改为 secretKeyRef、ALLOWED_HOSTS 收紧 |
| `web/nginx.conf` | server_tokens off + 5 个安全响应头 |
| `web/src/components/PromptInput.tsx` | DOMPurify 消毒 innerHTML |
| `web/package.json` | 新增 dompurify 依赖 |

---

## 2026-03-16 — v0.8.4: 管理员操作审计日志

**状态**: ✅ 已完成 | **验收**: ✅ 通过（本地测试）

### 变更内容
1. **AdminAuditLog 模型** — 新增审计日志 Model，记录操作人、操作类型（12 种）、目标、变更前后值（JSONField）、IP 地址、时间
2. **`log_admin_action()` 辅助函数** — 统一的审计日志写入接口，自动获取操作人和客户端 IP
3. **12 处 view 埋点** — 所有管理员 mutation 操作均记录审计日志：
   - 创建类：团队创建、团队管理员创建、用户创建、成员创建
   - 修改类：团队更新、团队充值、设置秒数池、用户额度更新、系统设置更新、成员额度更新
   - 状态类：用户状态切换、成员状态切换
4. **日志查询 API** — `GET /api/v1/admin/logs`，支持按操作类型、操作人、日期范围筛选 + 分页
5. **前端日志页面** — `/admin/logs` 操作日志页，含筛选栏（操作类型下拉、操作人搜索、日期范围）、变更详情展示（旧值 → 新值）、分页
6. **侧栏导航** — AdminLayout 新增"操作日志"菜单项

### 变更文件
| 文件 | 改动 |
|------|------|
| `backend/apps/accounts/models.py` | 新增 AdminAuditLog 模型 + log_admin_action 函数 |
| `backend/apps/accounts/migrations/0005_adminauditlog.py` | 新增迁移 |
| `backend/apps/generation/views.py` | 12 处埋点 + admin_audit_logs_view 新端点 |
| `backend/apps/generation/urls.py` | 新增 admin/logs 路由 |
| `web/src/types/index.ts` | 新增 AuditLog 接口 |
| `web/src/lib/api.ts` | 新增 getAuditLogs 方法 |
| `web/src/pages/AuditLogsPage.tsx` | 新建日志页面 |
| `web/src/pages/AuditLogsPage.module.css` | 新建日志页面样式 |
| `web/src/pages/AdminLayout.tsx` | 侧栏新增"操作日志" |
| `web/src/App.tsx` | 新增 /admin/logs 路由 |

### 新增 API
| Method | Endpoint | Description |
|--------|----------|-------------|
| GET | `/api/v1/admin/logs` | 审计日志查询（支持 action/operator/start_date/end_date 筛选） |

### 触发原因
- 充值、修改秒数等操作直接对应金钱，填错无法追溯
- 需要记录谁在什么时候做了什么操作、改了什么值

---

## 2026-03-16 — v0.8.3: 团队详情弹窗重构 + 修改秒数功能

**状态**: ✅ 已完成 | **验收**: 待测试

### 变更内容
1. **团队详情：抽屉→弹窗** — 右侧抽屉改为居中弹窗（Modal），遵循 VideoDetailModal 设计规范：毛玻璃背景 `backdrop-filter: blur(24px)`、`border-radius: 16px`、入场动画、精致的关闭按钮
2. **弹窗尺寸优化** — 宽度 1080px、最小高度 70vh，桌面端大气不小气
3. **字号提升** — 统计卡片标签 `#8b8ea8` 12px、数值 `#f1f0ff` 18px、成员表 14px（对齐 VideoDetailModal 规范）
4. **修改秒数池功能** — 团队详情"总秒数池"卡片旁新增编辑按钮，支持直接设置 `total_seconds_pool` 值（后端校验不能低于已消耗秒数、不能为负）
5. **member_count 修复** — 后端团队详情 API 漏返回 `member_count` 字段，已补上

### 变更文件
| 文件 | 改动 |
|------|------|
| `web/src/pages/TeamsPage.tsx` | 抽屉→弹窗结构、修改秒数池 UI + handler |
| `web/src/pages/TeamsPage.module.css` | 全部 Team Detail Modal 样式重写（VideoDetailModal 规范） |
| `web/src/lib/api.ts` | 新增 `setTeamPool` API 方法 |
| `backend/apps/generation/views.py` | 新增 `admin_team_set_pool_view`、团队详情补返 `member_count` |
| `backend/apps/generation/urls.py` | 新增 `admin/teams/<id>/set-pool` 路由 |

### 新增 API
| Method | Endpoint | Description |
|--------|----------|-------------|
| PUT | `/api/v1/admin/teams/<id>/set-pool` | 直接设置团队总秒数池 |

### 触发原因
- 团队详情使用右侧抽屉形式，信息拥挤、不符合暗色主题规范
- 充值秒数填错后无法修改，而这些秒数直接对应金钱
- 成员数卡片值为空（后端遗漏字段）

---

## 2026-03-16 — v0.8.2: 管理后台 UI 修复（4 项）+ 失败原因展示

**状态**: ✅ 已完成 | **验收**: 待测试

### 变更内容
1. **DatePicker 日历透明修复** — `.dropdown` 背景从半透明 `var(--color-bg-card)` 改为不透明 `#16161e` + `backdrop-filter`
2. **自定义 Select 组件** — 替换原生 `<select>` 白色下拉面板，暗色主题 + 动画 + click-outside 关闭（RecordsPage 1 处、UsersPage 2 处）
3. **公告横幅美化** — 渐变背景 + 左侧强调色竖条 + CSS 跑马灯滚动（hover 暂停）+ 淡出遮罩
4. **Toast 全局化** — `<Toast />` 从 VideoGenerationPage 移至 App.tsx 根级，管理后台页面（如设置页保存）可正常显示提示
5. **失败原因 tooltip** — 消费记录表中失败状态悬浮显示 `error_message`；CSV 导出增加"失败原因"列；后端 admin_records API 返回 `error_message` 字段

### 变更文件
| 文件 | 改动 |
|------|------|
| `web/src/components/DatePicker.module.css` | `.dropdown` 背景改为不透明 |
| `web/src/components/Select.tsx` | 新建自定义暗色 Select 组件 |
| `web/src/components/Select.module.css` | 新建 Select 样式 |
| `web/src/pages/RecordsPage.tsx` | 替换原生 select + 失败原因 tooltip + CSV 导出 |
| `web/src/pages/RecordsPage.module.css` | 新增 errorTooltip 样式 |
| `web/src/pages/UsersPage.tsx` | 替换 2 处原生 select |
| `web/src/components/AnnouncementBanner.tsx` | 跑马灯结构 |
| `web/src/components/AnnouncementBanner.module.css` | 渐变背景 + 滚动动画 |
| `web/src/App.tsx` | 全局 `<Toast />` |
| `web/src/components/VideoGenerationPage.tsx` | 移除局部 `<Toast />` |
| `web/src/types/index.ts` | `AdminRecord` 增加 `error_message` |
| `backend/apps/generation/views.py` | admin_records 返回 `error_message` |

### 触发原因
- DatePicker / Select 下拉面板与暗色主题不协调
- 公告横幅样式简陋
- 管理后台保存设置无反馈
- 失败记录无法查看具体原因

---

## 2026-03-15 — v0.8.1: Seedance API 友好错误提示 + Mock 数据清理

**状态**: ✅ 已完成 | **验收**: ✅ 通过（本地端到端测试）

### 变更内容
1. **Seedance API 友好错误提示** — `seedance_client.py` 新增 `SeedanceAPIError` 异常类 + `ERROR_MESSAGES` 错误码映射表，API 报错时返回中文友好提示（如"参考图片中检测到真实人脸"）而非原始英文错误
2. **views.py 错误传递优化** — `video_generate_view` 异常处理识别 `SeedanceAPIError`，将 `user_message` 存入 `error_message` 字段，前端直接展示具体原因
3. **移除前端 Mock 数据** — `generation.ts` 删除 DEV 环境下的 7 个硬编码 mock 任务，消除页面加载时的 404 轮询错误

### 变更文件
| 文件 | 改动 |
|------|------|
| `backend/utils/seedance_client.py` | 新增 `SeedanceAPIError` 异常类 + `ERROR_MESSAGES` 映射 + `create_task` 错误解析 |
| `backend/apps/generation/views.py` | 异常处理区分 `SeedanceAPIError`，存储友好错误信息 |
| `web/src/store/generation.ts` | 删除 DEV mock 数据（7 个假任务），消除 404 轮询 |

### 触发原因
- 本地测试上传含真人面部的图片，Seedance 返回 400 但前端只显示"生成失败，请重试"，用户无法理解失败原因
- DEV 环境 mock 数据的假 taskId 触发持续 404 轮询错误

### 备注
- 已覆盖错误码：隐私人脸、敏感图片/视频、参数无效、频率超限、余额不足
- 未匹配的错误码会直接展示 API 原始 message

---

## 2026-03-15 — v0.8.0: Seedance API 全流程修复 + TOS 视频持久化

**状态**: ✅ 已完成 | **验收**: ✅ 通过（本地端到端测试）

### 变更内容
1. **音频引用支持** — 后端 content_items 构建新增 `audio` 类型分支，Seedance API 可接收音频参考素材
2. **视频 TOS 持久化** — Seedance 返回的临时 URL（24h 有效）自动下载并上传到 TOS，生成永久 CDN 链接；失败时降级使用临时 URL
3. **移除硬编码密钥** — ARK_API_KEY 默认值从测试 key 改为空字符串，避免生产环境误用
4. **渐进式轮询** — 前端轮询从固定 3 分钟改为渐进式：前 2 分钟每 10s → 2-5 分钟每 30s → 5 分钟后每 60s
5. **TOS 新桶配置** — 切换到独立桶 `airdrama-media`（cn-beijing），TOS 配置默认值更新
6. **K8s Secret 注入** — TOS_ACCESS_KEY / TOS_SECRET_KEY 通过 K8s Secret 注入，CI/CD 自动创建
7. **CI/CD 密钥同步** — deploy.yaml 新增 TOS 密钥到 kubectl secret 创建命令

### 变更文件
| 文件 | 改动 |
|------|------|
| `backend/apps/generation/views.py` | 新增 audio content_item 分支 + 完成时 TOS 持久化逻辑 |
| `backend/utils/tos_client.py` | 新增 `upload_from_url()` — 从 URL 下载并上传到 TOS |
| `backend/config/settings.py` | TOS 桶/区域/端点改为 airdrama-media (cn-beijing)；ARK_API_KEY 默认值清空 |
| `web/src/store/generation.ts` | setInterval → setTimeout 渐进式轮询 |
| `k8s/backend-deployment.yaml` | 新增 6 个 TOS 环境变量（AK/SK from Secret） |
| `.gitea/workflows/deploy.yaml` | kubectl secret 新增 TOS_ACCESS_KEY / TOS_SECRET_KEY |

### 触发原因
- Seedance API 文档审查发现：音频引用未传递、视频 URL 24h 过期、密钥硬编码
- 需要独立 TOS 桶存放生成视频（原桶为同事的阿里云 OSS）

### 备注
- 本地测试通过：文生视频 "一只猫在阳光下伸懒腰" → 87,300 tokens → 永久 TOS URL
- Seedance 2.0 定价：不含视频输入 46 元/百万 tokens，含视频输入 28 元/百万 tokens
- 资源包 5,000,000 tokens，约可生成 57 个 4 秒 720p 视频

---

## 2026-03-13 — 异常上报体系优化 + 轮询策略调整

**状态**: ✅ 已完成 | **验收**: ✅ 通过

### 变更内容
1. **LogCenterMiddleware** — 新增 Django 中间件，捕获 DRF 之外的异常（导入错误、中间件异常、URL 解析失败），上报日志中台
2. **custom_exception_handler 优化** — 未处理异常返回 JSON `{'error': '...'}` 而非 HTML 500
3. **轮询间隔调整** — 前端视频生成任务轮询从 5 秒改为 3 分钟（Seedance 生成耗时 2-5 分钟）
4. **CLAUDE.md 更新** — 增量开发指南从 "Autonomous Skill" 修正为 "agent-auto"

### 变更文件
| 文件 | 改动 |
|------|------|
| `backend/utils/log_center.py` | 新增 LogCenterMiddleware + 优化 custom_exception_handler |
| `backend/config/settings.py` | MIDDLEWARE 列表首位加入中间件 |
| `web/src/store/generation.ts` | 轮询间隔 5000ms → 180000ms |
| `CLAUDE.md` | 增量开发指南更新 |

### 触发原因
- 线上 `/api/v1/video/tasks` 返回 500，日志中台未收到错误上报
- 视频生成轮询过于频繁，增加后端负载

---

## 2026-03-13 — Phase 4: TOS 存储 + Seedance API 集成

**状态**: ✅ 已完成 | **验收**: ✅ 通过

### 变更内容
1. **TOS 文件上传** — 火山引擎 TOS（S3 兼容）上传，`POST /api/v1/media/upload`
2. **Seedance API 对接** — 火山方舟 Seedance 视频生成 API，异步 create_task + query_task
3. **数据库持久化** — GenerationRecord 新增 ark_task_id、result_url、error_message、reference_urls
4. **前端重写** — generation store 完全重写：TOS 上传 → API 调用 → 轮询 → 展示结果
5. **页面刷新持久化** — `loadTasks()` 从数据库加载历史任务

### 新增/变更 API
| 端点 | 方法 | 说明 |
|------|------|------|
| `/api/v1/media/upload` | POST | 上传文件到 TOS |
| `/api/v1/video/generate` | POST | 创建 Seedance 任务（改写） |
| `/api/v1/video/tasks` | GET | 用户任务列表（新增） |
| `/api/v1/video/tasks/<uuid>` | GET | 单任务状态轮询（新增） |

### 变更文件
| 文件 | 改动 |
|------|------|
| `backend/utils/tos_client.py` | 新增：TOS 上传客户端 |
| `backend/utils/seedance_client.py` | 新增：Seedance API 客户端 |
| `backend/config/settings.py` | TOS + ARK 配置 |
| `backend/apps/generation/models.py` | 4 个新字段 |
| `backend/apps/generation/views.py` | 3 个新端点 + 重写 generate |
| `backend/apps/generation/urls.py` | 3 条新路由 |
| `backend/apps/generation/serializers.py` | references 字段 |
| `backend/requirements.txt` | tos>=2.7, requests>=2.31 |
| `web/src/store/generation.ts` | 完全重写 |
| `web/src/types/index.ts` | BackendTask 接口 |
| `web/src/lib/api.ts` | mediaApi + videoApi |
| `web/src/components/VideoGenerationPage.tsx` | loadTasks on mount |
| `web/src/components/GenerationCard.tsx` | 视频播放器 + 错误态 |

---

## 2026-03-13 — 测试隔离 + Mock 数据清理

**状态**: ✅ 已完成 | **验收**: ✅ 通过

### 变更内容
1. **测试 DB 隔离** — `TESTING=true` 环境变量切换到 `test_db.sqlite3`，Playwright 自动启动测试后端
2. **移除 Mock 数据兜底** — DashboardPage 图表仅显示真实数据，无 mock fallback

### 触发原因
- E2E 测试会污染开发数据库
- Dashboard 应展示真实数据而非虚假 Mock

---

## 2026-03-12 — Phase 3: 秒数计量 + 管理后台重做 + 个人中心

**状态**: ✅ 已完成 | **验收**: ✅ 通过（agent-auto 自动测试）

### 变更内容
1. **计量单位变更** — 所有「调用次数」改为「生成秒数」(daily_seconds_limit / monthly_seconds_limit)
2. **管理后台重做** — Sidebar 多页面布局，4 个子路由：
   - `/admin/dashboard` — 仪表盘 + ECharts 折线图 + 排行柱状图
   - `/admin/users` — 用户管理（分页、搜索、配额编辑、启用/禁用）
   - `/admin/records` — 消费记录（时间筛选、导出 CSV）
   - `/admin/settings` — 系统设置 + 公告管理
3. **用户个人中心** (`/profile`) — ECharts 环形进度条 + Sparkline + 消费记录
4. **8 个新 API 端点** — admin: stats/users/users/:id/quota/status/records + profile: overview/records

### 设计规范
- 深色主题（Linear/Vercel 风格）
- ECharts + echarts-for-react
- Arco Design 组件库优先

---

## 2026-03-12 — Phase 2: 后端 + 用户认证 + 管理面板

**状态**: ✅ 已完成 | **验收**: ✅ 通过（agent-auto 自动测试）

### 变更内容
1. **Django 后端** — Django 4.2 + DRF + MySQL 云数据库
2. **JWT 认证** — SimpleJWT + 前端 Token 自动刷新
3. **用户系统** — 登录 `/login` + 注册 `/register`
4. **管理后台** — 基础仪表盘 + 用户配额管理
5. **9 个新 API 端点** — 认证 4 个 + 管理 3 个 + 已有接口认证 2 个

---

## 2025 — Phase 1: 核心视频生成 UI

**状态**: ✅ 已完成 | **验收**: ✅ 通过（92 单元测试 + 14 E2E 测试）

### 变更内容
1. **视频生成页** — 全能参考/首尾帧双模式
2. **InputBar** — contentEditable 富文本 + @ mention
3. **深色主题 UI** — `#0a0a0f` 背景 + Arco Design
4. **状态管理** — Zustand store

---

## 模板（新增变更请复制此模板）

```markdown
## YYYY-MM-DD — 变更标题

**状态**: 🔲 开发中 / ✅ 已完成 | **验收**: 🔲 待验收 / ✅ 通过 / ❌ 未通过

### 变更内容
1. ...

### 变更文件
| 文件 | 改动 |
|------|------|
| `path/to/file` | 描述 |

### 触发原因
- ...

### 备注
- ...
```
