Files
th-hotel-simple/docs/project/go-live-notes.md
2026-07-21 15:01:16 +07:00

41 KiB
Raw Blame History

TH Hotel 上线注意事项

本文给产品、研发、测试、运维和后续协作 agent 使用,目标是把上线前必须确认的事项放在同一个地方。这里记录的是当前项目专属要求,不作为可整份复制到其他项目的通用模板。

1. 当前上线范围

当前后端已经具备以下能力:

  • GET /api/health:后端健康检查和非敏感部署证明。
  • GET /api/source-messages:查询 SourceMessage Inbox 安全摘要。
  • GET /api/source-messages/{id}:查询单条 SourceMessage 安全摘要。
  • GET /api/source-messages/{id}/original受控读取邮件原文、HTML 和媒体 URL并记录访问审计。
  • GET /api/system/agentbus-probe:查看 AgentBus WebSocket 连接状态和安全计数器。
  • AgentBus WebSocket 入站链路:默认关闭,开启后把业务 frame 写入 SourceMessage Inbox如开启 M007则在入库后异步创建 SuperAgent dispatch run。
  • SuperAgent 任务结果接收接口:当前代码接收一个外部 source_message_id 下的 AI 任务结果,反查 SourceMessage Inbox 后写入 AI 过渡层、订单、任务和任务卡;支持 V3 结构化 S10/S99 和业务根基础解析,同时兼容旧 S000/S999,source_message_id 文本入口结果并创建只读特殊任务。
  • Reservation 任务详情接口:返回任务字段、队列可处理状态和 OPERA 模拟操作摘要。
  • Reservation 任务草稿保存和最终确认接口:按任务卡矩阵做第一版后端校验,确认后生成 confirmed_payload_json
  • Reservation OPERA 模拟骨架已确认任务固定生成两条模拟操作支持执行、失败重试、attempt 记录和任务审计列表。
  • SuperAgent 查询上下文接口 1、2支持 HMAC 鉴权的订单上下文查询和对象详情查询。
  • Debug EML 上传到 SuperAgent 调试链路:受控上传 .eml、转存阿里云 OSS、写入 SourceMessage Inbox、调用 SuperAgent Open API 并返回调试结果。
  • Excel 转 PDF 手动上传接口:受控上传 .xls / .xlsx,通过 LibreOffice headless 转 PDF 后上传阿里云 OSS 并返回 PDF URL。
  • Reservation Manual Invoice 后端生成接口:登录用户可通过 POST /api/reservation/invoices/manual-generations 手工生成 Proforma Invoice后端填充受控 Excel 模板、转 PDF、上传 OSS并写入生成记录和业务审计。
  • 登录权限底座:支持用户名密码登录、登出、当前用户上下文、数据库 session token、可访问酒店、权限码和可见菜单。
  • 系统管理后台 V1支持用户、角色权限、菜单、酒店和管理操作审计的受控维护接口与前端页面。

当前不要把以下能力当作已上线:

  • SourceMessage Replay 到 MessageEvent / Evidence。
  • 真实 AI 识别服务实现、Case 完整模型、Operation、Receipt。
  • 自动 ACK、task.result 或客户回复。
  • 业务前端页面展示邮件原文。
  • AgentBus SourceMessage 入库后自动分发 SuperAgent 虽然后端 V1 已实现,但默认关闭;未经测试机验收前不要在生产启用。
  • OHIP / OPERA 或其他业务系统真实写操作。
  • 普通任务切换订单接口。
  • M002 V3 字段矩阵从当前扁平结构整体迁移到 0711 P0 新结构。
  • 现有业务接口强制登录和强制权限拦截。
  • 业务审计 actor 全量迁移到当前登录用户。
  • Debug EML 上传链路不属于生产普通业务页面能力,生产默认关闭;即使已有登录权限,也不要开放给普通用户。
  • Excel 转 PDF 当前只完成手动上传后端接口和 M009 Manual Invoice 内部复用;邮件附件自动转换、持久化转换任务和 worker 尚未实现。生产启用前必须确认 LibreOffice、字体、OSS、临时目录和访问口令。

2. 上线前必须确认

