Files
cozsweet-frontend-nextjs/docs/frontend-integration/2026-07-22-private-zone-rename.md
T
Codex 0357fbcaff
Docker Image / Build and Push Docker Image (push) Successful in 2m7s
refactor(private-zone): use canonical product name
2026-07-23 10:55:47 +08:00

8.6 KiB
Raw Blame History

Private Zone 全链路改名联调说明

  • 日期:2026-07-22
  • 目标环境:本地、pre、生产
  • 当前状态:已验证

1. 目标

原功能名称存在拼写错误。本次将前端、unified 后端、Manager、数据库、埋点和文档中的正式命名统一为 Private Zone,并同步切换页面路由、API 路径和公开枚举值。

2. 环境地址

环境 前端 API Base URL
pre https://frontend-test.banlv-ai.com https://proapi.banlv-ai.com
生产 https://cozsweet.com https://api.banlv-ai.com

3. 前端影响

前端已完成以下修改:

  • 页面路由统一为 /private-zone/characters/{characterSlug}/private-zone
  • 外部入口参数统一为 target=private-zone
  • 支付回跳参数统一为 returnTo=private-zone
  • 类型、Repository、API client、XState actor、Provider 和资源目录统一使用 privateZonePrivateZoneprivate-zoneprivate_zone
  • 埋点键统一为 navigation.private_zonechat.open_private_zone_from_avatar 等新名称。
  • 角色能力字段统一为 capabilities.privateZone

旧页面和旧查询参数不再作为正式入口保留。发布时必须让前后端属于同一个发布批次。

4. API 变更清单

所有接口都使用 Authorization: Bearer <TOKEN>,响应继续使用现有统一 envelope。请求与响应中未列出的业务字段保持原类型和含义。

方法 新路径 用途
GET /api/private-zone/albums 查询付费图片包
POST /api/private-zone/albums/{albumId}/unlock 解锁图片包
GET /api/private-zone/moments 查询朋友圈式内容
POST /api/private-zone/moments/{momentId}/unlock 解锁单条内容
GET /api/private-zone/config 查询当前角色和用户解锁配置
GET /api/private-zone/diaries 查询关系日记
POST /api/private-zone/diaries/{diaryId}/seen 标记关系日记已读
POST /api/private-zone/diaries/{diaryId}/unlock 解锁关系日记

4.1 图片包列表

GET /api/private-zone/albums?characterId=elio&limit=20
Authorization: Bearer <TOKEN>
字段 位置 类型 必填 可为 null 说明
characterId query string 角色 ID
limit query integer 1-50,默认 20
cursor query string 分页游标

调用示例:

curl 'https://proapi.banlv-ai.com/api/private-zone/albums?characterId=elio&limit=20' \
  -H 'Authorization: Bearer <TOKEN>'

4.2 解锁图片包

POST /api/private-zone/albums/{albumId}/unlock
Authorization: Bearer <TOKEN>
Content-Type: application/json
字段 位置 类型 必填 可为 null 说明
albumId path string 图片包 ID
expectedCost body integer 前端确认价格;与后端价格不一致时拒绝解锁
curl -X POST 'https://proapi.banlv-ai.com/api/private-zone/albums/<ALBUM_ID>/unlock' \
  -H 'Authorization: Bearer <TOKEN>' \
  -H 'Content-Type: application/json' \
  -d '{"expectedCost":320}'

4.3 Moments 内容与解锁

GET /api/private-zone/moments?characterId=elio&limit=20
POST /api/private-zone/moments/{momentId}/unlock

解锁请求体与图片包一致,expectedCost 为可选整数。响应中的正式分类值同步改为:

{
  "lockDetail": {
    "type": "private_zone_moment",
    "reason": "private_zone_moment"
  }
}

5. 其他公开值

使用位置 新值 类型
/api/chat/unlock-privatelockType 别名 private_zone string enum
日程导入 contentType 别名 private_zone string enum,归一化为 paid_content
外部入口 target private-zone string enum
支付回跳 returnTo private-zone string enum
锁定详情分类 private_zone_moment string enum

6. 数据库迁移

因为 pre 与生产当前共用 https://dbapi.banlv-ai.com,预发部署前先执行 unified 仓库中的临时桥接脚本:

database/private-zone-bridge.sql

桥接脚本会创建新表并在切换窗口内保持新旧解锁写入双向同步。生产前后端全部切换完成后,再执行最终迁移:

