领航项目工作流 v2
> 基于 2026-04-17 实战复盘优化。覆盖代码同步→安全修复→NPC审查→部署→数据库→发布→治理全链路。
项目概况
- 技术栈:微信小程序 + 腾讯云开发(CloudBase)
- 环境 ID:
lh-6grvuo7nd197089a - 仓库:
cnbmm/linghang(当前主力)/yunjinhong/linghang(正式) - 本地路径:
/tmp/linghang - 云函数(8个):userLogin, submitOrder, exchangeUpgrade, getTeamMembers, useMemberCode, adminAdjustPoints, adminHandleOrder, adminCreateCode
- 数据库集合:users, orders, courses, point_records, member_codes, login_attempts
- NPC:云开发工程师
@tencent/cloud/cloudbase/community(云开发工程师),assignees 设cnbnn
场景 A:Release 包覆盖仓库代码
> 触发:老板发 zip 包要求"以这个为准"
步骤
# 1. 下载解压
cd /tmp && wget -q "<zip_url>" -O linghang-release.zip
unzip -qo linghang-release.zip -d linghang-release/
# 2. 克隆仓库(保留 git 历史)
git -c credential.helper='!f() { echo "protocol=https"; echo "host=cnb.cool"; echo "username=oauth2"; echo "password=${CNB_TOKEN}"; }; f' clone https://cnbmm/linghang.git linghang
# 3. 全量覆盖(保留 .git)
rm -rf linghang/* linghang/.* 2>/dev/null
cp -a linghang-release/<dir>/. linghang/
# 4. 提交推送
cd linghang && git add -A
git commit -m "chore: 同步 vX.Y.Z release 包作为新基准"
git push origin main
对比报告格式
diff -rq release/ linghang/ --exclude=node_modules --exclude=miniprogram_npm --exclude=.git \
--exclude='*.lock' --exclude='project.private.config.json' --exclude='skills-lock.json'
报告内容:
- 仅 release 有 / 仅仓库有的文件/目录
- 两边都有但内容不同的文件(逐文件 diff 关键差异)
- 分类:安全修复、功能差异、遗留文件
- 给出建议(合并方向、哪些需要重新合入)
场景 B:代码安全修复 + NPC 审查
> 触发:安全审查、代码审查、NPC派活
步骤 1:自我修复
直接在 /tmp/linghang 编辑文件,commit + push:
cd /tmp/linghang
git add -A && git commit -m "fix: 安全审查修复 (Issue #N)"
git push origin main
修复后必须做的事:
node -c cloudfunctions/<fn>/index.js # 语法检查
步骤 2:创建 Issue 派 NPC
# ⚠️ 路径是 /{repo}/-/issues,不是 /repos/{repo}/issues
# ⚠️ 必须带 Accept: application/vnd.cnb.api+json
export CNB_TOKEN="${CNB_TOKEN:?Error: CNB_TOKEN not set}"
curl -s -X POST "https://api.cnb.cool/cnbmm/linghang/-/issues" \
-H "Accept: application/vnd.cnb.api+json" \
-H "Authorization: Bearer ${CNB_TOKEN}" \
-H "Content-Type: application/json" \
-d @/tmp/issue-body.json
Issue body 模板:
@tencent/cloud/cloudbase/community(云开发工程师)
## 背景
<一句话说明>
## 审查范围(commit: <sha1>, <sha2>)
### 1. <文件路径>
- 修复内容
- 关注点
## 请重点审查
1. <问题1>
2. <问题2>
## 期望输出
- 审查结论:通过 / 需修改
- 如需修改:具体文件+行号+建议
Issue 参数:assignees: ["cnbnn"], priority: "P1"
步骤 3:检查 NPC 反馈
curl -s "https://api.cnb.cool/cnbmm/linghang/-/issues/<N>/comments" \
-H "Accept: application/vnd.cnb.api+json" \
-H "Authorization: Bearer ${CNB_TOKEN}"
步骤 4:合并 NPC PR
# ⚠️ 参数是 merge_style(不是 merge_method),且必须带 commit_title
curl -s -X PUT "https://api.cnb.cool/cnbmm/linghang/-/pulls/<N>/merge" \
-H "Accept: application/vnd.cnb.api+json" \
-H "Authorization: Bearer ${CNB_TOKEN}" \
-H "Content-Type: application/json" \
-d '{"merge_style":"squash","commit_title":"fix: 描述"}'
步骤 5:关闭 Issue
# ⚠️ state 和 state_reason 必须同时传
curl -s -X PATCH "https://api.cnb.cool/cnbmm/linghang/-/issues/<N>" \
-H "Accept: application/vnd.cnb.api+json" \
-H "Authorization: Bearer ${CNB_TOKEN}" \
-H "Content-Type: application/json" \
-d '{"state":"closed","state_reason":"completed"}'
场景 C:云函数部署
> 触发:部署、上线、更新云函数
单个部署
cd /tmp/linghang
yes | tcb fn deploy <name> --dir cloudfunctions/<name>
批量部署全部
cd /tmp/linghang && for fn in userLogin submitOrder exchangeUpgrade getTeamMembers useMemberCode adminAdjustPoints adminHandleOrder adminCreateCode; do
yes | tcb fn deploy "$fn" --dir "cloudfunctions/$fn" 2>&1 | tail -1
done
部署前检查
# 语法检查所有云函数
for fn in cloudfunctions/*/; do
name=$(basename $fn)
node -c "$fn/index.js" 2>&1 && echo "✅ $name" || echo "❌ $name"
done
清理遗留云函数
for fn in hello-world init-database initDatabase exchangeMemberCode exchangeService getPointsStats queryData; do
yes | tcb fn delete "$fn" --env-id lh-6grvuo7nd197089a 2>&1 | tail -1
done
场景 D:数据库集合 + 索引管理
> 触发:创建集合、创建索引、TTL索引
创建集合
# 方法1: @cloudbase/node-sdk(推荐)
# 先写入 /tmp/create-coll.js:
# const cloudbase = require('@cloudbase/node-sdk')
# const app = cloudbase.init({ env: 'lh-6grvuo7nd197089a', secretId: '...', secretKey: '...' })
# app.database().createCollection('collection_name').then(() => console.log('Done')).catch(e => console.error(e.message))
cd /tmp && npm install @cloudbase/node-sdk 2>/dev/null
node /tmp/create-coll.js
创建索引(含 TTL)
# 通过 MongoDB createIndexes 命令
yes | tcb db nosql execute --env-id lh-6grvuo7nd197089a --json \
--command '[{"TableName":"<collection>","CommandType":"COMMAND","Command":"{ \"createIndexes\": \"<collection>\", \"indexes\": [{ \"key\": { \"<field>\": -1 }, \"name\": \"<index_name>\", \"expireAfterSeconds\": <seconds> }] }"}]'
验证索引
yes | tcb db nosql execute --env-id lh-6grvuo7nd197089a --json \
--command '[{"TableName":"<collection>","CommandType":"COMMAND","Command":"{ \"listIndexes\": \"<collection>\" }"}]'
查看集合列表
tcb fn list --env-id lh-6grvuo7nd197089a
tcb db model list 2>&1 | grep -A1 "Name"
场景 E:发布 Release
# 1. 打 tag
cd /tmp/linghang && git tag -a "vX.Y.Z" -m "版本说明" && git push origin "vX.Y.Z"
# 2. 创建 Release
curl -s -X POST "https://api.cnb.cool/cnbmm/linghang/-/releases" \
-H "Authorization: Bearer ${CNB_TOKEN}" \
-H "Accept: application/vnd.cnb.api+json" \
-H "Content-Type: application/json" \
-d '{"tag_name":"vX.Y.Z","name":"vX.Y.Z","body":"### 变更\n- ..."}'
# 3. 上传附件(3步流程,见 TOOLS.md)
场景 F:仓库治理
> 触发:清理 Issue、关闭过期任务
批量关闭 Issue
for num in <issue_numbers>; do
curl -s -X PATCH "https://api.cnb.cool/cnbmm/linghang/-/issues/${num}" \
-H "Accept: application/vnd.cnb.api+json" \
-H "Authorization: Bearer ${CNB_TOKEN}" \
-H "Content-Type: application/json" \
-d '{"state":"closed","state_reason":"completed"}'
done
state_reason 可选值:completed / not_planned / reopened
查看 Issue 列表
curl -s "https://api.cnb.cool/cnbmm/linghang/-/issues?state=open" \
-H "Accept: application/vnd.cnb.api+json" \
-H "Authorization: Bearer ${CNB_TOKEN}"
场景 G:代码审查(本地自审)
> 当 Claude Code/Codex 不可用时的替代方案
审查要点清单
云函数安全:
- [ ] 参数校验:类型、长度、必填、边界值
- [ ] 防暴力破解:频率限制、失败计数
- [ ] 防重复提交:唯一键约束 + 事务内二次校验
- [ ] 防并发竞态:事务 + _.inc() 原子操作
- [ ] 隐私保护:不返回 _openid、手机号等敏感字段
- [ ] 异常容错:集合不存在时 try-catch 不阻塞主流程
前端:
- [ ] 云函数返回字段变更时,前端是否同步更新
- [ ] wx:key 使用 _id 而非 _openid
- [ ] 方法引用是否存在(grep 检查未定义方法)
通用:
- [ ] node -c 语法检查
- [ ] git diff 确认变更范围
关键 diff 命令
# 查看最近提交的变更统计
cd /tmp/linghang && git diff HEAD~1 --stat
# 查看特定文件差异
git diff HEAD~1 -- <file>
CNB API 踩坑速查
| 场景 | 正确用法 | 常见错误 |
|---|---|---|
| 创建 Issue | POST /{repo}/-/issues |
❌ /repos/{repo}/issues |
| PR 合并 | merge_style + commit_title(必填) |
❌ merge_method |
| 关闭 Issue | state + state_reason 必须同时传 |
❌ 只传 state |
| Issue 评论 | POST /{repo}/-/issues/{n}/comments |
— |
| PR 文件 | GET /{repo}/-/pulls/{n}/files |
❌ .diff 不返回 |
| 认证头 | Authorization: Bearer $CNB_TOKEN |
❌ token |
| 响应格式 | Accept: application/vnd.cnb.api+json |
❌ 不带会报错 |
| CNB_TOKEN | source ~/.bashrc 或手动 export |
❌ 当前 shell 可能没有 |
CloudBase 踩坑速查
| 场景 | 正确用法 | 常见错误 |
|---|---|---|
| 集合不存在 | .add() 会报错,不会自动创建 |
❌ 以为能自动创建 |
| 创建集合 | @cloudbase/node-sdk 的 createCollection() |
❌ CLI 无直接命令 |
| 创建索引 | tcb db nosql execute + createIndexes 命令 |
❌ db model push 不能创建新模型 |
| TTL 索引 | expireAfterSeconds 在 indexes 定义里 |
❌ SDK 不支持,只能 CLI |
| 云函数调用 | CLI invoke 无 openid(只测参数校验) | ❌ 以为能测完整流程 |
| tcb fn deploy | --dir 指向包含 index.js 的目录 |
❌ 指向父目录 |
环境依赖
| 依赖 | 用途 | 状态 |
|---|---|---|
tcb CLI v3.2.2 |
云函数部署、数据库操作 | ✅ 已安装 |
@cloudbase/node-sdk |
集合创建 | ✅ /tmp 已安装 |
CNB_TOKEN |
CNB API 认证 | ⚠️ 在 ~/.bashrc,需 export |
| CloudBase 登录 | tcb CLI 认证 | ✅ tcb login --key |
git |
版本管理 | ✅ |