Update docs for ops, payments, and deployment guidance

This commit is contained in:
2569718930@qq.com
2026-03-21 14:52:25 +08:00
parent adf2924a1c
commit dd720582d5
10 changed files with 332 additions and 22 deletions
+11
View File
@@ -1,5 +1,16 @@
# Changelog
## Unreleased
- 新增 `/ops` 轻量运营后台,支持系统状态、会员列表、用户查询、周榜、手动补分
- `/ops` 新增支付异常单,支持按原因筛选并手动标记“已处理”
- 会员列表支持按 `user_id` 去重,并回补 Supabase Auth 邮箱/注册时间
- 新增按邮箱补跑订阅恢复脚本 `scripts/reconcile_subscription_by_email.py`
- 支付确认失败(如 `receiver_mismatch`)现在会明确落 `failed`,并写入 SQLite 审计事件
- 账户页支付前强制重新拉取 `/api/payments/config`,并对 `tx_payload.to` 做最新地址校验
- 城市详情页新增 `官方参考 / Official Sources` 区块,覆盖主要城市的官方机构/机场/METAR 链接
- 前端钱包选择补齐 EIP-6963 发现、稳定去重和绑定后账户状态即时刷新
## 1.5.0 - 2026-03-21
- 运行态状态与缓存支持 SQLite 渐进迁移,新增 `POLYWEATHER_STATE_STORAGE_MODE=file|dual|sqlite`
+32 -6
View File
@@ -14,12 +14,16 @@ Official dashboard: [polyweather-pro.vercel.app](https://polyweather-pro.vercel.
![PolyWeather Ankara analysis](docs/images/demo_ankara.png)
## Product Status (2026-03)
## Product Status (2026-03-21)
- Subscription live: `Pro Monthly 5 USDC`.
- Points redemption live: `500 points = 1 USDC`, max `3 USDC` off.
- Onchain checkout live: Polygon contract checkout (USDC / USDC.e).
- Auto-reconciliation live: event listener + periodic confirm loop.
- Ops dashboard live: `/ops` for memberships, leaderboard, manual point grants, and payment incident triage.
- Lightweight observability live: `/healthz`, `/api/system/status`, `/metrics`.
- Runtime state supports gradual SQLite migration (`file / dual / sqlite`).
- EMOS/CRPS pipeline is integrated in `shadow` mode with rollout gating.
## Open-Core Boundary (Important)
@@ -32,11 +36,12 @@ See: [Open-Core & Commercial Boundary](docs/OPEN_CORE_POLICY.md)
## Core Capabilities
- Aggregates observations and forecasts for 20 monitored cities.
- Aggregates observations and forecasts for 30 monitored cities.
- Uses DEB (Dynamic Error Balancing) to blend multi-model highs.
- Generates settlement-oriented probability buckets (`mu` + bucket distribution).
- Maps weather view to Polymarket quotes for mispricing scan.
- Reuses one analysis core across web dashboard and Telegram bot.
- Adds payment audit trails, replay tooling, and incident visibility in ops.
## Reference Architecture
@@ -57,12 +62,13 @@ flowchart LR
ANA --> PM["Polymarket Read-only Layer"]
```
## Monitored Cities (20)
## Monitored Cities (30)
- Europe / Middle East: Ankara, London, Paris, Munich
- APAC: Seoul, Hong Kong, Shanghai, Singapore, Tokyo, Wellington
- Europe / Middle East: Ankara, London, Paris, Munich, Tel Aviv, Milan, Warsaw, Madrid
- APAC: Seoul, Hong Kong, Taipei, Shanghai, Singapore, Tokyo, Wellington
- Americas: Toronto, New York, Chicago, Dallas, Miami, Atlanta, Seattle, Buenos Aires, Sao Paulo
- South Asia: Lucknow
- China extension: Chengdu, Chongqing, Shenzhen, Beijing, Wuhan
## Quick Start
@@ -91,6 +97,14 @@ POLYWEATHER_DB_PATH=/var/lib/polyweather/polyweather.db
## Ops Verification
### Health / system status / metrics
```bash
curl http://127.0.0.1:8000/healthz
curl http://127.0.0.1:8000/api/system/status
curl http://127.0.0.1:8000/metrics
```
### Frontend cache headers
```bash
@@ -103,6 +117,12 @@ POLYWEATHER_DB_PATH=/var/lib/polyweather/polyweather.db
docker compose logs -f polyweather | egrep "payment event loop started|payment confirm loop started|payment auto-confirmed"
```
### Payment runtime
```bash
curl http://127.0.0.1:8000/api/payments/runtime
```
### Wallet activity logs
```bash
@@ -127,9 +147,15 @@ docker compose logs -f polyweather | egrep "polymarket wallet activity watcher s
- Commercialization: [docs/COMMERCIALIZATION.md](docs/COMMERCIALIZATION.md)
- Open-Core policy: [docs/OPEN_CORE_POLICY.md](docs/OPEN_CORE_POLICY.md)
- Supabase setup (ZH): [docs/SUPABASE_SETUP_ZH.md](docs/SUPABASE_SETUP_ZH.md)
- Configuration & secrets (ZH): [docs/CONFIGURATION_ZH.md](docs/CONFIGURATION_ZH.md)
- Frontend deployment (ZH): [docs/FRONTEND_DEPLOYMENT_ZH.md](docs/FRONTEND_DEPLOYMENT_ZH.md)
- Tech debt (EN): [docs/TECH_DEBT.md](docs/TECH_DEBT.md)
- Tech debt (ZH): [docs/TECH_DEBT_ZH.md](docs/TECH_DEBT_ZH.md)
- Payment verification: [docs/payments/POLYGONSCAN_VERIFY.md](docs/payments/POLYGONSCAN_VERIFY.md)
- Payment audit: [docs/payments/PAYMENT_AUDIT_ZH.md](docs/payments/PAYMENT_AUDIT_ZH.md)
- Payment V2 upgrade: [docs/payments/PAYMENT_UPGRADE_V2_ZH.md](docs/payments/PAYMENT_UPGRADE_V2_ZH.md)
- Ops admin guide: [docs/OPS_ADMIN_ZH.md](docs/OPS_ADMIN_ZH.md)
- Deep research report: [docs/deep-research-report.md](docs/deep-research-report.md)
- Frontend report: [FRONTEND_REDESIGN_REPORT.md](FRONTEND_REDESIGN_REPORT.md)
- Release process: [RELEASE.md](RELEASE.md)
- Changelog: [CHANGELOG.md](CHANGELOG.md)
@@ -137,4 +163,4 @@ docker compose logs -f polyweather | egrep "polymarket wallet activity watcher s
## Version
- Version: `v1.5.0`
- Last Updated: `2026-03-14`
- Last Updated: `2026-03-21`
+13 -2
View File
@@ -14,13 +14,14 @@
![PolyWeather Ankara 分析页](docs/images/demo_ankara.png)
## 当前产品状态(2026-03-20
## 当前产品状态(2026-03-21
- 已上线订阅制:`Pro 月付 5 USDC`
- 已上线积分抵扣:`500 积分 = 1 USDC`,最多抵扣 `3 USDC`
- 已上线链上支付:Polygon 合约支付(USDC / USDC.e)。
- 已上线自动补单:事件监听 + 周期确认双链路。
- 已上线支付运行态与审计接口:`/api/payments/runtime`
- 已上线轻量运营后台:`/ops`(会员、周榜、补分、支付异常单)。
- 已上线轻量可观测性:`/healthz``/api/system/status``/metrics`
- 运行态状态与缓存已支持 SQLite 渐进迁移:`file / dual / sqlite`
- 已接入 EMOS/CRPS 校准链路,但当前仍保持 `emos_shadow`
@@ -126,6 +127,15 @@ docker compose logs -f polyweather | egrep "payment event loop started|payment c
curl http://127.0.0.1:8000/api/payments/runtime
```
### 运营后台
- 前端入口:`https://polyweather-pro.vercel.app/ops`
- 后端需配置:
```env
POLYWEATHER_OPS_ADMIN_EMAILS=yhrsc30@gmail.com
```
### 钱包异动监听日志
```bash
@@ -159,6 +169,7 @@ docker compose logs -f polyweather | egrep "polymarket wallet activity watcher s
- 支付合约验证:[docs/payments/POLYGONSCAN_VERIFY.md](docs/payments/POLYGONSCAN_VERIFY.md)
- 支付审计说明:[docs/payments/PAYMENT_AUDIT_ZH.md](docs/payments/PAYMENT_AUDIT_ZH.md)
- 支付 V2 升级方案:[docs/payments/PAYMENT_UPGRADE_V2_ZH.md](docs/payments/PAYMENT_UPGRADE_V2_ZH.md)
- 运营后台说明:[docs/OPS_ADMIN_ZH.md](docs/OPS_ADMIN_ZH.md)
- 深度评估报告:[docs/deep-research-report.md](docs/deep-research-report.md)
- 前端报告:[FRONTEND_REDESIGN_REPORT.md](FRONTEND_REDESIGN_REPORT.md)
- 发布流程:[RELEASE.md](RELEASE.md)
@@ -167,4 +178,4 @@ docker compose logs -f polyweather | egrep "polymarket wallet activity watcher s
## 当前版本
- 版本:`v1.5.0`
- 文档最后更新:`2026-03-20`
- 文档最后更新:`2026-03-21`
+32 -4
View File
@@ -1,6 +1,6 @@
# PolyWeather API 文档(v1.5.0
最后更新:`2026-03-20`
最后更新:`2026-03-21`
本文档描述当前对外可用 API 口径(`web/app.py` + `web/routes.py` + `frontend/app/api/*`)。
@@ -74,6 +74,7 @@ flowchart LR
| `/api/payments/intents/{intent_id}` | GET | 查询 intent 最新状态 |
| `/api/payments/intents/{intent_id}/submit` | POST | 提交交易哈希 |
| `/api/payments/intents/{intent_id}/confirm` | POST | 手动触发确认 |
| `/api/payments/reconcile-latest` | POST | 对当前登录用户最近一笔 intent 做恢复性确认 |
### 支付状态建议
@@ -107,13 +108,34 @@ flowchart LR
- `polyweather_source_requests_total`
- `polyweather_source_request_duration_ms_*`
## 7. 缓存策略(当前)
## 7. Ops 管理接口
这些接口主要给 `/ops` 管理后台使用,默认要求:
- 已登录
- 当前邮箱位于 `POLYWEATHER_OPS_ADMIN_EMAILS`
| 接口 | 方法 | 用途 |
| :-- | :-- | :-- |
| `/api/ops/users` | GET | 按 Telegram ID / 用户名 / 邮箱查询用户 |
| `/api/ops/leaderboard/weekly` | GET | 本周积分榜 |
| `/api/ops/memberships` | GET | 当前有效会员(已按用户去重,保留最晚到期) |
| `/api/ops/users/grant-points` | POST | 手动补分 |
| `/api/ops/payments/incidents` | GET | 支付异常单(仅 `payment_intent_failed` |
| `/api/ops/payments/incidents/{event_id}/resolve` | POST | 标记支付异常单已处理 |
`/api/ops/payments/incidents` 当前支持:
- `reason=<receiver_mismatch|sender_mismatch|event_mismatch|tx_reverted>`
- 默认不返回已标记处理的记录
- 重点用于排查“已付款未开通”“打到旧收款地址”等事故
## 8. 缓存策略(当前)
- `cities` / `summary` / `history`BFF 支持 `ETag + 304`
- `summary?force_refresh=true``Cache-Control: no-store`
- 详情接口与支付接口:`no-store`
## 8. 调试示例
## 9. 调试示例
### 查询未来日期 market_scan
@@ -133,6 +155,12 @@ curl -s http://127.0.0.1:8000/api/payments/config | python3 -m json.tool
curl -s http://127.0.0.1:8000/api/payments/runtime | python3 -m json.tool
```
### 查看支付异常单
```bash
curl -s "http://127.0.0.1:8000/api/ops/payments/incidents?reason=receiver_mismatch" | python3 -m json.tool
```
### 查看系统状态
```bash
@@ -145,7 +173,7 @@ curl -s http://127.0.0.1:8000/api/system/status | python3 -m json.tool
docker compose logs -f polyweather | egrep "payment event loop started|payment confirm loop started|payment auto-confirmed"
```
## 9. 开源口径说明
## 10. 开源口径说明
对外公开文档仅覆盖通用 API 契约。生产商业策略参数不在公开文档披露。
+8
View File
@@ -101,6 +101,7 @@ PolyWeather 的环境变量很多,但不是所有变量都属于同一层级
- `POLYWEATHER_AUTH_ENABLED`
- `POLYWEATHER_AUTH_REQUIRED`
- `POLYWEATHER_AUTH_REQUIRE_SUBSCRIPTION`
- `POLYWEATHER_OPS_ADMIN_EMAILS`
- `POLYWEATHER_STATE_STORAGE_MODE`
- `POLYWEATHER_PAYMENT_ENABLED`
- `POLYMARKET_MARKET_SCAN_ENABLED`
@@ -162,6 +163,11 @@ PolyWeather 的环境变量很多,但不是所有变量都属于同一层级
- `NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID`
- `NEXT_PUBLIC_WALLETCONNECT_POLYGON_RPC_URL`
说明:
- `/ops` 页面本身部署在 Vercel 前端下,但管理员写接口权限仍由后端 `POLYWEATHER_OPS_ADMIN_EMAILS` 控制。
- 因此,Vercel 侧不需要配置管理员邮箱白名单;管理员判定发生在 VPS / FastAPI 后端。
不要把后端专用密钥全搬进 Vercel。
### 5.3 GitHub Actions
@@ -198,6 +204,7 @@ UID=1000
GID=1000
POLYWEATHER_AUTH_ENABLED=true
POLYWEATHER_AUTH_REQUIRED=false
POLYWEATHER_OPS_ADMIN_EMAILS=yhrsc30@gmail.com
SUPABASE_URL=https://your-project.supabase.co
SUPABASE_ANON_KEY=...
SUPABASE_SERVICE_ROLE_KEY=...
@@ -258,6 +265,7 @@ POLYWEATHER_BACKEND_ENTITLEMENT_TOKEN=...
2. `.env.secrets.example` 新增
3. 前端 `.env.example` 收口
4. 运行时配置校验脚本新增
5. `/ops` 管理员白名单与前后端职责边界已明确
5. 支付运行态与多 RPC 配置支持
6. 运行态 SQLite 迁移配置支持
+26 -5
View File
@@ -87,7 +87,27 @@ NEXT_PUBLIC_TELEGRAM_BOT_URL=https://t.me/WeatherQuant_bot
只影响按钮跳转,不影响核心页面加载。
## 五、推荐的三套配置口径
## 五、支付配置与旧部署治理
支付区现在有一层额外防护:
1. 用户点击支付前,前端会重新请求 `/api/payments/config`
2. 若发现 `receiver_contract` 与页面旧状态不一致,会自动切换到最新地址
3. 若后端返回的 `tx_payload.to` 与最新 `receiver_contract` 不一致,会直接阻断支付
这层防护的目的,是降低以下事故概率:
- 用户使用长期未刷新的旧标签页
- 命中旧 deployment URL
- 页面本地状态残留旧收款地址
如果你变更过支付收款地址,建议同步执行:
1. 在 Vercel 对当前 production 做一次 redeploy
2. 删除明显过期、可能还带旧支付配置的旧 deployment
3.`Settings -> Security -> Deployment Retention Policy` 中收紧旧部署保留周期
## 六、推荐的三套配置口径
### 1. 公开游客模式
@@ -124,7 +144,7 @@ POLYWEATHER_BACKEND_ENTITLEMENT_TOKEN=<shared-token>
适合前后端都启用了会员/订阅保护的生产环境。
## 、不要放进 Vercel 的变量
## 、不要放进 Vercel 的变量
这些属于后端私密配置,不应该放到前端项目:
@@ -138,7 +158,7 @@ POLYWEATHER_BACKEND_ENTITLEMENT_TOKEN=<shared-token>
- `NEXT_PUBLIC_*` 会暴露给浏览器
- 只有明确允许前端公开使用的值,才应加 `NEXT_PUBLIC_`
## 、上线前检查
## 、上线前检查
Vercel 部署前至少确认:
@@ -146,8 +166,9 @@ Vercel 部署前至少确认:
2. `frontend/.env.example` 和 Vercel Project Settings 中的实际值一致
3. GitHub Actions 中 `frontend-quality` 已通过
4. 如果启用鉴权,Supabase redirect URL 已包含前端域名
5. `GET /api/payments/config` 返回的是当前最新地址,而不是旧收款合约
## 、常见问题
## 、常见问题
### 1. 页面打开后 API 全部 500
@@ -175,4 +196,4 @@ POLYWEATHER_API_BASE_URL
NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID
```
这是钱包连接的必需项。
这是钱包连接的必需项。
+104
View File
@@ -0,0 +1,104 @@
# Ops 运营后台说明
最后更新:`2026-03-21`
## 1. 入口
前端入口:
- `https://polyweather-pro.vercel.app/ops`
## 2. 权限
`/ops` 的写接口由后端白名单控制:
```env
POLYWEATHER_OPS_ADMIN_EMAILS=yhrsc30@gmail.com
```
可配置多个邮箱,逗号分隔。
## 3. 当前能力
### 只读能力
- 系统健康
- SQLite / rollout / metrics 摘要
- 支付运行态
- 当前会员
- 周榜
- 支付异常单
### 写能力
- 手动补分
- 标记支付异常单“已处理”
## 4. 当前会员
会员列表来自:
1. `subscriptions` 中的有效订阅
2. 本地 `users` / `supabase_bindings`
3. 若本地缺邮箱或注册时间,再回补 Supabase Auth 用户信息
去重规则:
- 同一个 `user_id` 只保留最晚到期那条
## 5. 支付异常单
当前异常单来源:
- `payment_audit_events`
- 仅筛 `payment_intent_failed`
当前支持的典型失败原因:
- `receiver_mismatch`
- `sender_mismatch`
- `event_mismatch`
- `tx_reverted`
默认只显示未处理项。
## 6. 典型处理流程
### 6.1 钱已到账但没开订阅
先看 `/ops` 的支付异常单:
- 如果是 `receiver_mismatch`
- 优先判定为支付打到了旧收款地址
- 不是缓存问题
然后执行:
1.`payment_intents`
2.`payment_transactions`
3.`subscriptions`
4. 跑恢复脚本:
```bash
python scripts/reconcile_subscription_by_email.py --email <user_email>
```
如果仍然失败,再人工补订阅。
### 6.2 已人工处理
`/ops` 里直接点:
- `标记已处理`
这不会删除审计事件,只会给原事件写:
- `resolved_at`
- `resolved_by`
## 7. 备注
`/ops` 是运营后台最小版,不是完整 Admin 平台。当前目标是:
- 让会员、积分、支付事故、系统状态可查
- 让常见人工操作不必再直接写 SQL
+3 -3
View File
@@ -3,9 +3,9 @@
## 执行摘要
PolyWeather(仓库:`yangyuan-zhen/PolyWeather`)定位为**面向温度类结算预测市场(如 Polymarket 的温度结算合约)**的“生产级气象情报系统”,核心在于把多源天气观测/预报转化为**结算导向的概率桶(μ + bucket distribution**,并进一步映射到市场报价完成**错价扫描**;同时提供 Web 仪表盘与 Telegram Bot 两套交互入口,并包含 Polygon 链上 USDC/USDC.e 支付、自动补单与订阅/积分体系。项目 README 明确其“Open-Core”边界:仓库公开天气聚合、基础分析、看板、Bot、标准支付流程;生产私有部分包含商业风控、阈值与运营工具等。
从工程实现看,截至 `2026-03-20`,项目已经完成一轮明确的工程化收口:多源天气采集仍保持现有业务能力,同时已完成采集层与 Web API 大文件拆分、CI 质量门禁、配置分级(`.env.example` / `.env.secrets.example` / 中文部署文档)、EMOS/CRPS 校准链路、运行态状态与缓存向 SQLite 的渐进迁移,以及基础可观测性接口(`/healthz``/api/system/status``/metrics`)。
从工程实现看,截至 `2026-03-21`,项目已经完成一轮明确的工程化收口:多源天气采集仍保持现有业务能力,同时已完成采集层与 Web API 大文件拆分、CI 质量门禁、配置分级(`.env.example` / `.env.secrets.example` / 中文部署文档)、EMOS/CRPS 校准链路、运行态状态与缓存向 SQLite 的渐进迁移,以及基础可观测性接口(`/healthz``/api/system/status``/metrics`)。
这意味着报告里最初最突出的“工程地基缺失”问题,已经有一部分被关闭:`src/data_collection/weather_sources.py``web/app.py` 不再是原来的超大单文件;GitHub Actions 已覆盖 Python、前端和 Docker build;配置与密钥治理已成体系;运行态状态不再只能依赖 JSON/JSONL 文件;EMOS 也不再只是概念,而是进入了可训练、可评估、可 shadow、可门禁判断的阶段。
但项目仍处在“从可用走向稳态”的中段,而不是终局。当前真正的高优先级问题已收敛为三类:第一,**SQLite 迁移仍处于推荐的 dual 过渡模式**,线上真正切主读路径前仍需跑一段时间验证;第二,**可观测性只完成了轻量级指标层**,还没有形成完整的外部监控、阈值告警与趋势面板;第三,**EMOS 仍未达到生产切换标准**,当前门禁结论明确为 `hold`,阻塞原因是 shadow bucket brier 明显退化。支付链路方面,链下审计与容灾已明显增强:事件重放、SQLite 审计事件、RPC 多节点容灾、合约静态检查都已补齐;当前剩余风险主要集中在**链上合约本身仍是最小实现**,尚未升级到 SafeERC20、Pausable、链上套餐绑定等更强防护版本。
但项目仍处在“从可用走向稳态”的中段,而不是终局。当前真正的高优先级问题已收敛为三类:第一,**SQLite 迁移仍处于推荐的 dual 过渡模式**,线上真正切主读路径前仍需跑一段时间验证;第二,**可观测性只完成了轻量级指标层**,还没有形成完整的外部监控、阈值告警与趋势面板;第三,**EMOS 仍未达到生产切换标准**,当前门禁结论明确为 `hold`,阻塞原因是 shadow bucket brier 明显退化。支付链路方面,链下审计与容灾已明显增强:事件重放、SQLite 审计事件、RPC 多节点容灾、合约静态检查`/ops` 支付异常单、按邮箱恢复脚本都已补齐;当前剩余风险主要集中在**链上合约本身仍是最小实现**,尚未升级到 SafeERC20、Pausable、链上套餐绑定等更强防护版本。
因此,当前阶段最正确的策略已经不是继续做“大范围基础重构”,而是围绕**迁移验收、可观测性补全、EMOS 上线门禁稳定化**这三条线持续收口。短中期内更高 ROI 的方向依然不是引入新的大模型,而是把现有“采集→后处理→市场映射→支付/订阅”的链路做成**状态一致、指标可见、发布可控、回退明确**的生产平台。
## 项目概览
@@ -169,7 +169,7 @@ Web/Telegram 请求 → FastAPI 调用采集器抓取/复用缓存 → 分析引
**对标结论**PolyWeather 与这类“全球 AI 预报模型”不在同一层级:PolyWeather 是“面向结算市场的产品化情报系统”,其价值核心是**将预测转成可交易/可结算的决策信息**。短中期内更高 ROI 的方向不是“自训大模型”,而是把现有“采集+后处理+市场映射”的链路做成**可复现、可观测、可评测、可扩展**的工程平台;在许可合规前提下,再评估引入外部模型推理作为额外信号源。
## 优先级改进建议
下表按截至 `2026-03-20` 的真实状态重排优先级。已完成项不再继续列为“待做”,只保留当前仍需推进的事项。
下表按截至 `2026-03-21` 的真实状态重排优先级。已完成项不再继续列为“待做”,只保留当前仍需推进的事项。
| 优先级 | 改进项 | 预估工作量 | 主要收益 | 主要风险 | 可执行步骤(建议顺序) |
| ------ | --------------------------------------------------------------------------------------------------------------------------------- | -------------------: | ------------------------------------------------------------------- | ------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 高 | **完成 SQLite 迁移切换与验收**:从 `dual` 过渡到 `sqlite` 主读路径 | 25 天 | 真正关闭 JSON/JSONL 并发一致性风险;状态/缓存统一入库 | 迁移校验不充分会导致线上行为漂移 | 1) 线上部署新代码 → 2) 执行迁移与校验脚本 → 3) `dual` 运行至少 24–48 小时 → 4) 校验 `/api/history`、bot 告警、snapshot、缓存都正常 → 5) 再切 `POLYWEATHER_STATE_STORAGE_MODE=sqlite` |
+58 -1
View File
@@ -1,6 +1,6 @@
# PolyWeather 支付审计与防护说明
最后更新:`2026-03-20`
最后更新:`2026-03-21`
## 1. 当前已落地的防护
@@ -22,6 +22,14 @@
- 后端只认链上 `OrderPaid` 事件。
- 前端提交 intent 不会直接视为支付完成。
- `confirm_loop` 会再次按链上交易与确认数校验 intent。
- 若确认失败,当前会明确把 intent / transaction 落为失败态,而不是长期停留在 `submitted`
当前已显式识别的失败原因包括:
- `receiver_mismatch`
- `sender_mismatch`
- `event_mismatch`
- `tx_reverted`
### RPC 多节点容灾
@@ -63,6 +71,23 @@ python scripts/replay_payment_events.py --from-block 10000000 --to-block 1000100
- event loop 最新状态
- 最近审计事件
### Ops 事故单
现在 `/ops` 已提供单独的支付异常单列表,默认展示:
- `payment_intent_failed`
支持:
- 按 `reason` 过滤
- 标记已处理
这让下面这类事故不再需要翻日志定位:
- 已付款但未开通
- 打到旧收款地址
- 交易事件不匹配
## 2. 当前合约的授权边界
合约源码:
@@ -176,6 +201,38 @@ curl http://127.0.0.1:8000/api/payments/runtime
- `event_loop_state.last_scanned_block`
- `recent_audit_events`
如果你在 `/ops` 或脚本里看到:
- `receiver_mismatch`
其含义通常不是“缓存没刷新”,而是:
- 用户这笔交易的 `to` 地址不是当前生产收款合约
- 常见原因是旧页面、旧 deployment、旧钱包会话,或历史收款地址仍被命中
此时应优先做:
1. 确认链上真实 `to` 地址
2. 确认当前 `/api/payments/config` 返回的 `receiver_contract`
3. 如确已收款,再走人工恢复或补开订阅
### 按邮箱恢复最近支付
已提供脚本:
- [reconcile_subscription_by_email.py](/E:/web/PolyWeather/scripts/reconcile_subscription_by_email.py)
命令:
```bash
docker compose exec polyweather_web python scripts/reconcile_subscription_by_email.py --email user@example.com
```
适用场景:
- 用户声称已付费但未开通
- 需要快速确认最近一笔 intent 是否能自动恢复
## 7. 下一版合约建议
如果后续升级合约,优先级建议:
+45 -1
View File
@@ -100,6 +100,50 @@ NEXT_PUBLIC_TELEGRAM_BOT_URL=https://t.me/WeatherQuant_bot
- `POST /api/payments/intents/[intentId]/submit`
- `POST /api/payments/intents/[intentId]/confirm`
Ops
- `GET /ops`
- `GET /api/ops/users`
- `GET /api/ops/leaderboard/weekly`
- `GET /api/ops/memberships`
- `GET /api/ops/payments/incidents`
- `POST /api/ops/users/grant-points`
- `POST /api/ops/payments/incidents/[eventId]/resolve`
## Ops 管理后台
当前前端已内置轻量管理页:
- [https://polyweather-pro.vercel.app/ops](https://polyweather-pro.vercel.app/ops)
页面当前支持:
- 系统状态
- SQLite / rollout / 支付运行态
- 用户查询
- 当前会员
- 本周积分榜
- 手动补分
- 支付异常单筛选与标记已处理
注意:
- `/ops` 页面是否可写,取决于后端 `POLYWEATHER_OPS_ADMIN_EMAILS`
- 前端登录邮箱本身不会自动获得管理员权限
## 支付安全补充
为降低“旧页面/旧配置导致打到旧收款地址”的风险,支付区现在会:
1. 点击支付前重新请求 `/api/payments/config`
2. 若 `receiver_contract` 已更新,先切到最新地址
3. 若后端返回的 `tx_payload.to` 与最新地址不一致,直接阻断支付
这意味着:
- 旧标签页风险已明显降低
- 但支付地址变更后,仍建议在 Vercel 上 redeploy 当前 production,并清理明显过期 deployment
## 缓存行为
- `cities` / `summary` / `history``ETag + Cache-Control`
@@ -113,4 +157,4 @@ NEXT_PUBLIC_TELEGRAM_BOT_URL=https://t.me/WeatherQuant_bot
详见根目录策略文档:`docs/OPEN_CORE_POLICY.md`
最后更新:`2026-03-20`
最后更新:`2026-03-21`