diff --git a/docs/shopify-deployment-runbook.md b/docs/shopify-deployment-runbook.md new file mode 100644 index 0000000..b5505a5 --- /dev/null +++ b/docs/shopify-deployment-runbook.md @@ -0,0 +1,266 @@ +# Shopify 真实环境部署上线说明 + +本文档用于测试人员和上线人员把当前代码部署到真实测试环境和生产环境。仓库里的默认 `shopify.app.toml` 是模板配置,不应保留个人账号测试时生成的 `client_id`、extension `uid`、`.shopify/` 本地 link 状态或任何 `.env` 密钥。 + +## 1. 环境边界 + +- 个人验证环境只用于本地 CLI 校验,验证完成后必须移除个人账号生成的 app 绑定信息。 +- 真实测试环境和生产环境必须分别使用各自 Shopify Partner / Developer Dashboard 中的 app。 +- 不要把 `SHOPIFY_API_SECRET`、第三方 `api_secret`、Admin access token、数据库密码提交到 Git。 +- `client_id` 和 extension `uid` 虽不是密钥,但属于环境绑定信息;若项目要求保密,放在私有部署配置或 CI/CD secret 里,不提交到公开仓库。 +- `.shopify/` 是 Shopify CLI 本地状态目录,已在 `.gitignore` 中忽略;不要复制到其他环境。 + +## 2. 前置条件 + +在部署机器或 CI/CD 环境中准备: + +```bash +node -v +npm -v +shopify version +``` + +要求: + +- Node.js 20 或更高版本。 +- Shopify CLI 可用。 +- 真实测试/生产 Shopify 账号已具备创建、配置和部署 app 的权限。 +- 已准备公网 HTTPS 后端域名,例如 `https://staging-app.example.com` 和 `https://app.example.com`。 +- 已准备数据库连接、Dreame 第三方接口地址和密钥。 + +## 3. 安装和基础校验 + +```bash +cd "/path/to/dreame-shopify-app" +npm install +npx prisma generate +npx prisma validate --schema prisma/schema.prisma +npm test +npm run typecheck +npm run build +``` + +如果使用 CI/CD,建议把以上命令作为部署前质量门槛。 + +## 4. 创建或链接 Shopify app + +建议测试和生产使用命名配置,避免互相覆盖: + +```bash +shopify app config link --config staging --reset +shopify app config link --config production --reset +``` + +CLI 会提示输入 app name。建议使用: + +- 测试环境:`Dreame Activity Staging` +- 生产环境:`Dreame Activity` + +如果真实 app 已经存在,使用对应 app 的 Client ID 链接: + +```bash +shopify app config link --config staging --client-id +shopify app config link --config production --client-id +``` + +链接后检查生成的配置文件: + +- `shopify.app.staging.toml` +- `shopify.app.production.toml` +- `extensions/thank-you-activity/shopify.extension.toml` 中的 `uid` + +## 5. 修改环境配置 + +在对应 `shopify.app..toml` 中确认: + +```toml +application_url = "https://" + +[access_scopes] +scopes = "read_orders,read_metaobjects" + +[auth] +redirect_urls = [ + "https:///auth/callback", + "https:///auth/shopify/callback", + "https:///api/auth/callback" +] +``` + +`extensions/thank-you-activity/shopify.extension.toml` 保留 CLI 为真实 app 生成的 `uid`。不要使用个人账号测试时生成的 `uid`。 + +## 6. 运行官方配置校验 + +```bash +shopify app config use staging +shopify app config validate --config staging --json +shopify app info --config staging --json +``` + +生产环境: + +```bash +shopify app config use production +shopify app config validate --config production --json +shopify app info --config production --json +``` + +验收标准: + +- `shopify app config validate --json` 返回 `valid: true`。 +- `issues` 为空。 +- `app info` 中的 `client_id`、`application_url`、`redirect_urls`、`scopes` 与目标环境一致。 + +## 7. 准备运行时环境变量 + +部署后端服务时配置: + +```env +SHOPIFY_API_KEY= +SHOPIFY_API_SECRET= +SHOPIFY_APP_URL=https:// +SCOPES=read_orders,read_metaobjects +DATABASE_URL= +THIRD_PARTY_MODE=live +THIRD_PARTY_TIMEOUT_MS=5000 +LOG_RETENTION_DAYS=7 +METAOBJECT_TYPE=dreame_activity +METAOBJECT_HANDLE=dreame-activity-config +``` + +Shopify CLI 可拉取 app 相关环境变量: + +```bash +shopify app env pull --config staging --env-file .env.staging +shopify app env pull --config production --env-file .env.production +``` + +不要把 `.env.staging`、`.env.production` 提交到 Git。 + +## 8. 数据库和 Prisma + +当前本地开发默认使用 SQLite: + +```env +DATABASE_URL="file:./dev.sqlite" +``` + +真实环境必须先确认数据库方案。若使用 Postgres,需要在上线前完成 Prisma datasource 和迁移策略调整,并在目标环境执行迁移。部署前至少确认以下表已经创建: + +- `Session` +- `ActivityPushLog` +- `ActivityPushIdempotency` + +## 9. Metaobject 配置 + +在目标店铺创建 Metaobject definition: + +- Type: `dreame_activity` +- Handle: `dreame-activity-config` +- Storefront access: `NONE` + +字段: + +| Key | Type | Required | +| --- | --- | --- | +| `activity_id` | `number_integer` | yes | +| `api_app_id` | `single_line_text_field` | yes | +| `api_secret` | `single_line_text_field` | yes | +| `status_api_url` | `url` | yes | +| `push_api_url` | `url` | yes | +| `redirect_url` | `url` | yes | +| `button_text` | `json` | yes | +| `shop` | `single_line_text_field` | no | + +`api_secret` 只能由后端读取,不应暴露给 Checkout UI Extension。 + +## 10. 部署后端服务 + +Shopify CLI 的 `app deploy` 不会部署 Remix 后端服务。需要先把 web app 部署到自有托管环境,并确认: + +```bash +curl -i https:/// +curl -i -X OPTIONS https:///api/action/activity/check +``` + +期望: + +- 首页或健康页返回 200。 +- OPTIONS 返回 204,并包含 CORS headers。 +- 未带 Shopify checkout session token 的 POST 应返回 `{"success":false}`。 + +## 11. 部署 Shopify 配置和扩展 + +测试环境: + +```bash +shopify app deploy --config staging --allow-updates --message "staging deployment" +``` + +生产环境建议先创建未发布版本: + +```bash +shopify app deploy --config production --no-release --message "production candidate" +``` + +确认版本无误后,再发布生产版本: + +```bash +shopify app deploy --config production --allow-updates --message "production release" +``` + +不要在生产环境使用 `--allow-deletes`,除非已经明确确认要删除远端扩展或配置。 + +## 12. Checkout UI Extension 设置 + +在目标 app 的 Checkout UI Extension 配置中,把 setting `app_url` 设置为当前环境后端地址: + +```text +https:// +``` + +确认 extension target: + +```text +purchase.thank-you.block.render +``` + +## 13. 上线验收 + +测试订单验收: + +1. 在目标店铺完成一笔测试订单。 +2. Thank You Page 加载 extension。 +3. Extension 调用 `/api/action/activity/check`。 +4. 后端通过 Shopify checkout session token 校验。 +5. 后端读取订单、Metaobject 配置和 Dreame 状态接口。 +6. `status=true` 时只推送一次 `order_end`。 +7. 页面展示本地化按钮。 +8. 点击按钮跳转到 Metaobject 配置的 `redirect_url`。 +9. 重复刷新订单完成页不会重复 push。 +10. `ActivityPushLog` 和 `ActivityPushIdempotency` 有对应记录,且不含 `api_secret` 或签名明文。 + +## 14. 回滚 + +- Shopify app 配置或扩展异常:在 Developer Dashboard 回滚到上一个 app version。 +- 后端异常:回滚托管平台的 web app release。 +- 第三方接口异常:临时切回 `THIRD_PARTY_MODE=mock` 只能用于测试环境,不允许作为生产长期方案。 + +## 15. 交付检查清单 + +- [ ] 代码测试通过:`npm test` +- [ ] TypeScript 通过:`npm run typecheck` +- [ ] 构建通过:`npm run build` +- [ ] Shopify config validate 通过 +- [ ] 后端公网 URL 与 redirect URLs 一致 +- [ ] 数据库迁移完成 +- [ ] Metaobject definition 和 entry 已创建 +- [ ] Checkout UI Extension 已部署并配置 `app_url` +- [ ] 真实测试订单通过 +- [ ] 日志和幂等记录已核验 +- [ ] 未提交 `.env`、`.shopify/`、个人 `client_id` 或个人 extension `uid` + +参考: + +- Shopify CLI: https://shopify.dev/docs/api/shopify-cli +- App configuration: https://shopify.dev/docs/apps/tools/cli/configuration