# 需求变更日志 (Changelog) > 按日期倒序记录每次需求变更。每条记录在开发完成、测试验收通过后归档。 --- ## 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//auto-learn` | 自动学习预期登录地区 | | POST | `/api/v1/admin/teams//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` → `` | | `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//set-pool` 路由 | ### 新增 API | Method | Endpoint | Description | |--------|----------|-------------| | PUT | `/api/v1/admin/teams//set-pool` | 直接设置团队总秒数池 | ### 触发原因 - 团队详情使用右侧抽屉形式,信息拥挤、不符合暗色主题规范 - 充值秒数填错后无法修改,而这些秒数直接对应金钱 - 成员数卡片值为空(后端遗漏字段) --- ## 2026-03-16 — v0.8.2: 管理后台 UI 修复(4 项)+ 失败原因展示 **状态**: ✅ 已完成 | **验收**: 待测试 ### 变更内容 1. **DatePicker 日历透明修复** — `.dropdown` 背景从半透明 `var(--color-bg-card)` 改为不透明 `#16161e` + `backdrop-filter` 2. **自定义 Select 组件** — 替换原生 `