feat: sync latest ARR implementation

This commit is contained in:
Wyndham ARR
2026-07-31 15:11:42 +08:00
parent d6f8a747fa
commit bf7939dd1a
185 changed files with 17527 additions and 2260 deletions

View File

@@ -1,100 +1,39 @@
# ARR Web Portal
# ARR 2.0 Web
The portal exposes four surfaces:
Web 层提供固定页面和审计友好的 API。生产 XML 写路径为:
- 日报处理XML upload, remote processing status, ARR validation and database result;
- 月报处理ordinary program generation from current database facts;
- 渠道 BIlive read-only aggregation from current retained facts;
- 渠道使用情况company ten-day report jobs.
`POST /api/jobs``ProgrammaticUploadCoordinator` → 固定处理器 → `DeliveryValidator` → PostgreSQL 原子提交。
## Current database model
`arr_web.repository.PostgresPortalRepository` reads migration 008 relations:
- `ingestion.processing_runs` / `ingestion.artifacts` for daily history and artifacts;
- `finance.daily_versions` / `finance.current_daily_versions` for validated dates;
- `finance.v_active_daily_facts` and current channel metrics through `channel_analytics`.
There are no database `report_versions`. The monthly-runs read endpoint exposes a source-ready monthly projection (dates, channels and row count) and does not claim an XLSX artifact. Generated monthly files live in the controlled publishing/OSS layer.
## Local run
```bash
PYTHONPYCACHEPREFIX=/private/tmp/arr-web-pyc \
.venv/bin/python -m arr_web.run \
--host 127.0.0.1 \
--port 8765 \
--db-config /path/to/private/booking-test-db.env \
--enable-processing \
--enable-agent-writeback \
--enable-monthly-generation \
--enable-company-reports \
--node-binary /absolute/path/to/node \
--artifact-tool-module /absolute/path/to/artifact_tool.mjs
```
- Desktop: `http://127.0.0.1:8765/`
- H5: `http://127.0.0.1:8765/h5`
- Health: `http://127.0.0.1:8765/api/health`
The active test target is the controlled `<ARR_DB_HOST>:5432/booking_test`. The old `booking-test-lan-db.env` is retained only for temporary rollback checks and should not receive new writes.
`--enable-processing` is also fail-closed. It reports `processing_ready=true`
only when PostgreSQL, the guarded OSS uploader and the Open Agent client all
initialize; the dispatched message contains one `fetch_oss_file` attachment
descriptor and no OSS credential.
`--enable-agent-writeback` is fail-closed. `GET /api/health` reports
`agent_writeback_ready=true` only after the current processor policy, PostgreSQL
state/repository, independent HMAC verifier, Aliyun OSS backend and controlled
output reader all initialize successfully. Missing or incompatible deployment
configuration keeps the callback route unavailable instead of accepting an
unverified result.
The local LaunchAgent wrapper optionally loads
`/path/to/private/agent-writeback.env`. It refuses a symlink,
non-regular file, foreign owner or permissions other than `0600`; no real
secret belongs in this repository or `.env.example`.
Local secrets use the macOS Keychain account `arr-web`. The launcher maps the
OSS key ID/secret and the Agent Open API key from their dedicated service names
into process environment variables; the callback HMAC remains an independent
Keychain item. At present the launchd label and launcher/log paths still use
the historical project location even though the process runs this repository;
that deployment-path cleanup is separate from application readiness.
## Security
- Browsers never receive a PostgreSQL DSN or OSS credential.
- Read transactions are repeatable-read/read-only and reject any database other than `booking_test`.
- Writes use same-origin session/CSRF; machine result callbacks use signed result verification.
- Downloads are resolved from server-owned artifact identity, then rechecked for path, type, size and SHA-256.
- Production needs dedicated reader/writer roles and a provider-backed private OSS reader; the current test database owner and local fixture reader are not production configuration.
## API
主要接口:
- `GET /login``POST /api/login``POST /api/logout`
- `GET /api/session`
- `GET /api/health`
- `GET|POST /api/jobs`
- `GET|POST /api/monthly-runs`
- `GET /api/months`
- `GET /api/analytics`
- `GET /api/h5/months` (legacy H5 raw compatibility)
- `GET /api/monthly/{month_key}/analytics` (analytics 1.2 raw compatibility)
- `GET /api/channel-detail`
- `GET|POST /api/company-reports/jobs`
- `POST /api/integrations/super-agent/results`
- `GET /healthz`:仅供容器读取的无详情 readiness 探针
- `POST /api/jobs`
- `GET /api/jobs`
- `GET /api/jobs/{job_id}/trace`
- `GET /api/download/daily`
- `GET /api/monthly-runs?month=YYYY-MM`:读取已持久化的月报版本
- `GET /api/download/monthly?report_id=...`:下载登记为 active/superseded 的月报并复核路径、大小和 SHA-256
- `POST /api/company-reports/source`:上传并提取原始 Booking XLSX先创建复核草稿
- `GET /api/company-reports/source/draft`:分页读取当前复核草稿
- `PATCH`/`DELETE /api/company-reports/source/draft/items/{id}`:人工保存房型/数量或删除记录
- `DELETE /api/company-reports/source/draft/items`:在同一事务中批量删除最多 50 条所选记录
- `DELETE /api/company-reports/source/draft``POST /api/company-reports/source/draft/activate`:放弃草稿或在零待人工时原子启用
- BI 与公司报表接口
The machine callback accepts the canonical signed body described in
[`AGENT_WRITEBACK_CONTRACT.md`](../AGENT_WRITEBACK_CONTRACT.md). HTTP `200`
means that the delivery is committed (or is an identical idempotent replay),
not merely that the remote Agent Run reported `success`.
ARR 2.0 不注册 `/api/integrations/super-agent/results`。访问旧回调地址返回 `404 ROUTE_NOT_FOUND`
## Verification
除登录静态资源、`POST /api/login``/healthz`页面、API、上传与下载均要求应用登录。Web 进程从 `ARR_WEB_USERNAME` / `ARR_WEB_PASSWORD` 读取 Finance 操作员凭据;缺失时启动失败。会话 cookie 为 `HttpOnly``SameSite=Strict`HTTPS 部署必须启用 `--secure-cookies`。Caddy 仅终结 HTTPS不再使用浏览器原生 Basic Auth。
```bash
PYTHONPYCACHEPREFIX=/private/tmp/arr-web-pyc \
python3 -m unittest tests.test_arr_web_repository_schema tests.test_arr_web -v
```
`--enable-processing` 只有在数据库、OSS、固定处理器和独立验证器全部初始化成功时才使 `processing_ready=true`。上传处理是同步终态边界HTTP 保持 `202` 兼容页面,但响应前已经完成验证/入库或记录失败。
The full fake-transport end-to-end suite remains privacy-safe and uses synthetic identifiers only.
日报历史和任务日志中的“文件”只显示浏览器上传的 XML basename。内部源工件继续规范化为 `source.xml`,不会暴露到这两个用户界面;迁移前的历史任务没有可还原的上传名,页面显示 `—`
月报主页面没有月份、截止日、手动生成或手动刷新控件。日报提交成功后,独立 `monthly_reports.worker` 消费 outbox 事件;它从数据库内纳入数据的最新 `ARRIVAL` 派生“更新至”。月报页可见时每四秒自动读取 `reporting.monthly_runs`新版本发布后直接新增页面隐藏或离开该页时停止轮询恢复时立即读取。Web 内部 POST 生成端点只作为显式启用的受控恢复入口,不属于用户主流程。
公司渠道明细的 Booking XLSX 使用“提取 → 人工核对 → 整表启用”边界。上传只写私有源工件和
`booking.extraction_*` 草稿;自动/人工记录都能编辑或删除,待人工项目不会进入有效房量。只有草稿不存在
待人工项目且至少保留一条确认记录时,后端才在一个事务中生成 accepted Booking 批次并切换
`booking.current_source_batch`。打开草稿期间禁止创建新的公司渠道明细任务。