feat: sync latest ARR implementation
This commit is contained in:
@@ -1,45 +1,22 @@
|
||||
# Copy to deploy/.env.production, fill every required value, then chmod 600.
|
||||
# Copy to deploy/.env.production, fill required values, then chmod 600.
|
||||
# Never commit deploy/.env.production.
|
||||
|
||||
ARR_IMAGE_NAME=wyndham-arr
|
||||
ARR_IMAGE_NAME=wyndham-arr2
|
||||
ARR_IMAGE_TAG=latest
|
||||
|
||||
# Two DNS records pointing to this server. Use hostnames only, without scheme/path.
|
||||
WEB_PUBLIC_HOST=arr.example.com
|
||||
MCP_PUBLIC_HOST=mcp.example.com
|
||||
ACME_EMAIL=ops@example.com
|
||||
ARR_WEB_USERNAME=arr-operator
|
||||
ARR_WEB_PASSWORD=replace_with_a_long_random_secret
|
||||
|
||||
# Caddy bcrypt hash. Generate interactively with `caddy hash-password`.
|
||||
WEB_BASIC_AUTH_USER=arrtester
|
||||
WEB_BASIC_AUTH_PASSWORD_HASH=replace_with_caddy_bcrypt_hash
|
||||
|
||||
# MCP transport authentication. Use an independent random 32-256 byte ASCII token.
|
||||
ARR_MCP_BEARER_TOKEN=replace_with_independent_random_token
|
||||
ARR_MCP_MAX_CONCURRENCY=2
|
||||
|
||||
# Must target the isolated PostgreSQL 15+ database named booking_test.
|
||||
ARR_DATABASE_URL=postgresql://arr_app:replace_me@db.example.internal:5432/booking_test?sslmode=require
|
||||
|
||||
# ARR -> SuperAgent Open API. This credential is not the MCP bearer.
|
||||
DEERFLOW_BASE_URL=https://superagent.example.com
|
||||
DEERFLOW_OPEN_API_KEY=replace_with_superagent_open_api_key
|
||||
DEERFLOW_AUTH_MODE=bearer
|
||||
DEERFLOW_TIMEOUT_SECONDS=60
|
||||
DEERFLOW_CONNECT_TIMEOUT_SECONDS=10
|
||||
|
||||
# Independent callback/signature material required by the processing runtime.
|
||||
ARR_AGENT_RESULT_HMAC_KEY_ID=arr-callback-key-1
|
||||
ARR_AGENT_RESULT_HMAC_KEY_B64=replace_with_base64_of_32_random_bytes
|
||||
ARR_AGENT_RESULT_MAX_AGE_SECONDS=600
|
||||
|
||||
# Private, encrypted, unversioned OSS bucket. public-read-write is rejected.
|
||||
ARR_OBJECT_PREFIX=arr
|
||||
ARR_OSS_REGION=cn-hangzhou
|
||||
ARR_OSS_ENDPOINT=https://oss-cn-hangzhou.aliyuncs.com
|
||||
ARR_OSS_BUCKET=replace-with-private-bucket
|
||||
ARR_OSS_BUCKET=replace-with-bucket
|
||||
|
||||
# Prefer a RAM role or short-lived STS credentials in production. The stock
|
||||
# Compose profile accepts environment credentials for an initial controlled test.
|
||||
# Prefer RAM role or short-lived STS credentials in production.
|
||||
OSS_ACCESS_KEY_ID=replace_me
|
||||
OSS_ACCESS_KEY_SECRET=replace_me
|
||||
# OSS_SESSION_TOKEN=replace_me
|
||||
|
||||
@@ -5,10 +5,6 @@
|
||||
{$WEB_PUBLIC_HOST} {
|
||||
encode zstd gzip
|
||||
|
||||
basic_auth {
|
||||
{$WEB_BASIC_AUTH_USER} {$WEB_BASIC_AUTH_PASSWORD_HASH}
|
||||
}
|
||||
|
||||
header {
|
||||
Strict-Transport-Security "max-age=31536000; includeSubDomains"
|
||||
X-Content-Type-Options "nosniff"
|
||||
@@ -20,15 +16,3 @@
|
||||
|
||||
reverse_proxy web:8765
|
||||
}
|
||||
|
||||
{$MCP_PUBLIC_HOST} {
|
||||
header {
|
||||
Strict-Transport-Security "max-age=31536000; includeSubDomains"
|
||||
X-Content-Type-Options "nosniff"
|
||||
X-Frame-Options "DENY"
|
||||
Referrer-Policy "no-referrer"
|
||||
-Server
|
||||
}
|
||||
|
||||
reverse_proxy mcp:8890
|
||||
}
|
||||
|
||||
158
deploy/README.md
158
deploy/README.md
@@ -1,149 +1,69 @@
|
||||
# 公网部署与完整 XML 流程测试
|
||||
# ARR 2.0 单机 Compose 部署
|
||||
|
||||
本目录提供单机 Docker Compose 部署配置:Caddy 负责公网 HTTPS,Web 负责 XML 上传与任务发起,MCP 负责 SuperAgent 处理结果落库。
|
||||
本 Compose 模板部署两个 HTTP 服务:`web` 负责应用登录、页面、程序化 XML 处理、验证和入库,`caddy` 负责 HTTPS。没有 Agent 回调服务或 MCP 公网入口。自动月报由另一个无端口的 `monthly_reports.worker` 进程执行,不得放进 Web 请求进程。
|
||||
|
||||
## 1. 前置条件
|
||||
## 前置条件
|
||||
|
||||
- 一台安装 Docker Engine 与 Docker Compose v2 的 Linux 服务器;
|
||||
- 两个已解析到该服务器的 DNS 名称,例如 `arr.example.com` 和 `mcp.example.com`;
|
||||
- 防火墙仅向公网开放 TCP 80/443(可选开放 UDP 443);
|
||||
- PostgreSQL 15+ 数据库,数据库名必须是 `booking_test`;
|
||||
- 私有、已启用服务端加密且关闭 versioning 的阿里云 OSS bucket;
|
||||
- SuperAgent 已发布的 ARR Agent Open API key;
|
||||
- SuperAgent 能访问 MCP 公网域名,并能通过其受信 `fetch_oss_file` 能力读取同一 OSS bucket。
|
||||
- DNS:`WEB_PUBLIC_HOST` 指向部署主机;
|
||||
- PostgreSQL 15+:目标必须是隔离数据库 `booking_test`,并已应用 008–012 权威迁移;
|
||||
- OSS:区域匹配、服务端加密、未启用或暂停 versioning、禁止匿名写;bucket ACL 可为 private 或 public-read;
|
||||
- ARR 数据库账号和 OSS RAM/STS 凭据由 Secret 管理器注入,不写入镜像或仓库。
|
||||
- worker 与 Web 使用同一数据库和共享的 `/app/outputs` 持久卷;worker 镜像还必须包含 Node.js 与配置匹配的 artifact-tool 模块。
|
||||
|
||||
Web 和 MCP 的 8765/8890 端口只在 Compose 内部网络暴露,不要映射到公网。
|
||||
|
||||
## 2. 数据库状态
|
||||
|
||||
若沿用已经验收并记录在 `database/APPLIED_MIGRATIONS.md` 的 `booking_test`,不要重跑任何迁移。
|
||||
|
||||
仅对全新、空的 `booking_test`,由有权限的数据库管理员在完成备份/目标核对后依次执行:
|
||||
|
||||
1. `database/008_arr_mvp_v1_rebuild.sql`
|
||||
2. `database/009_source_read_grants.sql`
|
||||
3. `database/010_mcp_result_ingestion.sql`
|
||||
|
||||
`008` 会删除并重建该数据库内的 `ingestion`、`booking`、`finance` schema;绝不能对含有未备份业务数据的库执行。`001`–`007` 是历史迁移,不应在 `008` 之后补跑。若数据库尚不存在,`000_create_booking_test_database.sql` 只能由 DBA 在维护库中单独执行。
|
||||
|
||||
## 3. 准备 Secret 配置
|
||||
## 配置
|
||||
|
||||
```bash
|
||||
cp deploy/.env.production.example deploy/.env.production
|
||||
chmod 600 deploy/.env.production
|
||||
```
|
||||
|
||||
编辑 `deploy/.env.production`,替换所有 `replace...` 值。该文件已被 Git 忽略,不能提交。
|
||||
填写应用登录账号/长随机密码、数据库、OSS 和域名。登录凭据必须由 Secret 管理器注入,不能写入镜像或提交到仓库。ARR 2.0 不需要以下配置:
|
||||
|
||||
生成相互独立的随机材料:
|
||||
- SuperAgent/Open Agent URL 或 API key;
|
||||
- MCP 域名、Bearer 或并发参数;
|
||||
- Agent callback URL/HMAC;
|
||||
- `fetch_oss_file` 或源文件公网 URL。
|
||||
|
||||
```bash
|
||||
openssl rand -hex 32
|
||||
openssl rand -base64 32
|
||||
docker run --rm -it caddy:2.10-alpine caddy hash-password
|
||||
```
|
||||
|
||||
- 第一项可作为 `ARR_MCP_BEARER_TOKEN`;
|
||||
- 第二项可作为 `ARR_AGENT_RESULT_HMAC_KEY_B64`;
|
||||
- 第三项会交互式读取 Web 密码并输出 Caddy bcrypt hash。把 hash 写入 env 文件时使用单引号,例如 `WEB_BASIC_AUTH_PASSWORD_HASH='$2a$...'`,避免 `$` 被 Compose 展开;
|
||||
- MCP bearer、SuperAgent Open API key、HMAC key、数据库密码和 OSS 凭据必须彼此独立;
|
||||
- 数据库 URL 中的特殊字符需按 URL 规则编码。
|
||||
|
||||
生产环境优先把凭据交给服务器 Secret 管理/RAM/STS。当前 Compose 模板通过进程环境变量注入凭据,适合受控的首次公网测试;不要把 env 文件打进镜像或备份到公开位置。
|
||||
|
||||
## 4. 启动
|
||||
|
||||
在仓库根目录执行:
|
||||
## 校验并启动
|
||||
|
||||
```bash
|
||||
docker compose --env-file deploy/.env.production config --quiet
|
||||
docker compose --env-file deploy/.env.production up -d --build
|
||||
docker compose --env-file deploy/.env.production ps
|
||||
docker compose --env-file deploy/.env.production build web
|
||||
docker compose --env-file deploy/.env.production up -d
|
||||
```
|
||||
|
||||
Web 的 Compose 命令明确包含:
|
||||
|
||||
```text
|
||||
python -m arr_web.run ... --enable-processing --secure-cookies
|
||||
```
|
||||
|
||||
镜像的 Dockerfile 默认 Web CMD 也包含 `--enable-processing`。运维若在容器平台
|
||||
覆盖 CMD/command,必须保留该参数,否则页面会显示“文件接收服务尚未完成生产接线”。
|
||||
|
||||
这些部署入口会请求打开 XML 上传处理,但不会绕过健康门禁:Web
|
||||
只有在数据库、OSS、SuperAgent 和签名配置都装配成功时才返回
|
||||
`processing_ready=true`。应用源码的 CLI 默认值仍未改成开放;Caddy 会等待
|
||||
Web/MCP 健康后再接入公网。
|
||||
|
||||
查看日志时不要复制或公开 env 文件内容:
|
||||
当前仓库镜像未内置 Codex 工作站提供的 artifact-tool,因此 Compose 模板不会虚假启动一个无法生成 XLSX 的 worker。部署环境完成该依赖打包后,应由 systemd、容器编排器或同等进程管理器独立执行:
|
||||
|
||||
```bash
|
||||
docker compose --env-file deploy/.env.production logs --tail=200 web mcp caddy
|
||||
python -m monthly_reports.worker \
|
||||
--db-config /run/secrets/booking-test-db.env \
|
||||
--node-binary /absolute/path/to/node \
|
||||
--artifact-tool-module /absolute/path/to/artifact_tool.mjs \
|
||||
--output-root /app/outputs/monthly_reports
|
||||
```
|
||||
|
||||
## 5. 公网验收
|
||||
|
||||
先验证 Web。下面命令会让 `curl` 交互式询问 Basic Auth 密码,避免把密码写进 shell history:
|
||||
检查:
|
||||
|
||||
```bash
|
||||
export WEB_PUBLIC_HOST=arr.example.com
|
||||
export WEB_BASIC_AUTH_USER=arrtester
|
||||
curl --fail --user "$WEB_BASIC_AUTH_USER" "https://$WEB_PUBLIC_HOST/api/health"
|
||||
curl --fail --silent "https://$WEB_PUBLIC_HOST/healthz"
|
||||
docker compose --env-file deploy/.env.production logs --tail=100 web
|
||||
```
|
||||
|
||||
响应中的以下值必须同时为 `true`:
|
||||
`/healthz` 仅以 HTTP 200/503 表示数据库与处理入口是否就绪,不暴露组件详情;详细 `/api/health` 必须登录后访问。worker 是独立进程,应另行监控其存活和 outbox 的 `pending/publishing/dead` 数量。失败时优先检查登录环境变量、数据库目标、OSS 区域/加密/versioning、OSS 凭据、固定处理器以及月报构建依赖;无需排查 Agent 或 MCP。
|
||||
|
||||
```json
|
||||
{
|
||||
"database_ready": true,
|
||||
"processing_ready": true
|
||||
}
|
||||
```
|
||||
## 验收
|
||||
|
||||
若 `processing_ready=false`,不要开始 XML 测试;优先核对数据库目标、OSS bucket 策略/加密/versioning、OSS 环境凭据、SuperAgent URL/key 和 HMAC 配置。
|
||||
使用无真实住客隐私的受控 XML:
|
||||
|
||||
再验证 MCP 的认证边界:
|
||||
1. 未登录访问首页应进入 ARR 登录页,错误凭据不得创建会话;
|
||||
2. 使用授权 Finance 账号登录,页面上传一次 XML;
|
||||
3. 上传响应应直接给出 `succeeded` 或 `failed` 终态以及 `job_id`;
|
||||
4. 在任务日志中确认“固定处理器已启动 → 程序输出制品已登记 → 独立验收 → Finance 提交”;
|
||||
5. 成功任务应能下载对应日报,数据库中 source/retained/outcome 数量必须与结构化结果一致;
|
||||
6. worker 应消费对应 outbox 事件,页面显示真实月报 ID/版本/“更新至”,下载文件哈希应与登记值一致;
|
||||
7. 退出登录后,页面、API 和下载均应重新要求登录;
|
||||
8. 业务失败任务不得激活 Finance 当前版本或触发月报。
|
||||
|
||||
```bash
|
||||
export MCP_PUBLIC_HOST=mcp.example.com
|
||||
curl --silent --output /dev/null --write-out '%{http_code}\n' "https://$MCP_PUBLIC_HOST/mcp"
|
||||
```
|
||||
## 回退
|
||||
|
||||
未认证请求必须返回 `401`。随后从 Secret 管理器读取 bearer,在不回显的终端变量中执行 MCP `initialize`/`tools/list`;认证后的发现结果应且只能包含 `arr_submit_processing_result`。完成后立即 `unset ARR_MCP_TOKEN`。
|
||||
|
||||
## 6. 重新绑定 SuperAgent MCP
|
||||
|
||||
在 SuperAgent MCP 管理中使用:
|
||||
|
||||
- 地址:`https://<MCP_PUBLIC_HOST>/mcp`
|
||||
- Header:`Authorization: Bearer <ARR_MCP_BEARER_TOKEN>`(使用平台 Secret 引用)
|
||||
- OAuth:空
|
||||
- 工具:只启用 `arr_submit_processing_result`
|
||||
|
||||
公网域名与临时 ngrok 地址不同,因此必须重新执行“连接/发现工具/保存”,再把 MCP 绑定到 ARR Agent 的新草稿并发布。只有工具发现成功且 Agent 已保存到当前发布版本后,才能进行页面上传测试。
|
||||
|
||||
## 7. 完整 XML 测试
|
||||
|
||||
1. 登录 `https://<WEB_PUBLIC_HOST>/`;
|
||||
2. 上传一份不含真实住客隐私的 Opera XML;
|
||||
3. 确认页面返回 `job_id`,任务状态进入 queued/running;
|
||||
4. 在 SuperAgent 确认本次会话只读取该 OSS XML,并调用唯一 ARR MCP 工具;
|
||||
5. 以 MCP receipt 的 `committed` 或 `already_committed` 为落库成功依据;Agent 页面单独显示 `success` 不等于数据库已提交;
|
||||
6. 回到 Web 核对日报历史、数据库月度投影和渠道看板。
|
||||
|
||||
## 8. 更新与回退
|
||||
|
||||
```bash
|
||||
git pull --ff-only
|
||||
docker compose --env-file deploy/.env.production up -d --build
|
||||
```
|
||||
|
||||
不要强制覆盖仓库历史,也不要把数据库迁移放进容器自动启动。回退应用镜像前先核对数据库 schema 兼容性;数据库回滚脚本只能按各文件顶部门禁人工执行。
|
||||
|
||||
## 当前未完成项
|
||||
|
||||
- 日报入库后自动触发月报仍未实现;
|
||||
- 月报 `TOTAL PRICE` 的指定公式规则仍未实现;
|
||||
- 本 Compose 配置因此只开启 XML processing,不开启月报、公司报表或旧 callback 写入开关。
|
||||
|
||||
完成一笔无隐私 XML 的公网竖切前,部署只能标记为“服务已启动”,不能标记为“业务链路已验收”。
|
||||
ARR 2.0 与 `/Users/chillishark/ARR项目0727` 是两个独立目录。应用级回退可停止本 Compose 并重新启动原工程;不要为了应用回退而删除数据库 009/010 表或 OSS 工件。数据库破坏性回滚需要单独审批、备份和迁移演练。
|
||||
|
||||
Reference in New Issue
Block a user