# 数字分身 H5 生产接入与部署 ## 1. 接入方式 生产会会在用户已登录后打开以下地址: ```text https://<数字分身生产域名>/#/avatar/manage?token= ``` 测试环境示例: ```text http://192.168.1.188:8099/#/avatar/manage?token= ``` 兼容参数位于域名查询串的形式,但生产统一使用上面的 hash 路由形式。必须对 token 调用 `encodeURIComponent`,不能拼接用户 ID 代替 token。 免登录流程如下: 1. H5 在页面渲染前读取 `token`,立即通过 `history.replaceState` 从地址栏和浏览器历史中移除。 2. H5 调用 `POST /api/huihui/token/login`,不会把会会 token 当作数字分身接口 token 直接使用。 3. 后端通过会会生产接口 `/im/box/netease` 换取 BOXIM 凭证,再调用 BOXIM `/user/self` 校验用户身份。 4. 后端以返回的 `huihuiUserId` 绑定本地用户,保存会会凭证供 BOXIM 接管功能使用,并签发本系统 `app_token`。 5. 浏览器只保存 `app_token` 和非敏感用户资料。会会原始 token 不返回浏览器存储。 6. token 无效、过期或上游校验失败时清除旧会话并进入登录页,不会沿用上一位用户的缓存身份。 ## 2. 生产配置 后端 `.env` 至少配置以下内容,密钥由部署平台注入,禁止提交 Git: ```dotenv HUIHUI_DEV_MOCK=false HUIHUI_AUTH_BASE_URL=https://99hui.com/api/usercenter HUIHUI_PLATFORM_BASE_URL=https://open.99hui.com/api BOXIM_API_BASE_URL=https://im.99hui.com/api HUIHUI_APP_ID= HUIHUI_ACCESS_ID= HUIHUI_ACCESS_SECRET= HUIHUI_CLIENT_CODE= BOXIM_TIMEOUT_SECONDS=20 DATABASE_URL=sqlite:////data/avatar.db UPLOAD_DIR=/data/uploads CHAT_MODEL_CONFIG_URL=http:///api/ai-models/runtime/digital-avatar ``` 如生产 AI 配置中心不可用,还应提供当前项目支持的 `OPENAI_API_KEY`、`OPENAI_BASE_URL`、`CHAT_MODEL` 等兜底配置。`/data` 必须挂载持久卷,数据库与知识库文件不可存放在容器临时层。 ## 3. 构建与发布 首次发布前备份数据: ```bash BACKUP_DIR="backups/$(date +%Y%m%d-%H%M%S)" mkdir -p "$BACKUP_DIR" cp /srv/digital-avatar/data/avatar.db "$BACKUP_DIR/" tar -C /srv/digital-avatar/data -czf "$BACKUP_DIR/uploads.tgz" uploads ``` 在发布目录执行: ```bash git fetch origin git checkout <已验收的提交SHA> cd digital-avatar-app docker compose build --pull avatar-backend avatar-frontend docker compose up -d avatar-backend avatar-frontend docker compose ps curl -fsS http://127.0.0.1:8099/api/health ``` 生产编排应把示例中的测试端口改为内网暴露,由统一 HTTPS 网关接入。后端暂时使用 SQLite,必须保持单实例写入;若扩展为多后端实例,应先迁移到 PostgreSQL,并把延迟接管任务改为共享队列。 ## 4. 网关要求 必须使用 HTTPS。同域部署时,H5 静态资源与 `/api/` 由同一域名提供,可避免跨域和 Cookie/来源策略问题。Nginx 关键配置示例: ```nginx location / { try_files $uri $uri/ /index.html; } location /api/ { proxy_pass http://avatar-backend:8000; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_buffering off; proxy_read_timeout 300s; client_max_body_size 20m; } ``` `proxy_buffering off` 用于数字分身 SSE 流式吐字,`client_max_body_size` 用于知识库文件上传。网关和应用日志必须关闭完整 URL 查询参数记录,任何异常日志都不得输出 token、Authorization 或平台密钥。建议同时设置严格的 `Referrer-Policy: no-referrer`。 ## 5. 发布验收 1. 已登录会会用户通过带 token 链接打开后直接进入 `/avatar/manage`,不出现登录页或创建新账号页。 2. 页面加载后地址栏中不再包含 `token`,刷新页面仍使用本地 `app_token` 正常访问。 3. 后端用户绑定的是 BOXIM 返回的 `huihuiUserId`,不是 BOXIM 内部 `id`;原有数字分身、独立知识库和 Token 余额均存在。 4. A、B 两个会会用户分别进入时只能看到各自的数字分身与知识库,不会继承上一用户缓存。 5. 使用过期或伪造 token 时进入登录页并显示凭证失效,不得继续访问旧用户数据。 6. 分身聊天 SSE 逐段输出正常,Markdown 正常渲染,知识库优先级和 Token 扣费正常。 7. 开启 BOXIM 主动接管后保持在线,收到消息、三秒回复、已读回执和主人发言暂停均正常。 8. 重建容器后数据库、头像、知识库文档仍存在,`/api/health` 返回成功。 ## 6. 回滚 保留上一版前后端镜像标签和发布前数据库/上传文件备份。代码回滚优先切回上一镜像;只有新版本执行了不可逆数据变更时才恢复数据库。恢复前先停止后端写入,恢复后对比用户数、分身数、知识库文档数并完成一次免登录和聊天验收。