database/private-zone-migration.sql

迁移会在同一事务中完成:

  • 将历史解锁表无损重命名;新旧表同时存在时先合并再删除旧表。
  • 重命名关联约束、索引、策略和触发器。
  • 合并 users.preferences 中历史解锁键,防止已解锁内容重新锁定。
  • credit_ledger 历史分类迁移到 private_zoneprivate_zone_moment
  • 定向迁移历史埋点键、页面 URL 和系统媒体路径,不改写用户聊天正文。
  • 删除切换窗口使用的双写触发器和函数。
  • 支持重复执行。

7. 兼容性与发布顺序

这是破坏性命名修正,不保留旧 API、旧页面路由或旧公开枚举作为正式兼容层。必须按以下顺序发布:

  1. 备份数据库并记录当前 unified、前端和 Manager 版本。
  2. 执行 database/private-zone-bridge.sql,确认新旧表双向写入一致。
  3. 部署 unified pre,验证所有 /api/private-zone/* 接口。
  4. 部署前端 pre,验证页面、外部入口、解锁和支付回跳。
  5. Manager 更新后验证积分用途显示为新分类。
  6. pre 验证通过后,先启动新生产后端并临时配置旧 API 到新 API 的 Nginx 转发。
  7. 切换生产后端,再部署同批次生产前端;确认新前端只调用 /api/private-zone/*
  8. 删除临时 Nginx 转发,执行 database/private-zone-migration.sql 清理旧数据库对象。

8. 错误与界面状态

  • 401:Token 缺失或无效,前端进入现有登录恢复流程。
  • 403:游客访问仅注册用户可用的关系日记操作,展示现有注册引导。
  • 404:角色、图片包、内容或日记不存在,展示现有空状态或失效提示。
  • 409expectedCost 与后端价格不同,刷新列表后重新确认。
  • 402 或业务余额不足错误:进入现有充值流程,并使用 returnTo=private-zone 返回原角色页面。
  • 网络失败:不修改本地解锁状态,保留重试入口。

9. 验收用例

  1. /characters/elio/private-zone、Maya 和 Nayeli 对应页面均可打开。
  2. GET /api/private-zone/albums 返回当前角色内容,角色之间不混用。
  3. 已解锁历史记录在迁移后保持解锁状态,不重复扣积分。
  4. 新解锁成功后刷新页面仍为已解锁状态。
  5. 积分不足进入充值页后,回跳到原角色 /private-zone 页面。
  6. target=private-zone&character=nayeli 进入 Nayeli 对应页面。
  7. Manager 的积分用途不再出现旧分类。
  8. 三个仓库执行旧命名残留扫描,结果为 0

10. 当前测试证据

  • unified316 passed
  • 前端:TypeScript 类型检查通过;Vitest 639 passedESLint 通过;契约测试 4 passed;生产构建通过并生成三个角色的 /private-zone 页面。
  • Manager75 passed
  • PostgreSQL 16 临时库:升级、重复升级、回滚和再次升级全部通过;历史解锁、偏好键、积分账本、埋点、媒体路径和数据库对象名均通过断言,临时容器已删除。
  • preunified 71da49b 和前端 35939e7 已验证;新 API 已注册 8/api/private-zone/* 路径,旧 API 路径数量为 0;新页面返回 200,旧页面返回 404
  • 生产:unified 镜像 ai-boyfriend-unified:prod-20260722-71da49b(镜像 ID sha256:755ef5741856d83d7d808e7df8ee259b6fa5fb94fe333b523ee280ed1d5f674b)和前端镜像 prod-35939e7 已健康运行;Manager 当前版本为 6eea005
  • 生产接口:测试账号调用 GET https://api.banlv-ai.com/api/private-zone/config?characterId=elio 返回 200success=true;旧版 API 路径在所有公开 API 入口均返回 404
  • 生产数据库:最终迁移已执行,旧表、桥接函数、桥接触发器、旧偏好键、旧积分分类和旧埋点值的残留数量均为 0

11. 回滚影响

最终迁移执行前可直接恢复旧应用,桥接表会保留双向一致的数据。最终迁移执行后,回滚必须同时执行 unified 仓库中的 database/private-zone-rollback.sql。回滚前应停止写入,先保存切换后的新增解锁记录,再执行逆向迁移并恢复旧应用版本。不得只恢复前端或只恢复 unified。

12. 待确认事项

  • 无。