# 云函数部署指南 本目录是 fmode 云函数源码。前端通过 `src/app/services/cloud-functions.ts` 里的函数 ID 调用这些函数。 后续新增的 `authCredit`、`systemStorage`、`fileAsset` 与既有 `manifest/task/history/result` 等函数使用同一套 fmode 云函数部署和调用机制:上传或更新对应 `.js` 文件,获得函数 ID,再回填到 `src/app/services/cloud-functions.ts`。它们不是新的后端体系。 ## 部署清单 `_session.js` 是用户私有数据云函数的共享源码依赖,作用是统一解析 Parse `sessionToken` 和校验管理员权限。当前 fmode 云函数运行环境不支持直接 `require('./_session')`,因此不要直接复制带 `require` 的源码文件部署。 部署前必须先执行: ```bash npm run build:cloud-functions ``` 然后复制 `cloud-functions/deployable/` 下对应编号的单文件版本到 fmode 平台。`deployable` 文件会内联 `_session.js`,不再依赖 `require`。源码文件仍保留共享模块写法,方便后续维护;真实部署以 `cloud-functions/deployable/*.js` 为准。 | 字段 | 文件 | 状态 | 主要 action / 能力 | |---|---|---|---| | session helper | `_session.js` | 源码依赖 | requireSession / optionalSession / requireAdmin / assertRequestedUserMatchesSession | | Parse Class helper | `_parseClassStore.js` | 源码依赖 | Parse REST / VideoWorkflow* Class / projectKey / owner Pointer | | `manifest` | `01-manifestManager.js` | 已配置 | list / get / create / update / delete | | `task` | `02-taskManager.js` | 已配置 | list / get / create / update / delete | | `history` | `03-historyManager.js` | 已配置 | list / create / delete / clearAll | | `result` | `04-resultManager.js` | 已配置 | list / get / create / update / delete | | `remix` | `05-remixManager.js` | 已配置 | listAll / listByVideo / upsert / delete | | `voice` | `06-voiceManager.js` | 已配置 | autoSpeakerId / syncProfile / listProfiles / initPool / deleteProfile | | `quickly` | `07-quicklyVideo.js` | 待部署 | create / query | | `proxy` | `08-proxyHub.js` | 已配置 | llmChat / geminiChat / llmChatStream | | `upload` | `09-uploadManager.js` | 已配置 | createUploadToken | | `authCredit` | `10-authCreditManager.js` | 已配置 ID,按需更新验收 | me / balance / rechargeContext / reserve / commitReservation / refundReservation / ledger / createRechargeOrder / saveRecharge | | `jimeng` | `11-jimengManager.js` | 已配置 | 即梦图片、视频、数字人、动作迁移代理 | | `douyin` | `12-douyinManager.js` | 已配置 | TikHub 抖音搜索、详情、评论、博主数据代理 | | `douyinInsight` | `13-douyinInsightManager.js` | 已配置 | 爆款分析、选题池、日报资产持久化、逐字稿任务 | | `systemStorage` | `14-systemStorageManager.js` | 已配置 ID,本次需用最新 deployable 更新线上内容并验收 | list / get / upsert / patch / delete / purge / audit / auditList / stats / migrationGet / migrationSet / adminInspect | | `fileAsset` | `15-fileAssetManager.js` | 已配置 ID,本次需用最新 deployable 更新线上内容并验收 | register / list / get / stats / bind / delete / purge / adminInspect | ## 部署步骤 1. 打开 fmode 云函数管理平台。 2. 新建或更新云函数,名称建议与文件名一致。 3. 对于 `01/02/03/04/05/06/09/13/14/15`,粘贴 `cloud-functions/deployable/` 下对应 `.js` 文件完整内容;对于不依赖 `_session.js` 的 `10/11/12/08` 等单文件函数,可直接粘贴 `cloud-functions/` 下源码。 4. 在平台配置该函数需要的环境变量。 5. 保存并部署,复制返回的 10 位函数 ID。 6. 更新 `src/app/services/cloud-functions.ts` 对应字段。 7. 执行 `npm run smoke:cloud` 验证已配置函数是否可调用。部署需要登录态的函数后,再带 `SMOKE_SESSION_TOKEN` 执行严格验收。 8. 执行 `npm run build` 验证前端编译。 ## 外部凭证清单 | 函数 | 必需凭证/配置 | 说明 | |---|---|---| | `06-voiceManager.js` | `VOICE_TOKEN`, `VOICE_TTS_BASE_URL` | 火山 TTS/音色训练代理;`listProfiles` 不需要调用上游。 | | `07-quicklyVideo.js` | `QUICKLY_APP_KEY`, `QUICKLY_APP_SECRET`, `QUICKLY_ACCOUNT_ID`, `QUICKLY_CALLBACK_URL`, `QUICKLY_RELAY_URL`, `QUICKLY_UPSTREAM_FN_ID` | 一键成片。如不用该功能可保持 `quickly` 为空。 | | `08-proxyHub.js` | `LLM_BASE_URL`, `LLM_API_KEY` | LLM/Gemini 代理。 | | `09-uploadManager.js` | `QINIU_AK`, `QINIU_SK`, `QINIU_BUCKET`, `QINIU_CDN_DOMAIN`, `QINIU_CDN_PREFIX`, `QINIU_UPLOAD_URL` | 七牛直传 token。 | | `10-authCreditManager.js` | `PARSE_API_HOST`, `PARSE_APP_ID`, `VIDEO_WORKFLOW_APIG_ID` | 当前项目的 Parse/APIG 账号积分网关,不再自建 AppUser/UserCreditAccount。 | | `11-jimengManager.js` | `JIMENG_TOKEN`, `JIMENG_BASE_URL`, `PARSE_BASE_URL`, `PARSE_APP_ID` | 即梦真实生成代理。为保留公司计费,线上 `JIMENG_BASE_URL` 应指向 `https://server.fmode.cn/api/volcengine/jimeng`;云函数会依次尝试 `fetch`、Node HTTPS、XMLHttpRequest 访问同一公司接口。 | | `12-douyinManager.js` | `DOUYIN_API_BASE_URL`, `DOUYIN_API_TOKEN`(可复用 `VOC_TOKEN` / `VOICE_TOKEN`) | 抖音真实平台数据抓取。默认走 `https://server.fmode.cn/api/voc-social`。 | | `13-douyinInsightManager.js` | `PARSE_API_HOST`, `PARSE_APP_ID`, `DOUYIN_API_BASE_URL`, `DOUYIN_API_TOKEN`, `IFLYTEK_GATEWAY_BASE_URL` | 业务资产持久化和用户隔离;逐字稿任务通过抖音数据网关获取视频详情,转写网关鉴权优先使用当前登录用户的 Parse `sessionToken`,与 `douyin-speaking-daily` 的 VOC token 机制一致。 | | `14-systemStorageManager.js` | `PARSE_API_HOST`, `PARSE_APP_ID` | 通用业务云端主存储,承接暂未独立建表的用户私有业务实体、轻量审计和迁移状态。 | 以上变量均已在云函数源码中改为“环境变量优先、当前兼容值兜底”。正式部署时应在 fmode 云函数平台配置环境变量,并在确认新变量生效后轮换旧凭证。 ## 当前前端函数 ID 见 `src/app/services/cloud-functions.ts`。当前仍为空的字段: - `quickly`: 一键成片云函数未启用。 - `authCredit`: 账号/积分云函数已有函数 ID;本次 Parse 主存储迁移不改 APIG 计费链路,只需确认余额仍可读。 - `systemStorage`: 通用业务云端主存储已有函数 ID;本次需把最新 `cloud-functions/deployable/14-systemStorageManager.js` 更新到该函数并验收。 - `fileAsset`: 七牛云文件资产治理已有函数 ID;本次需把最新 `cloud-functions/deployable/15-fileAssetManager.js` 更新到该函数并验收。 ## 验证命令 ```bash npm run smoke:cloud npm run build ``` `smoke:cloud` 会从 `src/app/services/cloud-functions.ts` 自动读取函数 ID,避免部署后需要在脚本里维护第二份 ID。函数 ID 为空的项目会跳过;对于 `jimeng`、`douyin`、`proxy` 会用预期失败请求验证函数可达和路由校验是否生效,避免触发真实生成或真实扣费。 部署 `authCredit`、`systemStorage`、`fileAsset`、新版 `upload` 后,建议执行: ```bash npm run smoke:cloud SMOKE_STRICT_PROTECTED=1 npm run smoke:cloud SMOKE_SESSION_TOKEN=你的_Parse_Session_Token npm run smoke:cloud SMOKE_SESSION_TOKEN=你的_Parse_Session_Token npm run validate:parse-storage:postdeploy ``` - 不带 session token:验证公开函数可达,并在严格模式下验证需要登录的函数会拒绝匿名访问。 - 带 `SMOKE_SESSION_TOKEN`:验证 `authCredit.balance`、`systemStorage.stats`、`fileAsset.stats` 和新版 `upload.token` 能用真实登录态成功返回。 - `validate:parse-storage:postdeploy`:用单个测试账号实际写入、读回、审计并软删除一条 `VideoWorkflowEntity`,同时注册、读回并软删除一条 `VideoWorkflowFileAsset` 元数据。 - 新版 `upload.token` 的成功验收会检查七牛 key 是否进入 `users/{userId}/...` 分区;如果仍返回旧的 `x/openclaw-skills/...`,说明线上 `09-uploadManager.js` 还没有更新到账号隔离版本。 完成 `authCredit/systemStorage/fileAsset/upload` 部署并回填函数 ID 后,再用两个不同测试账号执行账号隔离验收: ```bash STORAGE_GOVERNANCE_SESSION_A=用户A_Parse_Session_Token \ STORAGE_GOVERNANCE_SESSION_B=用户B_Parse_Session_Token \ npm run validate:storage-governance:postdeploy ``` 该命令会: - 验证用户 A 能读取 `authCredit.balance`。 - 用用户 A 在 `VideoWorkflowEntity` 写入一条 `governanceProbe` 临时实体并读回。 - 用用户 B 尝试读取用户 A 的同一 `governanceProbe`,必须读不到。 - 验证新版 `upload` 返回的七牛 key 进入 `users/{userId}/...` 分区。 - 用 upload 返回的用户分区 key 注册一条临时 `VideoWorkflowFileAsset` 元数据,读回后软删除。 - 验证用户 A 可读取 `fileAsset.stats`。 - 最后清理用户 A 的临时 `governanceProbe`。 注意:两个 session token 都是敏感信息,只能在本地命令行临时使用,不要写入文档、源码或提交记录。 2026-06-01 联网冒烟结果: - 最终通过:`manifest.list`、`task.list`、`history.list`、`result.list`、`remix.listAll`、`voice.listProfiles`、`upload.token.probe`、`jimeng.unknownAction`、`douyin.unknownRoute`、`douyinInsight.authGuard`、`proxy.unknownAction`。 - 权限保护符合预期:`douyinInsight.listTopics` 未带 session token 时返回“请先登录”。 - 首轮曾出现 `manifest.list`、`task.list` 偶发 `fetch failed`,复跑通过;后续生产运维需要继续观察函数平台网络稳定性。 - 未启用:`quickly`。`authCredit`、`systemStorage`、`fileAsset` 当前已有函数 ID;如果在 fmode 平台重建函数并产生新 ID,需要同步回填 `src/app/services/cloud-functions.ts`。 ## 首次部署后的特殊步骤 `voiceManager` 需要初始化 speaker_id 池: ```js await fetch('https://server.fmode.cn/api/functions', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-Parse-Application-Id': 'ncloudmaster', }, body: JSON.stringify({ id: 'voice 函数 ID', _ApplicationId: 'ncloudmaster', action: 'initPool', speakerIds: ['S_xxx', 'S_yyy'], }), }); ``` ## 上线前检查 - `cloud-functions.ts` 不允许留错函数 ID。 - 必需凭证要配置在云函数平台环境变量中。 - `npm run smoke:cloud` 通过。 - `npm run build` 通过。 - 批量真实生成、素材归档、发布复盘抓取各跑一条端到端样例。 ## 2026-06-03 凭证治理补充规范 本项目已经新增根目录 `.env.example` 作为本地开发配置模板。后续本地联调请复制为 `.env` 后填写真实值,`.env` 已被 `.gitignore` 忽略,禁止提交真实凭证。 云函数部署时必须在 fmode 云函数平台配置环境变量。代码中后续会逐步移除真实 token/key fallback,因此不要依赖源码里的兼容兜底值。 ### 变量分组 | 能力 | 变量 | 用途 | |---|---|---| | 即梦生成 | `JIMENG_TOKEN`, `JIMENG_BASE_URL` | 文生视频、图生视频、图片生成、数字人、动作迁移。为保留公司计费,生产建议使用 `https://server.fmode.cn/api/volcengine/jimeng`。 | | 抖音数据 | `DOUYIN_API_BASE_URL`, `DOUYIN_API_TOKEN`, `VOC_TOKEN`, `VOC_SOCIAL_TOKEN` | 视频详情、评论、博主作品、爆款分析证据抓取 | | TikHub 直连 | `TIKHUB_BASE_URL`, `TIKHUB_TOKEN` | 仅在明确直连 TikHub 时使用 | | 逐字稿 | `IFLYTEK_GATEWAY_BASE_URL` | 爆款分析补逐字稿、音频转写;云函数入口通过 Parse `sessionToken` 做用户鉴权和数据隔离,并优先把同一个当前用户 session token 作为转写网关 VOC token 使用。`TRANSCRIPTION_VOC_TOKEN` / `VOICE_TOKEN` / `OPENCLAW_VOC_TOKEN` / `VOC_TOKEN` 仅保留为诊断或兼容兜底,不作为线上多用户主路径。 | | LLM/Gemini | `LLM_BASE_URL`, `LLM_API_KEY` | AI 助手、脚本生成、素材理解 | | 七牛上传 | `QINIU_AK`, `QINIU_SK`, `QINIU_BUCKET`, `QINIU_DOMAIN`, `QINIU_CDN_DOMAIN`, `QINIU_CDN_PREFIX`, `QINIU_UPLOAD_URL` | 上传 token 和素材归档 | | 语音合成 | `VOLC_TTS_TOKEN`, `VOLC_SPEECH_API_KEY`, `VOLC_SPEECH_APP_KEY`, `VOLC_SPEECH_ACCESS_KEY`, `VOICE_TTS_BASE_URL` | TTS、音色训练、语音合成 | | Quickly | `QUICKLY_APP_KEY`, `QUICKLY_APP_SECRET`, `QUICKLY_ACCOUNT_ID`, `QUICKLY_CALLBACK_URL`, `QUICKLY_RELAY_URL`, `QUICKLY_UPSTREAM_FN_ID` | 一键成片 | ### 安全要求 - 文档、源码、提交记录中不记录真实 token/key。 - `diagnose` 类接口只能返回 `tokenConfigured`、`tokenSource`、`baseUrl`,不能返回明文 token。 - 已经暴露在源码或聊天记录中的凭证,上线前需要在对应平台轮换。 - 缺少凭证时应返回中文配置错误,提示具体变量名,不允许静默使用错误账号。