腾讯会议数字资产离职继承
员工离职时,其名下的**周期性会议(未来待召开会议)**与**云录制文件**需要交接给在职继承人。本文给出一套可直接集成的实现方案:在 HR 离职审批通过后,调用腾讯会议用户资产转移接口(`/v1/users/delete-transfer`)自动完成交接。 下载链接中共包含三份代码: |交付物|说明| | --- | --- | |Node.js 核心库(transfer-nodejs)|TypeScript| |Java 核心库(transfer-java/)|Java 17 + Maven,由 Agent Skill 生成| |skills(transfer-skills)|Agent Skill,用于生成其他语言版本| ## 前提条件 1. 已创建腾讯会议自建应用(参考[自建应用创建指引](https://cloud.tencent.com/document/product/1095/42413)),开启「管理企业用户」权限点,操作者具备用户列表编辑权限; 1. 使用 AK/SK 鉴权(SdkId / AppId / SecretId / SecretKey); 1. 运行环境:Node.js ≥ 18,或 Java ≥ 17。 ## 快速开始 ``` # Node.js 独立服务 cd transfer-nodejs && npm install && npm run build && npm run start:prod # Java 库(编译 + 单元测试) cd transfer-java && mvn package ``` ## 用 Agent Skill 生成其他语言版本 Java 核心库不是人工翻译的,而是由 Agent Skill 驱动 AI 编程助手生成的,保证不同语言版本行为一致。Skill 位于 `skills/meeting-asset-transfer/`,支持按需移植到任意目标语言(默认 Java),结构如下: ``` meeting-asset-transfer/ ├── SKILL.md # 目标语言判定 + 生成工作流 + 行为保真清单(20+ 核对项) └── references/ ├── ts-source-spec.md # TS 源码语义规格:签名算法、请求体字段、校验规则(语言无关) ├── tencent-meeting-api.md # delete-transfer 接口契约 + 实测错误码表(语言无关) ├── porting-guide.md # 通用移植指南:各语言 HMAC/HTTP/JSON 选型、校验适配、安全基线 └── lang-java.md # Java 专用映射 profile:类职责、HTTP 客户端、异常策略 ``` 使用方式:让 AI 编程助手加载该 skill,并指明目标语言(不指明时默认 Java)。它会先读取语言无关的规格文档,再加载目标语言的映射规则(有专用 profile 用 profile,否则走通用移植指南),按「签名 → 客户端 → DTO → 编排」的顺序生成代码,最后逐项核对保真清单并编译验证。 当腾讯会议接口变更或需要调整行为时,只需更新 skill 中的规格文档再重新生成,各语言版本即可保持同步;完成一门新语言的移植后,还可将映射决策沉淀为新的 `lang-.md` profile,保证后续同语言移植的一致性。 ## 实现流程 ### 1 删除离职用户 资产转移接口仅支持对**已被删除的企业用户**操作,因此发起转移前,离职用户必须已在腾讯会议企业内删除。客户侧的账号删除可以通过调用腾讯会议[「删除用户」REST API](https://cloud.tencent.com/document/product/1095/93436)(`DELETE /v1/users/{userid}`)删除。 > 注意:删除账号不会销毁其名下会议与录制数据,资产在转移前处于待交接状态。 ### 2 集成资产继承库 #### Node.js / TypeScript 将 `transfer-nodejs/src/meeting/` 整个目录拷入自有项目,提供以下接口方法: |方法|说明| | --- | --- | |new TencentMeetingClient(config)|创建客户端,凭证通过构造参数传入| |transferAssets(client, request)|批量转移:逐项调用 + 结果汇总(最常用入口)| |validateAssetTransferRequest(body)|入参校验,返回错误信息列表(空列表表示通过)| |client.transferUserAssets(params)|单次转移,需自行控制循环/并发时使用| |buildSignatureHeaders(secretId, secretKey, method, uri, body)|AK/SK 签名,调用腾讯会议其他 REST API 可复用| 客户端配置参数: |参数|必填|默认值|说明| | --- | --- | --- | --- | |appId / secretId / secretKey|是|—|自建应用凭证| |operatorId|是|—|操作者 userid,需具备用户列表编辑权限| |sdkId|是|—|自建应用 SdkId| |baseUrl|否|https://api.meeting.qq.com|接口地址| |timeoutMs|否|10000|单次请求超时| 在 HR 离职审批通过的回调中调用: ``` import { TencentMeetingClient } from './meeting/client'; import { transferAssets } from './meeting/transfer'; const client = new TencentMeetingClient({ appId: config.meeting.appId, // 从自有配置中心/密钥管理体系获取 secretId: config.meeting.secretId, secretKey: config.meeting.secretKey, operatorId: config.meeting.operatorId, sdkId: config.meeting.sdkId, }); const result = await transferAssets(client, { from_userids: ['departed_user'], // 离职员工,须已在企业内删除 to_userids: ['heir_user'], // 接收人,一般为主管或同岗位接替人 transfer_scopes: ['all'], // meeting=周期性会议 recording=云录制 all=全部 }); // result: { total, success_count, fail_count, results[] } // 失败项在 results[i].error_code / error_message 中原样透传腾讯错误 ``` #### Java Java 库位于 `meeting-asset-transfer-java/`,包 `com.example.meeting.transfer`,拷入 `src/main/java` 即可。接口方法与 TypeScript 版一一对应: |方法|说明| | --- | --- | |new TencentMeetingConfig(appId, secretId, secretKey, operatorId, sdkId)|配置(record 类型,可选 registered / baseUrl / timeoutMs)| |new TencentMeetingClient(config)|创建客户端,HTTP 使用 JDK 内置 java.net.http.HttpClient| |AssetTransferService.transferAssets(client, request)|批量转移:逐项调用 + 结果汇总| |AssetTransferService.validate(request)|入参校验,返回 List(空列表表示通过)| |client.transferUserAssets(fromUserid, receiverId, transferData)|单次转移,transferData:"0"=全部 "1"=云录制 "2"=会议列表| |SignatureUtil.buildSignatureHeaders(...)|AK/SK 签名,可复用| 调用示例: ``` TencentMeetingConfig config = new TencentMeetingConfig( "your-app-id", "your-secret-id", "your-secret-key", "admin_userid", "your-sdk-id"); TencentMeetingClient client = new TencentMeetingClient(config); AssetTransferRequest request = new AssetTransferRequest( List.of("departed_user"), List.of("heir_user"), List.of(TransferScope.ALL)); List errors = AssetTransferService.validate(request); if (!errors.isEmpty()) { // 校验失败,errors 逐条指出出错字段与下标 } AssetTransferResponse result = AssetTransferService.transferAssets(client, request); if (result.fail_count() > 0) { // 按 result.results().get(i).error_code() 处理失败项,如 500047=用户未删除 } ``` 密钥一律从配置中心或环境变量注入,不写入代码、不输出日志。 ### 3 (可选)独立部署 HTTP 服务 不便修改自有系统代码时,可将 `transfer/` 作为独立服务部署,HR 系统通过 HTTP 调用。将 `.env.example` 复制为 `.env` 并填写: ``` ###### 必填参数 ###### MEETING_APP_ID= # 自建应用 AppId MEETING_SDK_ID= # 自建应用 SdkId MEETING_SECRET_ID= # 自建应用 SecretId MEETING_SECRET_KEY= # 自建应用 SecretKey MEETING_OPERATOR_ID= # 操作者 userid ###### 可选参数 ###### API_KEY= # 对调用方的鉴权密钥,建议 openssl rand -hex 32 生成;不配置则不校验 PORT=3000 # 监听端口 ``` ``` npm install && npm run build && npm run start:prod ``` 服务暴露 `POST /api/v1/asset-transfers`,请求体与核心库入参结构一致(三个等长列表);配置了 `API_KEY` 时请求头需携带 `x-api-key`。响应逐项返回成功/失败,失败项携带透传的 `error_code` / `error_message`,HR 系统可据此生成待办或告警。 ### 4 错误码处理 常见的错误码包括: |场景|HTTP|error_code| | --- | --- | --- | |离职用户未删除(来源为在职用户)|500|500047| |收发同人|400|190004| |接收人为已删除用户|400|190004| |用户不存在(操作者/来源/接收人)|500|20001| |来源 IP 不在应用白名单|400|500125| |鉴权失败(AppId/SecretId/SecretKey 错误)|400|190303| |应用/操作者无权限|400|9042 / 500014|