上线前至少确认以下事项:

  • 当前分支、提交和部署包来源清楚,不能混入本地临时文件、真实 Secret、真实客户邮件样本或构建产物测试机 / UAT 构建包必须在本次代码提交后再打包,且能通过 GET /api/healthbuild_commit 证明当前运行提交。
  • server 后端通过完整检查:cd server && ./mvnw verify
  • 生产或 UAT 数据库已经备份,并确认 Flyway migration 只新增不修改历史脚本。
  • 所有 Secret 都通过环境变量、部署平台 Secret 或密钥管理系统注入,不写入仓库、镜像、前端环境变量或普通配置文件。
  • 生产默认不保存 AgentBus raw frame 样本。
  • AgentBus 实时链路开启前,已经确认 WebSocket URL、Token、Bot Address、外部消息幂等键和断线重连语义。
  • M007 自动分发开启前,必须先确认 SourceMessage 入库稳定、SuperAgent Open API Key 可用、SSE 断流恢复通过测试、dispatch worker 开关和回滚方式明确。
  • 源邮件只读通知卡上线前,必须确认 platform_hotel 中存在且只存在一家 ACTIVE 酒店,并且已有 SourceMessage Inbox 数据的 hotel_id 与该酒店一致。旧 S000/S999 和新结构化 S10/S99 都沿用该酒店解析约束。
  • 系统管理后台上线前,必须确认至少存在一个 ACTIVE 超级管理员账号,且该账号拥有 SYSTEM_ADMIN_CONSOLE_ACCESS 和各系统管理权限。
  • 单酒店阶段上线前,必须确认 platform_hotel 中只有一家 ACTIVE 酒店;新增酒店可以存在但应保持 DISABLED
  • M002 V4 lookup 上线前,必须确认当前 platform_hotel 唯一 ACTIVE 酒店有可用目录数据。V24 会初始化 HOTEL-TESTHOTEL-DEV,并给迁移执行时已经存在的 ACTIVE 酒店导入固定种子;如果生产真实酒店是在迁移后由 bootstrap 创建,ReservationV4CatalogBootstrapRunner 会在该酒店目录为空时补一份 FIXED_SEED_IMPORT 初始化目录。生产如不能使用固定种子作为业务事实源,必须在上线前补正式目录数据或新增导入脚本。
  • 管理后台启用后,不要继续把手工改库作为常规运营方式;用户、角色、菜单和酒店变更应通过 /api/admin/** 并写入管理审计。
  • 原文读取接口开启前,已经确认谁可以使用、在哪些场景使用、如何轮换访问 key。
  • 日志采集、错误响应和监控面板都不会展示邮件正文、HTML、附件 URL、Token、Cookie、客户姓名、邮箱、电话或支付信息。

3. 环境变量

3.0 构建与部署证明

变量 是否 Secret 上线注意事项
TH_HOTEL_BUILD_COMMIT 构建包时设置为已提交后的当前 Git commit例如 TH_HOTEL_BUILD_COMMIT=$(git rev-parse --short HEAD) ./mvnw clean package;该值会写入 Jar 内嵌 build-info/api/health 返回内嵌值;未设置时 /api/health 返回 build_commit=UNKNOWN,不能作为“已部署指定提交”的证明。不要用未提交工作区代码打包后仍标记旧 HEAD否则 build commit 只能证明旧提交,不能证明本次修复。

说明:

  • GET /api/health 会返回 runtime_markerbuild_commitbuild_timebuild_version,这些字段不包含 Secret只用于部署排查build_commit 应以构建阶段写入 Jar 的 build-info 为准,不把运行时临时环境变量或未提交工作区状态当作已部署代码证明。
  • 应用启动日志也会输出同一组 build info如果测试机接口不可访问可先看启动日志确认运行包。
  • 如果 build_commit 不是预期提交,先修部署或重新打包,不要继续改业务逻辑。

3.1 数据库

变量 是否 Secret 上线注意事项
TH_HOTEL_DB_URL 指向目标环境数据库。URL 包含 & 时要加引号。
TH_HOTEL_DB_USERNAME 使用最小权限账号,不使用个人账号。
TH_HOTEL_DB_PASSWORD 只能通过 Secret 注入,不写入仓库。
TH_HOTEL_DB_DRIVER MySQL 使用 com.mysql.cj.jdbc.Driver

3.2 登录权限

变量 是否 Secret 上线注意事项
AUTH_DEV_BOOTSTRAP_ADMIN_USERNAME / AUTH_TEST_BOOTSTRAP_ADMIN_USERNAME / AUTH_PROD_BOOTSTRAP_ADMIN_USERNAME 初始超级管理员用户名;系统已有超级管理员后不会覆盖。
AUTH_DEV_BOOTSTRAP_ADMIN_PASSWORD / AUTH_TEST_BOOTSTRAP_ADMIN_PASSWORD / AUTH_PROD_BOOTSTRAP_ADMIN_PASSWORD 初始超级管理员密码,只能通过 Secret 注入;系统已有超级管理员后不会覆盖。
AUTH_DEV_BOOTSTRAP_ADMIN_DISPLAY_NAME / AUTH_TEST_BOOTSTRAP_ADMIN_DISPLAY_NAME / AUTH_PROD_BOOTSTRAP_ADMIN_DISPLAY_NAME 初始超级管理员展示名。
AUTH_DEV_BOOTSTRAP_DEFAULT_HOTEL_ID / AUTH_TEST_BOOTSTRAP_DEFAULT_HOTEL_ID / AUTH_PROD_BOOTSTRAP_DEFAULT_HOTEL_ID 登录权限底座初始化默认酒店prod 必须配置真实酒店 ID。
AUTH_DEV_BOOTSTRAP_DEFAULT_HOTEL_NAME / AUTH_TEST_BOOTSTRAP_DEFAULT_HOTEL_NAME / AUTH_PROD_BOOTSTRAP_DEFAULT_HOTEL_NAME 默认酒店展示名称。
AUTH_DEV_BOOTSTRAP_DEFAULT_HOTEL_TIME_ZONE / AUTH_TEST_BOOTSTRAP_DEFAULT_HOTEL_TIME_ZONE / AUTH_PROD_BOOTSTRAP_DEFAULT_HOTEL_TIME_ZONE 默认酒店本地时区,默认 Asia/Bangkok
AUTH_DEV_SESSION_TTL_MINUTES / AUTH_TEST_SESSION_TTL_MINUTES / AUTH_PROD_SESSION_TTL_MINUTES 数据库 session token 有效分钟数,默认 720
AUTH_BOOTSTRAP_ADMIN_USERNAME / AUTH_BOOTSTRAP_ADMIN_PASSWORD / AUTH_SESSION_TTL_MINUTES 等通用变量 视具体变量而定 兼容兜底变量;新环境优先使用环境专属变量。

注意:

  • 数据库只保存 token_hash,不保存明文 access_token
  • access_token 只在登录成功响应中返回一次;前端只能放 sessionStorage,不能放 localStorage、URL、日志或错误上报。
  • 当前第一版只做可选 Bearer token 解析,现有 Reservation / SourceMessage 业务接口仍不强制登录。
  • /api/auth/me/api/auth/logout 需要 Authorization: Bearer <access_token>
  • 初始管理员 bootstrap 只以“启用状态超级管理员”为阻断条件;如果测试库或生产库只剩禁用超级管理员,应通过环境变量恢复一个可登录超级管理员后再排查账号运营问题。
  • 内置角色权限矩阵在启动时按代码同步,矩阵移除的旧权限关系会被清理;管理后台 V1 也不允许修改内置角色权限,临时权限应通过自定义角色承载。
  • 普通用户默认酒店由后端写入逻辑和数据库唯一索引共同保持单默认V10 migration 会在建约束前把历史重复默认清理为每个用户保留 id 最大的一条。
  • 单酒店阶段系统酒店由 platform_hotel 唯一 ACTIVE 酒店决定V12 migration 会通过唯一索引阻止第二家 ACTIVE 酒店。上线前如果已有多家 ACTIVE 酒店,必须先调整数据,否则迁移或运行时解析会失败。
  • 管理后台 V1 写操作会记录 platform_admin_audit_log;重置密码只允许临时密码出现在本次响应中,不得进入日志、审计快照或前端持久化存储。

3.3 SourceMessage

SourceMessage 原文和邮件会话完整正文已迁移到登录权限体系:

  • 前端请求必须携带 Authorization: Bearer <access_token>
  • 当前用户必须同时拥有 SOURCE_MESSAGE_READSOURCE_MESSAGE_ORIGINAL_READ
  • 后端按 SourceMessage 实际所属酒店校验酒店访问权。
  • 后端内部写入原文读取审计actor 使用当前登录用户稳定 ID。
  • SOURCE_MESSAGE_DEV_ORIGINAL_READ_ACCESS_KEYSOURCE_MESSAGE_TEST_ORIGINAL_READ_ACCESS_KEYSOURCE_MESSAGE_PROD_ORIGINAL_READ_ACCESS_KEYSOURCE_MESSAGE_ORIGINAL_READ_ACCESS_KEY 已废弃,不再作为部署必备 Secret。

3.4 AgentBus

变量 是否 Secret 上线注意事项
AGENTBUS_PROBE_ENABLED 是否启用 WebSocket 长连接。生产首次上线建议先保持 false,完成连通性窗口后再打开。
AGENTBUS_WS_URL AgentBus WebSocket 地址。
AGENTBUS_WS_TOKEN WebSocket 鉴权 Token只能通过 Secret 注入。
AGENTBUS_WS_RECONNECT_DELAY 断线重连间隔,默认 5s
AGENTBUS_CONNECT_TIMEOUT 连接超时,默认 15s
AGENTBUS_MAX_FRAME_BYTES 单个入站 frame 最大字节数,默认 1048576
AGENTBUS_CAPTURE_ENABLED 是否把业务 frame 写入 SourceMessage Inbox。
AGENTBUS_SUPERAGENT_DISPATCH_ENABLED AgentBus 新邮件入库后是否创建 SuperAgent dispatch 记录,默认关闭。
AGENTBUS_SUPERAGENT_DISPATCH_WORKER_ENABLED 是否启动异步 worker 调用 SuperAgent Open API默认关闭。
AGENTBUS_SUPERAGENT_DISPATCH_MAX_ATTEMPTS 单条 dispatch 最大尝试次数,建议默认 3
AGENTBUS_SUPERAGENT_DISPATCH_BATCH_SIZE worker 每轮领取数量,建议默认 10
AGENTBUS_SUPERAGENT_DISPATCH_LOCK_TTL worker 抢占锁有效期,建议默认 5m
AGENTBUS_SUPERAGENT_DISPATCH_INITIAL_BACKOFF 首次失败后的重试等待时间,建议默认 30s
AGENTBUS_SUPERAGENT_DISPATCH_MAX_BACKOFF 最大重试等待时间,建议默认 15m
AGENTBUS_SUPERAGENT_DISPATCH_WORKER_FIXED_DELAY_MS worker 调度间隔毫秒,建议默认 10000

注意:

  • AGENTBUS_PROBE_ENABLED=true 只表示启用连接和入站接收,不代表可以回复客户。
  • AGENTBUS_CAPTURE_ENABLED=false 时,业务 frame 会被忽略,不会写入 SourceMessage Inbox。
  • AGENTBUS_DEFAULT_HOTEL_ID 是 M005 前旧变量,当前后端不再读取;系统酒店来自 platform_hotel 唯一 ACTIVE 酒店。
  • 当前实现不发送 ACK、不发送 task.result、不自动回复客户。
  • M007 自动分发即使开启,也只能在 SourceMessage 入库后通过 dispatch / outbox 异步调用 SuperAgent不能在 AgentBus WebSocket 回调内同步等待外部返回。
  • M007 dispatch 创建使用 SourceMessage + dispatch_source 幂等;重复 RECEIVED 投递会尝试补偿缺失 outbox锁已过期的 RUNNING 记录会被 worker 重新领取。

3.5 SuperAgent HMAC

变量 是否 Secret 上线注意事项
SUPERAGENT_DEV_TASK_RESULT_HMAC_SECRET dev SuperAgent 查询接口 1、2 和任务结果通知接口共用的 HMAC secret。
SUPERAGENT_TEST_TASK_RESULT_HMAC_SECRET test SuperAgent 查询接口 1、2 和任务结果通知接口共用的 HMAC secret。
SUPERAGENT_PROD_TASK_RESULT_HMAC_SECRET prod SuperAgent 查询接口 1、2 和任务结果通知接口共用的 HMAC secret。生产不能为空只能通过 Secret 注入。
SUPERAGENT_TASK_RESULT_HMAC_SECRET 旧通用 HMAC 变量,仅作为兼容兜底;新环境优先配置环境专属变量。
SUPERAGENT_TASK_RESULT_CLOCK_SKEW_SECONDS 请求时间允许偏移,默认 300 秒。上线前确认本系统、SuperAgent 和 AgentBus 所在机器时间已通过 NTP 同步。
SUPERAGENT_TASK_RESULT_NONCE_TTL_SECONDS nonce 防重放窗口,默认 600 秒。
SUPERAGENT_TASK_RESULT_MAX_BODY_BYTES SuperAgent 入站请求体最大字节数,默认 1048576
SUPERAGENT_TEST_ALLOW_LEGACY_INTERNAL_SOURCE_MESSAGE_ID 仅用于本地 / test 旧夹具兼容内部 SourceMessage ID正式联调和生产不得开启。

注意:

  • 查询接口和任务结果通知接口使用同一套 Header、签名串、secret、timestamp 和 nonce 规则。
  • SuperAgent 侧也需要配置同一个 secret并按原始请求体计算 SHA-256。
  • 当前第一版只支持一个 HMAC secretsecret 轮换需要协调部署窗口。
  • 任务结果通知接口 JSON body 里的 source_message_id 是外部来源消息 ID对应 AgentBus source.external_message_idSuperAgent 默认不传 hotel_id,后端用系统酒店 hotel_id + provider + channel + external_message_id 反查内部 SourceMessage Inbox。
  • 当前代码的任务结果通知接口也支持 text/plainS000,source_message_idS999,source_message_id。这类请求不在 body 里带 hotel_id,后端同样使用平台酒店表唯一 ACTIVE 酒店查询 SourceMessage Inbox。
  • M002 V3 已支持结构化 S10/S99、V3 业务根基础解析、UNHANDLED_CURRENT_INTENTadapter_contract_error 最小落库:上线前必须单独验证新 JSON 入站、旧 S000/S999 兼容、隐藏技术订单、任务列表可见、订单列表不可见和只读限制。
  • 0712 P0.1 后SuperAgent runtime 必须同步使用 P0.1 Main Agent prompt / booking-desk-event skill。完整 Parent split 的父事件必须提交为 Cancel Allotment + cancel_allotment_control_block;当前新入站 Cancel Booking + linked_parent_release_after_child_split 会被后端按 adapter_contract_error 处理,不创建业务任务。旧历史 payload 只读兼容,不做批量迁移。
  • application/jsontext/plain 都必须使用原始请求体计算 SHA-256 并参与 HMAC 签名SuperAgent 侧不能签名格式化后的 JSON 或二次拼接字符串。
  • 旧 S000/S999 会创建 SOURCE_MESSAGE_ONLY 只读特殊任务和隐藏技术订单,任务列表可见,订单列表不可见,不允许编辑、确认、转换订单或执行 OPERA。V3 S10/S99 应保持同等只读和不可执行边界。
  • SuperAgent 查询上下文接口中的 source_message_idsource_event_index 第一版仅兼容接收,不参与查询和校验;不要依赖它们限制查询范围。

3.6 Debug EML / SuperAgent Open API / 阿里云 OSS

变量 是否 Secret 上线注意事项
DEBUG_EML_UPLOAD_DEV_ENABLED dev 是否启用 Debug EML 上传接口,未配置时可兜底 DEBUG_EML_UPLOAD_ENABLED
DEBUG_EML_UPLOAD_TEST_ENABLED test 是否启用 Debug EML 上传接口,默认关闭。
DEBUG_EML_UPLOAD_PROD_ENABLED prod 默认必须保持 false;未接入正式用户权限前不要开放。
DEBUG_EML_UPLOAD_DEV_ACCESS_KEY dev Debug EML 上传访问口令,未配置时可兜底 DEBUG_EML_UPLOAD_ACCESS_KEY
DEBUG_EML_UPLOAD_TEST_ACCESS_KEY test Debug EML 上传访问口令,未配置时可兜底 DEBUG_EML_UPLOAD_ACCESS_KEY
DEBUG_EML_UPLOAD_PROD_ACCESS_KEY prod Debug EML 上传访问口令;生产通常不应启用该接口。
DEBUG_EML_UPLOAD_MAX_FILE_BYTES .eml 上传大小上限,默认 10485760
DEBUG_EML_UPLOAD_SSE_HEARTBEAT_INTERVAL Debug EML 页面到后端的 SSE 心跳间隔,默认 15s;测试机如仍遇到空闲断流可调小到 10s
DEBUG_EML_UPLOAD_SSE_REQUEST_TIMEOUT Spring MVC 异步请求总超时,默认 1800s;用于保障 Debug EML 页面长流程不被后端 MVC 容器提前关闭。注意 Spring MVC async timeout 是应用级全局设置,后续如增加其他 async/SSE 接口需一起评估。
DEERFLOW_DEV_BASE_URL / DEERFLOW_TEST_BASE_URL / DEERFLOW_PROD_BASE_URL SuperAgent / DeerFlow Open API 基础地址,未配置时可兜底 DEERFLOW_BASE_URL
DEERFLOW_DEV_OPEN_API_KEY / DEERFLOW_TEST_OPEN_API_KEY / DEERFLOW_PROD_OPEN_API_KEY SuperAgent Open API Key未配置时可兜底 DEERFLOW_OPEN_API_KEY
SUPERAGENT_DEV_OPEN_API_ENABLED / SUPERAGENT_TEST_OPEN_API_ENABLED / SUPERAGENT_PROD_OPEN_API_ENABLED 是否启用真实 SuperAgent Open API 调用prod 默认关闭。
SUPERAGENT_DEBUG_EML_EXTERNAL_SUBJECT_ID Debug EML 创建 SuperAgent session 的 external subject id默认不配置时复用实时 AgentBus V4 subject。历史 V2/V3 Debug profile 只能显式配置用于旧链路排查,不得作为 V4 smoke 默认入口。
SUPERAGENT_AGENTBUS_EXTERNAL_SUBJECT_ID AgentBus 自动分发创建 SuperAgent session 的 external subject id。
SUPERAGENT_DEBUG_EML_CONNECT_TIMEOUT SuperAgent Open API 建连超时,默认 15s
SUPERAGENT_DEBUG_EML_READ_TIMEOUT 旧版 RestClient 读取超时兼容变量;当前 JDK SSE 客户端不设置整段 SSE 固定读取超时,断流恢复由 run/events 机制处理。
SUPERAGENT_OPEN_API_SSE_RECOVERY_MAX_ATTEMPTS SSE EOF 后通过 /runs/{run_id}/events 恢复的最大尝试次数,默认 5
SuperAgent Open API CSRF 不需要额外环境变量;后端每次请求自动生成临时 X-CSRF-Token,并用同值 csrf_token Cookie 做 double-submit。
ALIYUN_OSS_DEV_ENDPOINT / ALIYUN_OSS_TEST_ENDPOINT / ALIYUN_OSS_PROD_ENDPOINT 阿里云 OSS Endpoint未配置时可兜底 ALIYUN_OSS_ENDPOINT
ALIYUN_OSS_DEV_BUCKET / ALIYUN_OSS_TEST_BUCKET / ALIYUN_OSS_PROD_BUCKET 阿里云 OSS Bucket未配置时可兜底 ALIYUN_OSS_BUCKET
ALIYUN_OSS_DEV_ACCESS_KEY_ID / ALIYUN_OSS_TEST_ACCESS_KEY_ID / ALIYUN_OSS_PROD_ACCESS_KEY_ID 阿里云 OSS AccessKey ID未配置时可兜底 ALIYUN_OSS_ACCESS_KEY_ID
ALIYUN_OSS_DEV_ACCESS_KEY_SECRET / ALIYUN_OSS_TEST_ACCESS_KEY_SECRET / ALIYUN_OSS_PROD_ACCESS_KEY_SECRET 阿里云 OSS AccessKey Secret未配置时可兜底 ALIYUN_OSS_ACCESS_KEY_SECRET
ALIYUN_OSS_DEV_PUBLIC_BASE_URL / ALIYUN_OSS_TEST_PUBLIC_BASE_URL / ALIYUN_OSS_PROD_PUBLIC_BASE_URL OSS 对外访问基础 URL未配置时可兜底 ALIYUN_OSS_PUBLIC_BASE_URL
ALIYUN_OSS_DEBUG_EML_PREFIX Debug EML 上传对象路径前缀,默认 debug/eml/

注意:

  • Debug EML 上传接口会接收原始邮件、上传 OSS 并调用 SuperAgent风险和成本高于普通查询接口。
  • Debug EML 上传 key、SuperAgent Open API Key、阿里云 OSS AccessKey 都不得进入前端源码、VITE_*、镜像、普通日志或文档真实值。
  • Debug EML 写入 SourceMessage Inbox 时 provider=DEBUG_EML_UPLOAD,不能伪装为 AgentBus 来源。
  • Debug EML 写入 SourceMessage Inbox 时 external_message_id 是后端生成的 debug-eml-run-{debugRunId}-{sha256前缀};原始邮件 Message-ID 不进入发给 SuperAgent 的主 payload需要排查时看原始 EML OSS 文件、Debug run 和 SuperAgent Open API metadata。
  • Debug EML 返回的 agentbus_like_payload 是 AgentBus Outlook-like 主输入,会包含普通 reply_policy.mode=manualreply_policy.final_only=true;不再包含 schema_versionsource.provider=DEBUG_EML_UPLOADdebug_context 或旧的 Debug 专属 reply_policy.mode=debug_only。Debug 来源区分仍依赖 SourceMessage provider=DEBUG_EML_UPLOAD 和 payload 表 schemaVersion=debug-eml-upload-v1;拿到 AgentBus 真实 reply_policy.mode 枚举后需统一替换占位值。
  • Debug EML 调用 SuperAgent Open API 时metadata 中 source=DEBUG_EML_UPLOAD 只表示来源类型,model_contract=M002_V4 表示后续业务写入期望按 V4 契约处理profile 路由必须使用 external_subject_id,不要把 metadata.source 当 profile 名。
  • Debug EML 返回 html_body_sanitizedhtml_sanitize_requiredhtml_render_mode,前端展示 HTML 时应优先使用清洗字段。
  • Debug EML 当前会识别 SuperAgent Open API 返回的旧 S000/S999,source_message_id,并在 superagent_parsed_json 中返回结构化入口结果;这不是 JSON 解析失败。结构化 S10/S99 可通过任务结果通知接口入站Debug EML 页面若要直接展示完整 V3 入口结构,前端展示仍需继续补齐。
  • Debug EML 服务自身只展示 SuperAgent Open API 结果,不直接创建订单、不直接创建任务、不调用任务结果通知接口;如 SuperAgent 后续通过正式回调 / MCP 写入业务结果,必须按当前 M002 V4 契约创建 V4 order task / cards不再创建旧 workflow_reservation_task
  • AgentBus 实时收到邮件后自动推 SuperAgent 已由 M007 后端 V1 实现,不能把 Debug EML 链路等同于生产实时自动处理链路。
  • Debug EML 和 AgentBus 自动分发复用同一个 SuperAgent Open API SSE 稳定客户端;上线前必须验证 run.completed + end + final answer 严格成功条件和 EOF 后 /events 恢复。
  • 当前共享 Open API client 会自动携带临时 CSRF double-submit header / cookie如果测试机仍返回 CSRF token missing,优先检查部署包版本和反向代理是否转发 X-CSRF-TokenCookie

3.7 Excel 转 PDF / LibreOffice

变量 是否 Secret 上线注意事项
DOCUMENT_CONVERSION_DEV_ENABLED / DOCUMENT_CONVERSION_TEST_ENABLED / DOCUMENT_CONVERSION_PROD_ENABLED 是否启用 Excel 转 PDF 手动上传接口prod 默认必须保持 false,确认运行环境后再开启。
DOCUMENT_CONVERSION_DEV_ACCESS_KEY / DOCUMENT_CONVERSION_TEST_ACCESS_KEY / DOCUMENT_CONVERSION_PROD_ACCESS_KEY 文件转换访问口令;未配置时可兜底 DOCUMENT_CONVERSION_ACCESS_KEY。不得进入前端源码、镜像、普通日志或文档真实值。
DOCUMENT_CONVERSION_SOFFICE_PATH / DOCUMENT_CONVERSION_*_SOFFICE_PATH soffice 可执行文件路径,默认 soffice。测试机和生产机路径可能不同。
DOCUMENT_CONVERSION_TEMP_DIR / DOCUMENT_CONVERSION_*_TEMP_DIR 文件转换临时目录。后端运行用户必须有读写权限,目录应有系统清理策略。
DOCUMENT_CONVERSION_MAX_FILE_BYTES / DOCUMENT_CONVERSION_*_MAX_FILE_BYTES 单个 Excel 文件大小上限,默认 20971520
DOCUMENT_CONVERSION_TIMEOUT_SECONDS / DOCUMENT_CONVERSION_*_TIMEOUT_SECONDS 单次 LibreOffice 转换超时秒数,默认 60
DOCUMENT_CONVERSION_MAX_CONCURRENT / DOCUMENT_CONVERSION_*_MAX_CONCURRENT 最大并发转换数,默认 2。不要盲目调大,避免 LibreOffice 进程拖垮后端。
DOCUMENT_CONVERSION_OUTPUT_OSS_PREFIX / DOCUMENT_CONVERSION_*_OUTPUT_OSS_PREFIX PDF 输出 OSS 前缀,默认 document-conversions/excel-to-pdf/
DOCUMENT_CONVERSION_WORKER_ENABLED / DOCUMENT_CONVERSION_*_WORKER_ENABLED 自动转换 worker 预留开关CP2 不使用,默认关闭。
DOCUMENT_CONVERSION_MULTIPART_MAX_FILE_BYTES / DOCUMENT_CONVERSION_MULTIPART_MAX_REQUEST_BYTES Spring multipart 框架上限;默认分别为 25165824 / 29360128,应高于业务 MAX_FILE_BYTES,否则请求会在进入 Controller 前被框架拦截。

注意:

  • 服务器必须安装 LibreOffice / LibreOffice Calc并确认后端运行用户可以执行 soffice
  • 服务器必须安装中文、英文、泰文等业务字体;缺少字体会导致 PDF 乱码、缺字或分页变化。
  • 每次转换会创建独立临时目录和 LibreOffice profile正常结束、失败或超时后后端会清理但仍建议运维配置临时目录兜底清理。
  • 当前接口路径为 POST /api/system/document-conversions/excel-to-pdfHeader 为 X-TH-Hotel-Document-Conversion-Key
  • 当前接口只支持 .xls / .xlsx,不支持 .xlsm;后端会校验扩展名和文件头,改后缀的非 Excel 文件会返回受控错误。
  • PDF 上传到阿里云 OSS返回 pdf_urlobject_keypdf_file_namepdf_size_bytesduration_millis
  • CP2 不落库,不提供转换历史查询;如果需要自动处理邮件附件,应先进入 M008 后续持久化任务和 worker checkpoint。
  • M009 Manual Invoice 不调用上述调试接口,也不使用 X-TH-Hotel-Document-Conversion-Key;它通过登录 Bearer token、RESERVATION_INVOICE_GENERATE 权限和后端内部转换 Adapter 生成 PDF。
  • M009 Manual Invoice 当前模板资源为 server/src/main/resources/templates/reservation-invoice/proforma-invoice-v1.xlsx,部署包必须包含该资源;模板为 A4 纵向单页版式,缺少字体或 LibreOffice 版本差异仍可能影响最终分页,测试环境上线后需用真实浏览器打开生成 PDF 复核。
  • M009 Manual Invoice 会写入 workflow_reservation_invoice_generation,上线前需确认 Flyway 已执行到 V22。
  • M009 Manual Invoice 失败记录也可能保留已上传成功的 Excel / PDF object key排查或清理 OSS 生成物时应以生成记录为主,不只看 SUCCEEDED 状态。

4. 数据库上线注意事项

当前 SourceMessage 相关 migration

  • server/src/main/resources/db/migration/V1__create_source_message_inbox.sql
  • server/src/main/resources/db/migration/V2__create_source_message_original_access_audit.sql

当前 M002 订单任务相关 migration

  • server/src/main/resources/db/migration/V3__create_reservation_ai_task_workflow.sql
  • server/src/main/resources/db/migration/V4__harden_reservation_task_queue_and_manual_conversion.sql
  • server/src/main/resources/db/migration/V5__add_reservation_task_draft_and_confirmation.sql
  • server/src/main/resources/db/migration/V6__create_reservation_opera_simulation_tables.sql
  • server/src/main/resources/db/migration/V11__add_reservation_order_visibility.sql
  • server/src/main/resources/db/migration/V16__add_m002_v3_ai_route_fields.sql
  • server/src/main/resources/db/migration/V21__add_reservation_order_latest_activity.sql
  • server/src/main/resources/db/migration/V23__create_reservation_v4_order_task_card.sql
  • server/src/main/resources/db/migration/V24__create_reservation_catalog_tables.sql

当前 M004 Debug EML 相关 migration

  • server/src/main/resources/db/migration/V7__create_debug_eml_superagent_run.sql

当前 SourceMessage duplicate 诊断相关 migration

  • server/src/main/resources/db/migration/V8__create_source_message_payload_duplicate.sql

当前 M007 AgentBus 自动分发 SuperAgent 相关 migration

  • server/src/main/resources/db/migration/V20__create_superagent_dispatch_run.sql

当前 M009 Manual Invoice 相关 migration

  • server/src/main/resources/db/migration/V22__create_reservation_invoice_generation.sql

当前 M003 登录权限相关 migration

  • server/src/main/resources/db/migration/V9__create_identity_access_hotel_menu.sql
  • server/src/main/resources/db/migration/V10__enforce_single_default_user_hotel.sql
  • server/src/main/resources/db/migration/V12__enforce_single_active_platform_hotel.sql

当前 M006 系统管理相关 migration

  • server/src/main/resources/db/migration/V15__create_platform_admin_audit_log.sql

上线前确认:

  • 目标数据库为空库或 Flyway history 与当前代码一致。
  • 如果某个环境已经在缺少 V10 的临时提交上执行过 V11 / V12不能直接用默认 Flyway 策略补跑 V10应先重建测试库或按运维窗口明确 out-of-order / repair 策略。
  • V21 会为 workflow_reservation_order 增加 latest_activity_at,并按订单更新时间和历史任务最新来源 / 创建时间回填一次;上线后订单列表依赖该字段排序,不再在列表查询时聚合全量任务。发布后需要确认 Flyway 已执行到 V21且订单列表能按最新业务活动倒序返回。
  • V24 会新增 workflow_reservation_catalog_accountworkflow_reservation_catalog_code,并初始化 HOTEL-TESTHOTEL-DEV 以及迁移执行时已有 ACTIVE 酒店的 Account、Market、Source、Room Type、Rate Code 种子目录。启动后 ReservationV4CatalogBootstrapRunner 会补齐迁移后由平台 bootstrap 创建且目录为空的 ACTIVE 酒店。发布后需要确认 Flyway 已执行到 V24且当前酒店 lookup 能返回目录项;真实 PMS 同步、目录管理后台和 workflow_reservation_catalog_sync_run 仍未实现。
  • V22 会新增 workflow_reservation_invoice_generation,用于记录 Manual Invoice 生成状态、Excel / PDF OSS 对象、金额摘要和安全错误摘要;发布后需要确认 RESERVATION_INVOICE_GENERATE 权限已由启动同步写入平台权限表,预订操作员或目标角色已拥有该权限。
  • MySQL 版本满足项目要求,默认使用 MySQL 8.0+。
  • migration 在 UAT 或测试库已经跑过。
  • 表和字段中文注释能正常创建。
  • 数据库业务时间点按 UTC 写入,接口层返回带 Z 的 ISO 8601 UTC 时间,例如 2026-07-08T03:00:00Z
  • MySQL JDBC URL 建议明确 serverTimezone=UTC;部署容器和 JVM 也应使用 UTC或至少确认应用代码所有入库时间均通过 UTC 时钟生成。
  • AgentBus 邮件来源时间、SuperAgent HMAC timestamp、本系统 created_at / updated_at 等时间点统一按 UTC 理解SourceMessage received_at 优先保存 AgentBus payload received_at,缺失时回退本系统接收时间,前端展示时再按用户或酒店时区格式化。
  • 入住日期、离店日期、酒店营业日属于酒店本地业务日期,不应因为 UTC 换算而自动前后偏移。
  • 详细时间设计、页面展示和按酒店本地日期筛选规则见 docs/project/backend-time-design.md
  • 执行 V4 前,如果目标库已有 M002 试运行数据,必须先检查 ACTIVE 订单业务号重复和同订单任务队列序号重复。
  • 执行 V5 / V6 前,如果目标库已有 M002 试运行数据,必须确认任务草稿、确认 payload 和 OPERA 模拟操作表允许从空数据开始补齐;不要手工伪造已确认 payload 或 attempt 历史。
  • 执行 V16 前,确认 workflow_reservation_ai_transition.result_typeworkflow_reservation_task.result_type 扩容到 VARCHAR(64) 不会被历史手工约束阻断V16 会新增 route_codesystem_process_categoryadapter_error_codeadapter_error_message 和对应查询索引。
  • 执行 V11 前,如果目标库已有手工造数或历史隐藏订单方案,必须确认是否需要回填 order_visibility;默认值 VISIBLE 会让历史订单继续出现在订单列表。

V4 前置检查 SQL

SELECT hotel_id, order_key_type, order_business_key, COUNT(*) AS duplicate_count
FROM workflow_reservation_order
WHERE order_status = 'ACTIVE'
  AND order_key_type IN ('GROUP_CODE', 'CONFIRMATION_NUMBER')
  AND order_business_key IS NOT NULL
GROUP BY hotel_id, order_key_type, order_business_key
HAVING COUNT(*) > 1;

SELECT hotel_id, order_id, queue_participation, execution_order, COUNT(*) AS duplicate_count
FROM workflow_reservation_task
GROUP BY hotel_id, order_id, queue_participation, execution_order
HAVING COUNT(*) > 1;

处理要求:

  • 如果任一 SQL 返回记录,不要继续执行 V4。
  • ACTIVE 订单业务号重复时,先由业务确认保留哪一条 ACTIVE其他订单应转为 LOGIC_DELETEDENDED 或完成任务迁移后再上线。
  • 同订单任务队列序号重复时,先按来源顺序和审计证据重新分配 execution_order,确认前置任务关系正确后再上线。
  • 不要为了让唯一索引创建成功而随意删除订单、任务或 AI 原始记录。
  • OPERA 模拟操作失败只代表单条模拟操作失败,当前任务不会因此自动进入 FAILED;上线验证时不能把失败操作当作真实 OPERA 失败处理。

禁止事项:

  • 禁止直接修改已发布 migration。
  • 禁止手工改生产表结构后再让代码“凑合跑”。
  • 禁止把真实邮件正文、附件 URL 或客户数据做成测试种子数据提交。

5. 安全与日志

上线前必须确认普通日志、错误响应和状态接口不会输出:

  • Authorization、Cookie、CSRF Token。
  • Provider API Key、AgentBus Token、数据库密码。
  • 邮件正文、HTML、附件 URL、原始 payload。
  • 客户姓名、电话、证件号;发件人展示字段因业务识别需要允许返回完整邮箱或名称,但不得写入普通日志、错误响应或调试状态接口。
  • 支付信息。

SourceMessage 普通列表和普通详情只能返回安全摘要:

  • 可以返回SourceMessage ID、酒店 ID、provider、channel、外部邮件 ID、外部邮件链 ID、状态、时间、发件人展示值、主题摘要、安全短摘要。
  • 不应返回完整正文、HTML、附件 URL、原始 payload。

原文读取接口只允许在明确授权场景下使用:

GET /api/source-messages/{id}/original
Header: Authorization: Bearer <access_token>
Required permission: SOURCE_MESSAGE_READ + SOURCE_MESSAGE_ORIGINAL_READ

前端展示 htmlBody 前必须 sanitize。后端返回 htmlSanitizeRequired=true 是提醒前端不要直接信任 HTML。

6. AgentBus 上线注意事项

AgentBus 是消息入口,不是 AI Provider。生产实时链路必须保持以下边界

  • WebSocket 回调内只做 SourceMessage Inbox 入库和轻量 dispatch 标记。
  • 如启用 M007只能在入库后通过受控异步 dispatch / outbox 调用 SuperAgent。
  • 不创建 MessageEvent、Evidence、Case、Task、Operation、Receipt。
  • 不调用 OHIP、ERP、支付系统等业务写接口。
  • 不自动发送 ACK、task.result 或客户回复。
  • 不在普通日志里输出 raw frame、邮件正文、HTML 或附件 URL。

建议上线顺序:

  1. 保持 AGENTBUS_PROBE_ENABLED=false,先部署服务并确认健康检查。
  2. 确认数据库 migration 和 SourceMessage 查询接口正常。
  3. 配置 AgentBus URL 和 Token但仍保持连接关闭。
  4. 在约定观察窗口打开 AGENTBUS_PROBE_ENABLED=true
  5. 观察 /api/system/agentbus-probe,确认连接状态、sessionReady、计数器和最近错误代码。
  6. 用合成测试邮件验证 SourceMessage Inbox 是否写入。
  7. 确认日志和监控没有泄露 raw frame、正文或附件 URL。
  8. 如需开启 M007 自动分发,先保持 worker 关闭并确认 dispatch run 能正确创建,再打开 worker 处理少量合成邮件。
  9. 验证 SuperAgent dispatch 成功不会直接创建订单或任务,业务任务仍只来自 SuperAgent 后续任务结果通知或 MCP 提交。

如果出现异常:

  • 先关闭 AGENTBUS_PROBE_ENABLED,停止接收入站 frame。
  • 如果只是想暂停入库但保留连接,可关闭 AGENTBUS_CAPTURE_ENABLED
  • 如果只想暂停 M007 自动分发,优先关闭 AGENTBUS_SUPERAGENT_DISPATCH_WORKER_ENABLED;如需停止新建 dispatch再关闭 AGENTBUS_SUPERAGENT_DISPATCH_ENABLED
  • 保留状态接口、应用日志和数据库记录用于排查,但不要导出真实邮件正文或附件 URL。

7. 上线后冒烟验证

后端服务启动后,按顺序验证:

GET /api/health

期望:

  • HTTP 200。
  • status = UP
  • runtime_marker = m002_v4_review_pointer_deployment_proof_v1
  • build_commit 为本次预期部署提交;如果是 UNKNOWN 或旧提交,先修部署包。
GET /api/system/agentbus-probe

期望:

  • HTTP 200。
  • 返回 enabledconnectedsessionReady、计数器和最近错误代码。
  • 响应中不包含 Token、Authorization、raw frame、payload 或邮件正文。
GET /api/source-messages?pageNum=1&pageSize=20

期望:

  • HTTP 200。
  • 只返回安全摘要。
  • 不包含正文、HTML、附件 URL 或原始 payload。
GET /api/source-messages/{id}

期望:

  • HTTP 200 或 404。
  • 如果存在记录,只返回安全摘要。
GET /api/source-messages/{id}/original

期望:

  • 未携带正确访问 key 时返回 403。
  • 携带正确访问 key、调用方和访问场景时返回原文内容并写入 platform_source_message_original_access_audit

8. 监控建议

至少监控:

  • 应用进程是否存活。
  • GET /api/health 是否正常。
  • AgentBus connectedsessionReady 状态。
  • AgentBus failedFrameCountrejectedFrameCount 是否持续增长。
  • SourceMessage Inbox 每小时入库数量是否异常突增或归零。
  • FAILED SourceMessage 数量和安全错误摘要。
  • 原文读取审计数量是否异常。
  • 数据库连接池、慢 SQL、磁盘空间和 migration 状态。

告警信息不得包含 Secret、正文、HTML、附件 URL 或客户个人信息。

9. 回滚与降级

优先降级开关:

AGENTBUS_PROBE_ENABLED=false
AGENTBUS_CAPTURE_ENABLED=false

说明:

  • 关闭 AGENTBUS_PROBE_ENABLED 可以停止 WebSocket 入站连接。
  • 关闭 AGENTBUS_CAPTURE_ENABLED 可以保留连接但暂停写入 Inbox。
  • 如需临时关闭前端邮件原文 / 会话完整正文读取,应从相关角色移除 SOURCE_MESSAGE_ORIGINAL_READSOURCE_MESSAGE_READ,或禁用对应用户入口;旧原文读取 key 已废弃,不能作为关闭开关。

数据库回滚注意:

  • 已执行的 migration 不应直接删除或手工回滚。
  • 如果新版本已写入 SourceMessage 数据,回滚应用前要确认旧版本是否能兼容新表存在。
  • 需要修复表结构时,应新增 migration而不是修改已发布 migration。

10. 上线责任确认

上线前需要有人明确确认:

  • 部署版本:确认本次上线的分支、提交和构建产物。
  • 数据库:确认 migration、备份和连接信息。
  • Secret确认所有密钥由部署平台注入。
  • AgentBus确认是否开启 WebSocket是否允许捕获入库。
  • 安全:确认日志、错误响应、状态接口和监控面板没有敏感数据。
  • 业务:确认当前上线范围不包含 replay、AI、Case、Task、客户回复或 OHIP 写操作。

只要上述任何一项没人确认,就不要打开生产实时入口。