# 本地开发工作流(暂停部署) **生效时间**: 2026-06-22 起 **原因**: 进入密集调试修改阶段,所有改动只在本地验证,等批次完成后再统一发到生产 --- ## 🚦 红灯规则 | 行为 | 是否允许 | |------|----------| | 修改本地代码(apps/api、apps/web、scripts 等)| ✅ | | 修改 prisma schema(本地 dev.db)| ✅ | | nest watch 热重载 | ✅ 自动 | | next dev 热重载 | ✅ 自动 | | **rsync 代码到生产** | ❌ 暂停 | | **重启生产 PM2 进程** | ❌ 暂停 | | **生产 prisma db push** | ❌ 暂停 | | **生产数据库迁移 / SQL** | ❌ 暂停 | | **生产证书 / Nginx 修改** | ❌ 暂停 | | **生产服务器手工操作** | ❌ 暂停(仅读查询例外)| 例外:本地只读查询到生产是允许的(如 `ssh ... ls/cat/tail/grep/curl/sshpass` 只读命令) --- ## ✅ 本地修改流程 1. 修改代码 → nest watch / next dev 自动重载 2. 用本地 DB 验证:`http://localhost:3001` + `localhost:4000/api` 3. 类型检查(必要时): ```bash cd /Users/zou/Documents/02-平台开发/平台助手/apps/api npx tsc --noEmit cd /Users/zou/Documents/02-平台开发/平台助手/apps/web npx tsc --noEmit ``` 4. 在浏览器测试 UI 效果 --- ## 📦 批次打包流程(等所有调试完成后) 打包前确认清单: - [ ] 所有本地修改的源代码已稳定运行 ≥24 小时 - [ ] 本地数据库 schema 与 prisma/schema.prisma 一致 - [ ] 类型检查 0 错误 - [ ] 关键功能回归测试通过 打包命令: ```bash # 1. 本地构建 cd /Users/zou/Documents/02-平台开发/平台助手 npm run build -w apps/api npm run build -w apps/web # 如果失败,先绕过 next build lockfile patch # 2. rsync 源码到生产(不传 node_modules、.next) rsync -avz --delete \ --exclude='node_modules' \ --exclude='.next/cache' \ --exclude='prisma/dev.db*' \ --exclude='public/uploads' \ --rsh="sshpass -e ssh -o StrictHostKeyChecking=no" \ ./ ubuntu@172.81.241.109:/opt/pingtai/ # 3. 生产环境:重新构建 + 同步 DB schema sshpass -p 'Jubianshuzi@2026' ssh ubuntu@172.81.241.109 " cd /opt/pingtai/apps/api npm run build npx prisma db push # 注意:会修改生产 DB schema cd /opt/pingtai npm install # 如果有依赖变更 pm2 restart pingtai-api pingtai-web --update-env " # 4. 验证 curl -s -o /dev/null -w 'API: %{http_code}\n' http://172.81.241.109:4000/api/health curl -s -o /dev/null -w 'Web: %{http_code}\n' https://direv.cloud ``` --- ## 📝 调试变更追踪 每次修改请记录到这里,方便后续打包时知道改了哪些。 | 日期 | 修改内容 | 文件 | |------|---------|------| | 2026-06-22 | 加 publishTime 字段;publish 默认值改"未发布" | apps/api/prisma/schema.prisma | | 2026-06-22 | crawler.upsert 写入 publishTime | apps/api/src/crawler/crawler.service.ts | | 2026-06-22 | 表格加"发布时间"列;发布状态列字体统一 | apps/web/src/components/InquiryPage.tsx | | 2026-06-22 | **MCP 集成密钥轮换**:本地数据库写入新 appSecret,集成状态 error → active。密钥轮换脚本 `scripts/rotate-mcp-key.sh`(拿到新密钥后 `NEW_APP_ID=xxx NEW_APP_SECRET=yyy bash scripts/rotate-mcp-key.sh` 一键执行)| scripts/rotate-mcp-key.sh(新文件)| | 2026-06-22 | **修复 publish_rfq 返回 rfqId=null bug**:MCP tool 返回结构是 `{code, msg, data: {orderId, rfqId, status}}`,B2B 业务对象嵌在外层 `data.data`。原代码 `data.rfqId` 拿到 undefined。修复为 `payload = data.data \|\| data; payload.rfqId \|\| ...`。**修复后端到端验证通过**:远程订单号 `RFQ20260622161118531`、rfqId `2068970068244123649`、direvUrl 带真 rfqId | apps/api/src/lead/lead.service.ts | | 2026-06-22 | **MCP 适配新 schema(移除了 category_id/unit/deadline)**:原 publishToDirev 传 `category_id:1 / unit:件 / deadline` 但 MCP server 重启后 schema 简化了。改为只传 schema 接受的字段:`title / description / qty / attachments`。attachments 优先用 `lead.attachments`(JSON 字符串),fallback 到 `lead.detailUrl` | apps/api/src/lead/lead.service.ts | | 2026-06-22 | **Lead 模型加 4 个新字段**:quantity(整数)、unit(单位)、regionDetail(详细收货地址)、attachments(JSON 数组字符串)。db push 已同步本地 dev.db | apps/api/prisma/schema.prisma | | 2026-06-22 | **前端 Lead 类型扩展**:InquiryPage / LeadDetailPage 的 Lead 接口加 regionDetail / quantity / unit / attachments 字段;表格加"数量"列(colSpan 从 10 改 11);详情页加"询价数量/收货地址/附件"三栏;抽屉加"询价数量/收货地址/公告日期";附件字段支持 JSON 数组渲染多链接 | apps/web/src/components/InquiryPage.tsx, apps/web/src/components/LeadDetailPage.tsx | | 2026-06-22 | **devbox F002 升级需求文档**:`docs/devbox-requirements/MCP-publish_rfq-字段升级需求.md`。需求:在 devbox 的 `publish_rfq` zod schema + `InquiryServiceImpl.publish()` 补 deadline/deliveryDate/shippingAddress/contactName/contactPhone/freightFlag/paymentMethod/invoiceType/procurementType/inquiryParty 共 10 个商务字段。**当前 devbox 还没改,平台助手先按现有 schema 实现** | docs/devbox-requirements/MCP-publish_rfq-字段升级需求.md(新文件)| | 2026-06-22 | **devbox F002 升级完成 + 平台助手二次适配**:devbox 已把 publish_rfq schema 升级(W29.7, 补 11 商务字段),Java 后端 `InquiryServiceImpl.publish()` 也补全字段映射。平台助手这边把新参数加进 `publishToDirev` 的 `publishArgs`:deadline(直接传 Lead.deadline YYYY-MM-DD)、deliveryDate(自动 deadline+30 天)、shippingAddress(优先 Lead.regionDetail, fallback region)、contactName/Phone(从 Lead.contact/phone)、inquiryParty("郑州巨变")、freightFlag("含运费")、procurementType("定量采购")、invoiceType("增值税专票")、paymentMethod("货到付款") | apps/api/src/lead/lead.service.ts | | 2026-06-22 | **devbox 升级导致密钥重置**:`app_9dd07cb4e0e24fccbecd` 的 appSecret 被重置(MySQL 里 hash 前缀从 `$2a$10$iR3Rl` 变 `$2a$10$m3hRN`)。用 `POST /sys/openapi/app/reset-secret/{id}` 端点自助重置拿到新密钥 `d02dc00c6fbe4a34a5bf013134146c3f2759148c61a341d2`,本地集成密钥已轮换 | scripts/rotate-mcp-key.sh | | 2026-06-22 | **端到端验证新字段入库**:rfqId=2068990783236042754,orderId=RFQ20260622173337369,MySQL 里 11 个商务字段都正确填充(purchase_quantity=50, inquiry_valid_date=2026-08-31, deliver_date=2026-09-30, shipping_address, contact_name="郑钊", contact_phone=15532027557, inquiry_party="郑州巨变", freight_flag=1, invoice_type=2, procurement_type=1, urls)。**唯一未入库:`payment_method` 字段为 NULL**,原因:devbox 按企业 ID + 名称查 `tb_supplier_pay_type` 表,没找到 "货到付款" 这个字典项就会抛错但不影响 publish 成功(注意日志可能有 `付款方式查询失败: ...` 警告)| — | | 2026-06-23 | **密钥再次重置 + 司库系统重发**:devbox 傍晚又把密钥重置(hash 前缀 `m3hRN → diPRva`,update_date 18:18:22)。用 `reset-secret` 端点再次自助重置拿到新密钥 `fcb53684845648e2a7fc1082f5245180cfa4eea1f5404176`。**用户反馈现象**:选了 `司库系统升级完善项目` 点一键发布,本地显示"发布成功"但 B2B 后台查不到。**根因**:MCP 鉴权失败后代码降级为本地假订单号(X+时间戳),让用户误以为成功。 | scripts/rotate-mcp-key.sh | | 2026-06-23 | **彻底移除降级本地模式 + MCP 失败弹警告**:(1) 后端 `publishToDirev` 不再写本地假 `inquiryNo=X...`;MCP 鉴权/调用失败时抛 `ServiceUnavailableException` 返回 503 + 详细错误信息;Lead 状态完全不动。(2) 前端 `doPublish` 收集每条失败原因(fetch `res.json().message`),失败时弹新 Modal(红框 + 错误列表 + 「去 MCP 配置」/「我知道了」按钮)。**端到端验证**:把密钥改成 `invalid_test_key_for_qa` → publish 返回 HTTP 503 + JSON 含 `appSecret 校验失败` + 引导文案;Lead 表 publish/inquiryNo/followLogs 全部不变。 | apps/api/src/lead/lead.service.ts, apps/web/src/components/InquiryPage.tsx | | 2026-06-25 | **生产部署(commit 49f9224)**:本地全量构建后 rsync 到 `/opt/pingtai/`;生产跑 `npx prisma db push + generate`;生产 `next build`(有 lockfile 警告但构建成功);`pm2 restart pingtai-api pingtai-web --update-env`。**手工补齐生产 db 缺列**(prisma db push 路径错):真生产 db 是 `/data/pingtai/dev.db`(不是 `/opt/pingtai/apps/api/prisma/dev.db`),缺 `Lead.regionDetail/quantity/unit/attachments/notes/notesExtractedAt/notesSource` + `Integration.companyUserId` 共 8 列。手工 `ALTER TABLE` 全部补齐,95 条 Lead 数据完整保留。**生产验证**:API + Web online 13m+;lead 95 条、product 75 条、crawler 3 条、inquiry 3 条都正常返回。**新建 Integration 配置**(生产 db 之前为空):在生产创建 MCP 集成 id=751ab09c-e6ab-4c97-bd2d-2c317df32893,appId=app_9dd07cb4e0e24fccbecd。**遗留问题**:生产服务器 172.81.241.109 → devbox 100.111.84.16:3002 网络不通(ping 100% 丢包,curl 5s 超时)。MCP publish_rfq 端到端在生产跑不通(生产 connect 集成返回 `fetch failed`),publish 接口在生产会返回 503 + "未配置 B2B 集成"或"网络不通",这是网络层面的限制不是代码问题。 | apps/api/src/lead/lead.service.ts, docs/本地开发工作流.md | | 2026-06-25 | **主域名切换:弃用 zoupeng.cloud,改用 direv.cloud**。**根因**:`zoupeng.cloud` DNS 解析到 `222.137.3.123`(旧/无效 IP,ping 通但 443 不通),而 `direv.cloud` DNS 正确解析到 `172.81.241.109`(实际生产服务器 IP)。**改动**:文档第 83 行 `https://zoupeng.cloud` → `https://direv.cloud`,rsync 同步到生产。**长期建议**:去腾讯云 DNSPod 控制台把 `zoupeng.cloud` 的 A 记录改到 `172.81.241.109`;生产 nginx 加 `zoupeng.cloud` 的 server block(同 direv.cloud),否则 `zoupeng.cloud` 永远打不开。AGENTS.md 里"主 `https://zoupeng.cloud`、备 `https://direv.cloud`"是错的,应反过来。 | docs/本地开发工作流.md | | 2026-06-22 | **devbox F002 升级完成 + 平台助手二次适配**:devbox 已把 publish_rfq schema 升级(W29.7, 补 11 商务字段),Java 后端 `InquiryServiceImpl.publish()` 也补全字段映射。平台助手这边把新参数加进 `publishToDirev` 的 `publishArgs`:deadline(直接传 Lead.deadline YYYY-MM-DD)、deliveryDate(自动 deadline+30 天)、shippingAddress(优先 Lead.regionDetail, fallback region)、contactName/Phone(从 Lead.contact/phone)、inquiryParty("郑州巨变")、freightFlag("含运费")、procurementType("定量采购")、invoiceType("增值税专票")、paymentMethod("货到付款") | apps/api/src/lead/lead.service.ts | | 2026-06-22 | **devbox 升级导致密钥重置**:`app_9dd07cb4e0e24fccbecd` 的 appSecret 被重置(MySQL 里 hash 前缀从 `$2a$10$iR3Rl` 变 `$2a$10$m3hRN`)。用 `POST /sys/openapi/app/reset-secret/{id}` 端点自助重置拿到新密钥 `d02dc00c6fbe4a34a5bf013134146c3f2759148c61a341d2`,本地集成密钥已轮换 | scripts/rotate-mcp-key.sh | | 2026-06-22 | **端到端验证新字段入库**:rfqId=2068990783236042754,orderId=RFQ20260622173337369,MySQL 里 11 个商务字段都正确填充(purchase_quantity=50, inquiry_valid_date=2026-08-31, deliver_date=2026-09-30, shipping_address, contact_name="郑钊", contact_phone=15532027557, inquiry_party="郑州巨变", freight_flag=1, invoice_type=2, procurement_type=1, urls)。**唯一未入库:`payment_method` 字段为 NULL**,原因:devbox 按企业 ID + 名称查 `tb_supplier_pay_type` 表,没找到 "货到付款" 这个字典项就会抛错但不影响 publish 成功(注意日志可能有 `付款方式查询失败: ...` 警告)| — | --- ## ⚠️ 常见陷阱 1. **数据库结构**:本地 dev.db 和生产 dev.db 是分开的,本地任何 schema 变更不会自动同步到生产 2. **依赖升级**:如果加了新依赖(如 npm install xxx),生产需要单独跑 npm install 3. **next build**:生产 next build lockfile patch 经常失败,使用 dev mode 跑 web 即可,不强制 build 4. **Prisma generate**:每次改 schema 都要跑 `npx prisma generate`,否则 API 拿不到新字段 --- ## 🔍 当前本地服务状态 ```bash # Web: http://localhost:3001 (PID 66990, next dev) # API: http://localhost:4000/api (PID 17721 + 20451, nest watch) # DB: apps/api/prisma/dev.db (本地 SQLite) ``` **账号**: admin / admin123