# 开发交接 —— 换一台开发机继续做(2026-11-02) > **写给**:在新 Windows 机器上接手的人(或未来的 agent) > **不涉及**:服务器 / 聚石塔 / SAE 都不用重建,云端资源全部现成可用 > **上一份**:[HANDOFF-2026-11-01.md](HANDOFF-2026-11-01.md)(那一轮只到「链路打通 + Java MVP」,UI 和真机测肤是这一轮做的) --- ## 0. 一句话状态 **真机全链路已跑通**:淘宝小程序 → 云网关(AppKey 35486228)→ 聚石塔云应用 1me-net → 私网 CLB → SAE `nnn`(只做透传)→ 聚石塔 NAT 出网(EIP `47.92.113.176`)→ `https://1me.xajuzi.com/tb/` → 现有 H5 的 Node 服务 → 旷视 Face++,**三视图拍摄后报告正常返回**。 小程序五个页面的 UI 已按 H5 重做(像素级对齐,见下)。剩下的是相机组件验证和一批工程化工作,清单在第 8 节。 --- ## 1. 新机器准备 ### 1.1 必装 | 工具 | 版本 | 用途 | |---|---|---| | Git | 任意近期版本 | 拉代码 | | Node.js | **18+(推荐 20/22)** | `taobao/` 测试、`h5/` 本地跑、零依赖 | | JDK | **17** | `backend-java/` 编译与测试 | | Maven | 3.9.x | 同上 | | 淘宝小程序开发者工具 | 最新 | 真机预览(**模拟器不支持云应用 SDK**) | | PowerShell 7(可选) | 7.x | 仓库里的脚本按 pwsh 语法写 | ### 1.2 拉代码 ```powershell git clone https://git.xiangsilian.com/xsl/juzi.git cd juzi ``` > 远端证书有效期到 2027-01-29;凭据失效时重新配置 Git 凭据管理器。 ### 1.3 小程序依赖(必做,否则真机报 `Cannot find module`) ```powershell cd taobao npm ci ``` `@tbmp/mp-cloud-sdk` 固定 1.5.10,只有这一个运行期依赖。 ### 1.4 工具链 仓库自带 `tools/env-java.ps1`,查找顺序:仓库内便携工具链 → 环境变量 → PATH。 ```powershell Set-ExecutionPolicy -Scope Process Bypass . .\tools\env-java.ps1 # 输出 JAVA_HOME / MAVEN_HOME / java -version ``` - 用系统安装的 JDK 17 + Maven 即可,**不需要**再下便携版 - 想复原老机器的布局:把 JDK 放 `tools/jdk17/`、Maven 放 `tools/maven/apache-maven-3.9.9/`(这两个目录 gitignore) ### 1.5 必须单独拷贝的机密文件(**不在 git 里**) | 文件 | 内容 | 没有会怎样 | |---|---|---| | `backend-java/src/main/resources/application-local.yml` | 淘宝 AppKey/AppSecret + `mode: forward` + `forward-base` | JAR 里没有 AppKey/Secret,`/session` 一定 401 | | `reference/facepp-skinanalyze/credentials.env` | 旷视 `FACEPP_API_KEY/SECRET` | `h5/server.js` 启动即 `exit(1)` | | SSH 私钥 | 免密登录 `ubuntu@1me.xajuzi.com` | 无法部署 Node 侧 / 看日志 | ```powershell # 从老机器拷(示例) scp <老机器>:D:/juzi/backend-java/src/main/resources/application-local.yml .\backend-java\src\main\resources\ scp <老机器>:D:/juzi/reference/facepp-skinanalyze/credentials.env .\reference\facepp-skinanalyze\ ``` 新机器要能 ssh 服务器的话:`ssh-keygen -t ed25519` 后把公钥追加到服务器 `~/.ssh/authorized_keys`。 > 老机器若已不可用:AppSecret / 旷视 key 找项目负责人索取,或在开放平台重置(重置后记得同步更新服务器 `/etc/juzi/taobao.env` 与 JAR)。 ### 1.6 淘宝 IDE 的一个已知坑(Windows) 老机器上 IDE 曾因 `wmic` 缺失打不开,用 `tools/fix-taobao-ide-wmic.ps1` 生成过一个 shim(`C:\Users\<你>\.local\bin\wmic.cmd`)。新机器如果 IDE 报 `install miniapp extension fail: ... wmic ...`,跑这个脚本。 --- ## 2. 仓库地图 ``` juzi/ ├── taobao/ 淘宝小程序(当前主战场) │ ├── config.js ★ 环境/传输配置(cloud+tower+test、assetBase) │ ├── app.acss ★ 全局设计 token(对齐 H5 的 .btn-primary/.card/.chev/.popup) │ ├── pages/ │ │ ├── splash/ 启动页(登录、隐私弹窗、开发版入口) │ │ ├── profile/ 档案填写(出生/性别/地区/肤质轮播) │ │ ├── camera/ 拍照页(蒙版取景 or 系统相机兜底) │ │ ├── report/ 报告页(环形分、7 视角、叠加层、标记点) │ │ ├── history/ 历史报告 │ │ ├── mvp/ 连通性调试页(ping/whoami/echo) │ │ └── camtest/ ★ 相机组件冒烟页(只放 ,判断组件是否可用) │ ├── utils/ │ │ ├── transport.js 云网关/direct 两种传输 + 信封解包 │ │ ├── api.js 9 个接口封装(challenge/session/me/photo/skin-analyze/…) │ │ ├── permissions.js ★ 权限(scope 前缀、诊断 diagnose()) │ │ ├── image.js 1280 长边 + JPEG q0.88 压缩 │ │ ├── voice.js 语音播报(异常静默) │ │ └── report-model.js payload → 报告页 data │ └── test/ 20 个 node:test 用例 ├── h5/ ★ 真正的测肤后端(Node,零依赖) │ ├── server.js 入口:Face++ 调用、评分、报告、admin │ ├── lib/taobao-*.js ★ 淘宝云网关路由/验签/会话(关键算法在这里) │ ├── js/skin-score.js 评分引擎(6 类 → 3 维,4:3:3 加权) │ └── test/ 一堆独立测试脚本(没有统一 runner) ├── backend-java/ SAE 上的透传层(Spring Boot 3.5.6 / Java 17) │ ├── src/main/java/com/juzi/mvp/api/ │ │ ├── TaobaoForwardController.java ★ mode=forward 时字节级透传 │ │ ├── TaobaoEnvelope.java 客户端要的 data.ok + data.http_status │ │ ├── TaobaoAuthController.java native 模式的登录接口(当前未启用) │ │ └── TaobaoSessionService.java challenge + Bearer token │ └── src/main/java/com/juzi/mvp/gateway/TaobaoSignatureVerifier.java 验签算法 ├── deploy/ ★ 服务器侧配置(systemd / nginx / 安装脚本) ├── docs/ 交接与实施文档(本文件所在) └── tools/ 构建与素材脚本 ``` --- ## 3. 三套测试 ```powershell # 1) 小程序:20 个用例 cd taobao ; npm test # 2) Java:11 个用例(含验签向量的回归测试) cd backend-java ; mvn test # 3) H5 单测(独立脚本,逐个跑) node h5/test/taobao-auth.js # 网关签名,必须 PASS ``` **改动提交前请保证**:`taobao` 20/20 + `backend-java` 11/11。老机器最后一次全绿是在 `fed5293`。 > `taobao/test/frontend.test.cjs` 会用 vm 真跑页面 JS,页面 data 字段改名要同步改测试。 --- ## 4. 本地怎么跑 ### 4.1 H5 后端(Node,测肤真正的实现) ```powershell cd h5 $env:PORT=8099 ; $env:HOST='127.0.0.1' ; $env:JUZI_ENTRY_MODE='state' $env:JUZI_DATA_ROOT='..\temp\h5-data' node server.js # http://127.0.0.1:8099/api/health → {"ok":true} ``` 启动时缺旷视 key 会直接退出。只想调 UI/接口时给假值即可(真实检测会失败,但路由可用): ```powershell $env:SKIN_API_KEY='dummy' ; $env:SKIN_API_SECRET='dummy' ``` ### 4.2 Java(SAE 那一层) ```powershell . .\tools\env-java.ps1 cd backend-java mvn spring-boot:run # 或 mvn -DskipTests package 后 java -jar target\*.jar curl.exe -X POST -H "Content-Type: application/json" -d "{}" http://127.0.0.1:8080/api/taobao/ping ``` - 默认 `mode: native`(Java 自己实现登录,便于单独调接口) - 部署用的 `application-local.yml` 里写的是 `mode: forward` - 本地想看透传:`$env:TAOBAO_MODE='forward'` + `$env:TAOBAO_FORWARD_BASE='http://127.0.0.1:8099'` ### 4.3 小程序 1. 淘宝 IDE 导入仓库里的 `taobao/`(`mini.project.json` 的 `appid` 留空,以 IDE 账号为准) 2. **确认 IDE 当前小程序是 35486228(`1me 肌肤状态检测`)** 3. `config.js` 保持 `transport: 'cloud'` / `cloudType: 'tower'` / `cloudEnv: 'test'` 4. 顶部「预览」→ **手机淘宝扫码**(模拟器不支持 `cloud.application.httpRequest`) 5. 启动页右上角有三个**开发版入口**(`environment !== 'production'` 时才显示): | 入口 | 作用 | |---|---| | 权限诊断 | 打印 `my.canIUse`、`getSetting` 的 authSetting、`authorize` 的原始返回(真机上唯一能看到这些的地方) | | 相机组件测试 | 整页只有一个 ``,用来判断组件是否可用 | | SAE MVP 连通性 | `ping/whoami/echo`,看 `transport:"gateway"`、`server:"java"` | --- ## 5. 云端资源(只读,无需重建) | 资源 | 值 | |---|---| | 开放平台应用 | `1me 肌肤状态检测`,AppKey **35486228** | | 旧应用(废弃) | `1me肌肤检测` 35479221 —— **不要再用它的 Secret** | | 聚石塔云应用 | `1me-net`,ID **62829**,默认应用 | | 私网 CLB | `lb-k2j324dwux1svaf2akwqx` / `192.168.65.185:80` | | SAE 应用 | `nnn`,`cn-zhangjiakou:my-namespace` | | 代码包 | `taobao-mvp-backend-0.0.4-forward.jar`(**环境变量全空**,配置都在包里) | | VPC / vSwitch | `vpc-8vb5mcvenp8jwa1roqcsa` / `vsw-8vbna5zb2rq03gaeiymch`(可用区 A) | | NAT 出口 EIP | **47.92.113.176**(nginx `/tb/` 白名单按它放行) | | 服务器 | `ubuntu@1me.xajuzi.com`,Node v20.20.2 | | 生产 H5 | `https://1me.xajuzi.com/state/` → `juzi-h5.service`(8080) | | 红书渠道 | `https://1me.xajuzi.com/rednote/` → `juzi-rednote.service`(8081) | | 淘宝专用 | `https://1me.xajuzi.com/tb/` → `juzi-taobao.service`(18081) | --- ## 6. 改完怎么上线 ### 6.1 小程序 IDE 编译 → 预览(自测)→ 「上传」发版本。**不需要碰服务器。** ### 6.2 Java(SAE) ```powershell . .\tools\env-java.ps1 ; cd backend-java mvn clean package # 测试会自动跑 # 产物 target\taobao-mvp-backend-0.0.4-forward.jar ``` SAE 控制台 → `nnn` → 部署应用 → 代码包部署 → 上传 JAR(**版本号要和上次不同**,否则会被当成同一个版本)→ 环境变量保持全空。 ### 6.3 Node(`/tb` 实例) 见 [deploy/README.md](../deploy/README.md) 第 1 节。核心三步: ```powershell tar -czf temp/juzi-h5.tgz --exclude=h5/data --exclude=h5/test -C . h5 scp temp/juzi-h5.tgz ubuntu@1me.xajuzi.com:/tmp/ ``` ```bash ssh ubuntu@1me.xajuzi.com "tar -xzf /tmp/juzi-h5.tgz -C /home/ubuntu/juzi-tb && sudo systemctl restart juzi-taobao" ``` > ⚠️ **不要动** `/home/ubuntu/juzi`(生产 H5)和 `/home/ubuntu/juzi-rednote`。我们那份是独立拷贝 `/home/ubuntu/juzi-tb`。 --- ## 7. 这一轮的关键结论(踩过的坑,别重复踩) 1. **云网关签名算法**:真实请求**不带 `sign_method`**,缺省等价于 `MD5(secret + content + secret)`(`content` = 排序后的 `key+value` 拼接 + **原始 body 字节**)。之前按 `MD5(content + secret)` 实现,是 10 月底那个「signature mismatch」的真因。改在 [h5/lib/taobao-auth.js](../h5/lib/taobao-auth.js)。 2. **淘宝的 scope 是带前缀的** `scope.camera` / `scope.album`;传裸名 `camera` 返回 `{"errorCode":"5022","errorMessage":"Scope:camera信息不存在"}`。 3. **`` 组件在真机上会让整页崩溃**,且 `my.canIUse('camera')` 返回 `yes` 是**假阳性**。当前默认走系统相机(`config.nativeCamera = false`)。怀疑原因是相机里嵌了**微信专有的 ``**,已改成兄弟节点 + 普通 view 覆盖,并加了 `pages/camtest` 冒烟页——**这个还没在真机验证,是新机器的第一件事**。 4. **网关限制**:单请求 **10 秒 / 128KB**。所以 `skin-analyze` 必须 **202 + 1 秒轮询(最长 90 秒)**,不能同步等旷视。 5. **旷视 Face++**:正式 key 有并发窗口,必须**串行 + 4 秒间隔**;60 秒超时,失败/5xx/并发超限重试 1 次;返回值含 `face_maps`,4000px 素材时约 3.2MB(真实链路客户端压到 1280,约 200–300KB)。 6. **`/api/taobao/reports` 详情带 3 张 base64 照片**,历史报告页有超时风险(网关大响应未验证)。 7. **会话/任务全在内存**:SAE 只能单副本;`juzi-taobao` 重启后登录态与进行中的任务都会丢。 8. **没有任何清理策略**:每次检测在磁盘留 10–12MB,长期必须换 OSS。 9. **转发必须字节级透传**:签名覆盖原始 body 和 query,Java 一旦重新序列化 JSON 就会 401。 10. **生产那台 Node 是旧代码**,没有 `/api/taobao/*`;我们另外起 `/home/ubuntu/juzi-tb`(18081)跑新代码,用 nginx `/tb/` 分流。 11. **图片资源**走 `https://1me.xajuzi.com/state/assets/`(`config.assetBase`)。之前是 `127.0.0.1:18180`,真机上全部加载失败。 --- ## 8. 待办(建议顺序) | # | 事项 | 说明 | |---|---|---| | 1 | **真机验证 `pages/camtest`** | 能出实时画面 → 把 `config.nativeCamera` 改 `true`,拍照页立刻有蒙版取景;仍然崩 → 维持系统相机 | | 2 | `/reports` 详情瘦身 | 现在透传 3 张 base64 原图(约 0.5MB+),改缩略图或 OSS URL | | 3 | 存储工程化 | 照片/原始 JSON/记录 → OSS + RDS;现在全在容器/单机磁盘,无清理 | | 4 | 旷视请求裁剪 | `return_maps` 请求 10 层但报告只用 6 层,可少传 4 层省带宽与落盘 | | 5 | WebP 转码(可选) | 实测:6 层图 WebP q80 省 54%,叠 50% 缩放省 84%;**先真机验证 `` 支持 WebP data URL** | | 6 | 密钥治理 | `application-local.yml` / `/etc/juzi/taobao.env` 里的 AppSecret、JAR 内嵌 Secret → 改 KMS/保密字典,并**重置一次 AppSecret** | | 7 | Java 端可选迁移 | `mode=native` 的登录接口已写好并测过(4 个用例),可把 auth 从 Node 搬到 Java;测肤仍留在 Node | | 8 | 仓库收拾 | `sdk-java-35479221/`、三个 `.pptx`、`tools/build_taobao_proposal_*.py` 仍未跟踪,建议加 ignore 或删除 | | 9 | 启用签名校验(Java 侧) | 当前 forward 模式下由 Node 验签;若切 `native` 或要 `/ping` 也验签,把 `verify-sign` 打开即可(算法已修复) | --- ## 9. 故障对照表 | 现象 | 原因 | 处理 | |---|---|---| | 真机 `cloud init failed` | IDE 当前 app 不是 35486228 / 云应用没设默认 | 确认 IDE 账号与 AppKey | | `淘宝身份校验失败,请重新授权登录` | 云网关签名不匹配 | 检查服务器 `/etc/juzi/taobao.env` 的 AppSecret;算法见第 7 节第 1 条 | | `请先配置淘宝云应用和 HTTPS 服务地址` | `cloudType` 不是 `tower` 或 `transport` 不是 `cloud` | 看 `config.js` | | 页面一片灰没有图 | `assetBase` 指向 127.0.0.1 | 应为 `https://1me.xajuzi.com/state/assets/` | | 点拍照整页崩(「系统遇到一点问题」) | `` 组件 | 保持 `nativeCamera: false`,用系统相机/相册 | | 报告页白屏 | `payload` 为空或 `report-model` 抛错 | 看启动页「SAE MVP 连通性」是否 `server:"java"` | | SAE 侧 `上游 403` | 容器出口 IP 不在 nginx `/tb/` 白名单 | `curl -s https://myip.ipip.net` 取新 IP,改 nginx 后 reload | | `Cannot find module '@tbmp/mp-cloud-sdk'` | 没装依赖 / IDE 没构建 npm | `npm ci`,IDE「工具 → 构建 npm」 | | Java 打包报找不到 `application-local.yml` | 机密文件没拷过来 | 见 1.5 | --- ## 10. 交接检查清单 - [ ] `npm ci`(taobao)跑过 - [ ] `tools/env-java.ps1` 能加载出 JDK17 + Maven - [ ] `application-local.yml` 与 `credentials.env` 已从老机器拷来 - [ ] `taobao` 20/20、`backend-java` 11/11、`node h5/test/taobao-auth.js` PASS - [ ] IDE 打开 `taobao/` 并确认 AppKey 是 35486228 - [ ] 真机预览能看到图片(说明资产域名通) - [ ] 真机点「权限诊断」→ `authorize(scope.camera)=ok` - [ ] 真机点「相机组件测试」→ 记录结果,决定 `nativeCamera` 开关 - [ ] 能 `ssh ubuntu@1me.xajuzi.com`,`systemctl is-active juzi-taobao` 为 active --- **给接手者的第一句话**:先按第 1 节把机器装好、把两个机密文件拷过来,跑通三套测试;然后去真机验 `camtest`——那是唯一还悬着的技术问题,也决定拍照页最终形态。