diff --git a/FRONTEND_REDESIGN_REPORT.md b/FRONTEND_REDESIGN_REPORT.md index 5b64e2fa..6914ea8f 100644 --- a/FRONTEND_REDESIGN_REPORT.md +++ b/FRONTEND_REDESIGN_REPORT.md @@ -1,262 +1,137 @@ -# 前端重新设计完成报告 +# 前端交付与重构报告(2026-03-12) -## 概述 +## 1. 报告目的 -按照 `docs/images/demo_map.png` 的设计,已成功重新设计和实现了 PolyWeather 首页核心布局。 +本报告用于说明当前线上前端(`frontend/`)的真实实现状态,替代旧版“单次改版完成报告”。 -## 核心设计 +--- -### 三列布局架构 +## 2. 当前前端架构 -``` -┌─────────────────────────────────────────────────────────────┐ -│ 顶部导航栏 (高度: 48px) │ -├──────────────┬──────────────────────────────┬───────────────┤ -│ │ │ │ -│ 左侧边栏 │ 中央地图展示区 │ 右侧详情面板 │ -│ (宽: 192px)│ (Leaflet全球地图) │ (宽: 288px) │ -│ │ │ │ -│ • Logo │ • 全球地图视图 │ • 大温度显示 │ -│ • 搜索框 │ • 彩色圆形标记 │ • 观测信息 │ -│ • 城市列表 │ • 风险等级标色 │ • 小时趋势图 │ -│ • 温度显示 │ │ • 概率分布 │ -│ │ │ • 多模型预报 │ -│ │ │ • 多日预报 │ -└──────────────┴──────────────────────────────┴───────────────┘ +```mermaid +flowchart LR + B["Browser"] --> N["Next.js App Router (Vercel)"] + N --> RH["Route Handlers /api/*"] + RH --> F["FastAPI (VPS)"] + + N --> STORE["Dashboard Store"] + STORE --> MAP["MapCanvas"] + STORE --> SIDEBAR["CitySidebar"] + STORE --> PANEL["DetailPanel + Modal"] ``` -x +### 2.1 组件分层(实际) -## 实现细节 +- 页面入口:`frontend/app/page.tsx` + `frontend/components/dashboard/DashboardEntry.tsx` +- 核心容器:`frontend/components/dashboard/PolyWeatherDashboard.tsx` +- 主要视图: + - `MapCanvas.tsx` + - `CitySidebar.tsx` + - `DetailPanel.tsx` + - `FutureForecastModal.tsx` + - `HistoryModal.tsx` + - `GuideModal.tsx` +- 状态管理:`frontend/hooks/useDashboardStore.tsx` -### 1. 左侧城市列表面板 (192px) +--- -``` -功能: - • Logo 和标题: "PolyWeather" - • 搜索输入框: 搜索城市功能 - • 城市列表: - - 显示所有支持的城市 - - 当前温度显示 - - 风险等级颜色指示器 - - 活跃城市高亮显示 - - 可点击选择切换城市 +## 3. 本轮已落地能力 -样式: - - 背景: slate-900/50 - - 边框: slate-800 - - 活跃状态: cyan-500 高亮 - - 悬停效果: bg-slate-800/30 +### 3.1 侧栏风险分组折叠(已完成) + +- 按 `high / medium / low / other` 分组展示城市。 +- 分组支持折叠/展开。 +- 保留“本地时间”和“峰值时间”显示。 +- 折叠状态持久化到 `localStorage`(`polyWeather_sidebar_groups_v1`)。 + +### 3.2 选中城市状态持久化(已完成) + +- 最近一次选中城市持久化到 `localStorage`(`polyWeather_selected_city_v1`)。 +- 页面刷新后自动恢复。 + +### 3.3 未来日期分析与市场扫描(已完成) + +- 前端通过 `target_date` 调用 `/api/city/{name}/detail`。 +- 未来日期 modal 可展示对应日期的模型概率与市场扫描。 + +### 3.4 市场概率分布去重保护(已完成) + +- 后端温度桶去重后,前端仍保留兜底去重逻辑。 +- 避免“同温度重复四行”导致的可视化误导。 + +### 3.5 可访问性修复(已完成) + +- 解决详情侧栏关闭时 `aria-hidden` 焦点冲突。 +- 方案:`inert` + `activeElement.blur()`。 + +### 3.6 图标与性能观测(已完成) + +- 已接入 favicon/Apple touch icon/manifest。 +- 已集成 Vercel Speed Insights 与 Analytics。 + +--- + +## 4. 缓存与性能策略(当前状态) + +### 4.1 BFF HTTP 缓存(Vercel) + +- `/api/cities`:`ETag` + `s-maxage=300` +- `/api/city/{name}/summary`:`ETag` + `s-maxage=20` +- `/api/history/{name}`:`ETag` + `s-maxage=60` +- `summary?force_refresh=true`:`Cache-Control: no-store` + +### 4.2 前端本地缓存 + +- `sessionStorage`:城市详情缓存(5 分钟 TTL + revision 探测) +- 请求去重:并发请求合并(pending request map) +- `localStorage`:选中城市 + 侧栏折叠状态 + +### 4.3 当前明确未做 + +- Service Worker Cache API +- IndexedDB + +--- + +## 5. 验收记录 + +### 5.1 前端缓存验收脚本 + +```bash +./scripts/validate_frontend_cache.sh "https://polyweather-pro.vercel.app" ``` -### 2. 中央地图展示区 (Leaflet) +当前结果:`PASS (14 passed)`。 -``` -功能: - • Leaflet 全球地图 - • 动态缩放控制 - • 多个城市标记 +### 5.2 自动化测试 -标记样式: - • 圆形标记,半径 24px - • 显示当前温度(度数字) - • 颜色编码 (基于风险等级): - - 高风险: 红色 (#ef4444) - - 中风险: 橙色 (#f97316) - - 低风险: 绿色 (#10b981) - - 默认: 青色 (#06b6d4) - • 发光效果: box-shadow - • 点击弹窗显示详细信息 +```bash +.\\venv\\Scripts\\python.exe -m pytest -q ``` -### 3. 右侧详情面板 (288px) +当前结果:`31 passed`。 -#### a. 大温度显示区域 +--- -``` -┌─────────────────────────────────┐ -│ │ -│ 12.0°C │ -│ (文字大小: 3xl/48px) │ -│ (颜色: 青色 - cyan-400) │ -│ │ -│ 观测时间: 11°C @17:00 │ -│ │ -│ ┌────┬────┬────┐ │ -│ │Obs │DEB │Fcst│ │ -│ │1.0 │6.6 │5.9 │ (三列参考) │ -│ └────┴────┴────┘ │ -│ │ -└─────────────────────────────────┘ -``` +## 6. 风险与改进点 -#### b. 小时趋势图 +1. `frontend/.next` 构建产物在本地可见,需继续确保不进入版本管理。 +2. 前端缓存策略已覆盖 P0+P1,但离线能力仍未建设(无 SW/IndexedDB)。 +3. 多源数据仍依赖后端聚合延迟,前端仅能做缓存与降噪,不可替代后端刷新节奏。 -``` -简化的柱状图: - • 显示最近 12 小时的温度 - • 动态高度基于温度值 - • 渐变颜色: cyan-500 → cyan-400 - • 高度: 80px -``` +--- -#### c. 概率分布 +## 7. 结论 -``` -水平条形图: - • 显示温度概率分布 - • 显示前 3 个最高概率的温度范围 - • 动态条形宽度 - • 渐变背景: cyan-500 → emerald-500 -``` +当前前端已从“单体页面”演进为组件化 dashboard,具备: -#### d. 多模型预报 +- 风险分组侧栏与状态持久化 +- 未来日期分析与市场扫描联动 +- BFF 标准缓存头(`ETag/304`) +- 可访问性修复与基础性能观测 -``` -模型列表 (GFS, ECMWF, ICON, GEM, Open-Meteo, DEB): - • 每个模型显示一条横向进度条 - • 指示器显示预报值在范围内的位置 - • 显示精确温度值 - • 支持动态模型范围计算 -``` +可以支持继续推进商业化接入,但支付相关能力仍需后端与权限体系配套完成。 -#### e. 多日预报 +--- -``` -4 天预报卡片: - • 网格布局 (4列) - • 显示日期 (Day 0, Day 1, ...) - • 显示最高温度 - • 简洁的卡片设计 -``` - -## 颜色主题 - -### 暗色主题 (Dark Mode) - -``` -背景: - - 主背景: slate-950 (#030712) - - 面板背景: slate-900/50 - - 组件背景: slate-800/50 - -文本: - - 主文本: slate-200 - - 次文本: slate-400 - - 强调文本: cyan-400 (#06b6d4) - -边框: - - 主边框: slate-800 - - 次边框: slate-700/50 - -强调色: - - 主强调: cyan-400 (#06b6d4) - - 辅助强调: emerald-500 (#10b981) - - 警告: rose-500 (#ef4444) -``` - -## 文件变更 - -### 新建文件 - -1. **`frontend/components/dashboard/map-dashboard.tsx`** (新建) - - 核心三列布局组件 - - 城市列表、地图、详情面板的主容器 - - 包含所有数据处理和渲染逻辑 - -### 修改文件 - -1. **`frontend/app/page.tsx`** - - 重新设计,移除 `TerminalDashboard` - - 改用新的 `MapDashboard` 组件 - - 简化页面结构,减少代码冗余 - -2. **`frontend/components/dashboard/map-view.tsx`** - - 更新地图标记类型定义 - - 改用新的 `createTemperatureMarker` 标记样式 - - 适配新的数据结构 (`color`, `temp` 而非 `value`) - -## 技术实现 - -### 关键技术点 - -1. **动态导入 (Dynamic Import)** - - ```typescript - const MapView = dynamic(() => import("@/components/dashboard/map-view"), { - ssr: false, - loading: () =>
Loading map...
, - }); - ``` - - - 解决 Leaflet SSR 兼容性问题 - - 提高首屏加载性能 - -2. **响应式布局** - - Flex 布局实现三列设计 - - 固定宽度边栏 (192px, 288px) - - 弹性地图中央区域 - -3. **数据可视化** - - 柱状图 (hourly trend) - - 条形图 (probability, models) - - 网格布局 (daily forecast) - -4. **交互设计** - - 城市列表可点击切换 - - 地图标记可悬停显示信息 - - 搜索框输入过滤城市 - -## 性能优化 - -1. **编译状态** - ✅ 编译成功 - ✅ 没有 TypeScript 错误 - ✅ 没有构建警告 - -2. **打包大小** - - 首页大小: 8.29 kB - - 首屏 JS: 121 kB - - 支持静态预渲染 - -## 部署检查清单 - -- [x] 前端编译通过 -- [x] 无 TypeScript 错误 -- [x] 无构建警告 -- [x] SSR 兼容性解决 -- [x] 数据绑定就绪 -- [x] 响应式设计完成 -- [x] 颜色主题应用 -- [x] 交互功能实现 - -## 下一步工作 - -1. **数据集成** - - 从后端 API 动态获取所有城市数据 - - 实现实时数据更新 - -2. **城市级地图** - - 为每个城市添加多个测站标记 - - 显示周边观测点信息 - -3. **高级分析** - - 实现点击地图标记显示详细分析 - - 添加时间滑块用于历史数据回放 - -4. **市场数据集成** - - 在详情面板添加 Polymarket 市场信息 - - 显示市场价格和概率对比 - -## 总结 - -✅ **首页设计完全按照 `demo_map.png` 的风格重新实现** - -- 三列布局清晰分工 -- 暗色主题统一协调 -- 数据可视化专业美观 -- 交互流畅直观 -- 代码结构清晰可维护 -- 编译部署无误 - -前端现已准备就绪,可以与后端 API 进行数据集成测试。 +最后更新:`2026-03-12` diff --git a/README.md b/README.md index f15be849..5e3bdea4 100644 --- a/README.md +++ b/README.md @@ -14,121 +14,99 @@ Official dashboard: [polyweather-pro.vercel.app](https://polyweather-pro.vercel. ![PolyWeather Ankara analysis](docs/images/demo_ankara.png) -## What This Project Does +## Core Capabilities -- Aggregates weather observations and forecasts for monitored cities. -- Blends multi-model forecasts with DEB (Dynamic Error Balancing). -- Computes settlement-oriented probability buckets (mu-centered distribution). -- Maps model view to Polymarket read-only market data for mispricing/risk scan. -- Delivers the same core logic to web dashboard and Telegram bot. +- Aggregates real-time observations and forecasts for 20 monitored cities. +- Uses DEB (Dynamic Error Balancing) to blend multi-model highs. +- Produces settlement-oriented probability buckets (`mu` + bucket distribution). +- Maps weather model view to Polymarket read-only quotes for mispricing scan. +- Serves the same analysis core to web dashboard and Telegram bot. -## Overview Diagram +## Architecture (Current) + +```mermaid +flowchart LR + U["Users (Web / Telegram)"] --> FE["Next.js Frontend (Vercel)"] + U --> BOT["Telegram Bot (VPS)"] + FE --> API["FastAPI /web/app.py"] + BOT --> API + + API --> WX["Weather Collector"] + WX --> METAR["Aviation Weather (METAR)"] + WX --> MGM["MGM (Turkey station network)"] + WX --> OM["Open-Meteo"] + WX --> NWS["weather.gov (US cities)"] + + API --> ANALYSIS["DEB + Trend + Probability + Market Scan"] + ANALYSIS --> PM["Polymarket Read-only Layer"] +``` + +## Bot Runtime Layout ```mermaid flowchart TD - A["PolyWeather Pro"] - - subgraph DL["Data Layer"] - DL1["METAR (Aviation Weather / METAR)"] - DL2["MGM (Turkey MGM)"] - DL3["Station 17130 (Ankara Center 17130)"] - DL4["Open-Meteo"] - DL5["weather.gov (US cities)"] - DL6["Polymarket (P0 Read-only)"] - end - - subgraph AL["Analysis Layer"] - AL1["DEB (Dynamic Error Balancing)"] - AL2["Probability Engine (mu + buckets)"] - AL3["Trend Engine"] - AL4["Risk Profiles"] - AL5["Mispricing Radar"] - end - - subgraph DEL["Delivery Layer"] - DEL1["FastAPI"] - DEL2["Next.js Dashboard"] - DEL3["Telegram Bot"] - DEL4["Alert Push"] - end - - subgraph OL["Ops Layer"] - OL1["Docker Compose (VPS backend + bot)"] - OL2["Vercel (frontend)"] - OL3["Cache + force_refresh"] - OL4["Speed Insights"] - end - - A --> DL - A --> AL - A --> DEL - A --> OL + E["bot_listener.py"] --> O["src/bot/orchestrator.py"] + O --> H["src/bot/handlers/*"] + O --> S["src/bot/services/*"] + O --> A["src/bot/analysis/*"] + O --> G["src/bot/command_guard.py"] + O --> R["src/bot/runtime_coordinator.py"] ``` -## Architecture +## Source Policy -```mermaid -graph TD - User[Web / Telegram User] --> FE[Next.js Frontend on Vercel] - User --> Bot[Telegram Bot on VPS] - FE --> API[FastAPI Service] - Bot --> API +| Domain | Current Policy | +| :-- | :-- | +| Primary observation | Aviation Weather / METAR | +| Ankara enhancement | MGM + nearby stations, lead station fixed to `17130` | +| Forecast baseline | Open-Meteo + multi-model (ECMWF/GFS/ICON/GEM/JMA) | +| US official context | weather.gov | +| Market layer | Polymarket P0 read-only discovery + quotes | +| Removed source | Meteoblue (fully removed from runtime and docs) | - API --> WX[Weather Data Collector] - WX --> METAR[METAR / Aviation Weather] - WX --> MGM[MGM API / nearby stations] - WX --> OM[Open-Meteo] - WX --> NWS[weather.gov] +## Monitored Cities (20) - API --> DEB[DEB + Trend + Probability Engines] - API --> PM[Polymarket Read-only Layer] - PM --> Gamma[Gamma API] - PM --> CLOB[CLOB / py-clob-client] -``` +- Europe / Middle East: Ankara, London, Paris, Munich +- APAC: Seoul, Hong Kong, Shanghai, Singapore, Tokyo, Wellington +- Americas: Toronto, New York, Chicago, Dallas, Miami, Atlanta, Seattle, Buenos Aires, Sao Paulo +- South Asia: Lucknow -## Current Source Policy +## Major Updates (2026-03-12) -| Domain | Source Policy | -| :------------------ | :--------------------------------------------------- | -| Primary observation | Aviation Weather / METAR | -| Ankara enhancement | MGM + nearby stations, lead station fixed to `17130` | -| Forecast baseline | Open-Meteo | -| US official context | weather.gov | -| Market layer | Polymarket P0 read-only discovery + quotes | -| Removed source | Meteoblue (fully removed from code and docs) | +1. Bot architecture refactor completed: + - `bot_listener.py` is now a thin entrypoint. + - Core runtime moved to orchestrator + handlers/services/analysis layers. + - Startup loops managed by `StartupCoordinator`, with `/diag` diagnostics. +2. Mispricing radar hardened: + - Anchor changed from single Open-Meteo settlement to multi-model highest-high anchor. + - Skip non-tradable markets (`closed`, inactive, not accepting orders, or past end time). + - Future-date scan supported via `target_date` in detail aggregate endpoint. +3. Wallet activity watcher upgraded: + - Wallet aliases (`POLYMARKET_WALLET_ACTIVITY_USER_ALIASES`) supported. + - Telegram link preview toggle (`POLYMARKET_WALLET_ACTIVITY_LINK_PREVIEW`) supported. + - Debounce + immediate delta push controls reduce noisy spam bursts. +4. Frontend P0+P1 cache and UX improvements: + - BFF `ETag + 304` on `/api/cities`, `/api/city/{name}/summary`, `/api/history/{name}`. + - `force_refresh=true` on summary keeps `Cache-Control: no-store`. + - `sessionStorage` city-detail cache + background summary revision probe. + - `localStorage` persistence for selected city and risk-group collapse state. + - Detail panel accessibility fix (`inert` + active-element blur). +5. Observability: + - Vercel Speed Insights integrated. + - Telegram alert/watcher startup diagnostics exposed through `/diag`. -## Recent Changes (2026-03-12) +## Repository Layout -- Removed all Meteoblue API integration and references. -- Added frontend BFF `ETag + Cache-Control` for: - - `/api/cities` - - `/api/city/{name}/summary` (`force_refresh=true` keeps `no-store`) - - `/api/history/{name}` -- Added frontend state persistence: - - selected city in `localStorage` - - risk-group collapse state in sidebar `localStorage` - - background summary revision check to silently refresh stale detail cache -- Mispricing radar safety hardening: - - skip non-tradable markets (`closed`, inactive, not accepting orders, or past `endDate`) - - propagate tradable state in `market_scan.primary_market` -- AI decision guard: - - peak-window state (`before` / `in_window` / `past`) now explicitly injected into AI context - - before-peak state now forbids "locked/confirmed floor" style conclusions -- Fixed market top-bucket rendering path by deduplicating repeated temperature buckets. -- Added frontend fallback guard when market top buckets collapse to low-quality duplicates. -- Fixed detail panel accessibility issue (`aria-hidden` focus conflict) using `inert` + active-element blur. -- Added Vercel Speed Insights integration in `frontend/app/layout.tsx`. - -## Repositories and Runtime Paths - -- Frontend: `frontend/` (Next.js App Router) -- Backend API: `web/app.py` and `src/` -- Telegram runtime: `bot_listener.py` + `src/analysis/*` +- Frontend: `frontend/` +- Backend API: `web/app.py`, `src/` +- Telegram bot runtime: `bot_listener.py`, `src/bot/*` +- Wallet watchers: `src/onchain/*` +- Ops scripts: `scripts/` - Docs: `docs/` ## Quick Start -### Backend + Bot (VPS / Docker) +### Backend + Bot (Docker) ```bash docker compose up -d --build @@ -142,14 +120,14 @@ npm install npm run dev ``` -### Frontend production build check +### Frontend production build ```bash cd frontend npm run build ``` -## Operations Verification +## Ops Verification ### Validate frontend cache headers (`ETag` / `304` / `force_refresh=no-store`) @@ -157,31 +135,46 @@ npm run build ./scripts/validate_frontend_cache.sh "https://polyweather-pro.vercel.app" ``` -### Watch mispricing radar push decisions +### Watch mispricing radar decisions ```bash docker compose logs -f polyweather | egrep "market not tradable|trade alert pushed|mispricing cap" ``` -## Command Surface (Telegram) +### Watch wallet activity watcher startup and pushes -| Command | Purpose | -| :------------- | :---------------------------- | -| `/city ` | City real-time analysis | -| `/deb ` | DEB historical reconciliation | -| `/top` | User leaderboard | -| `/help` | Help and command usage | +```bash +docker compose logs -f polyweather | egrep "wallet activity watcher started|wallet activity pushed|wallet activity cycle failed" +``` + +### Check bot startup diagnosis in Telegram + +```text +/diag +``` + +## Telegram Command Surface + +| Command | Purpose | +| :-- | :-- | +| `/city ` | City real-time analysis | +| `/deb ` | DEB historical reconciliation | +| `/top` | User leaderboard | +| `/id` | Show current chat ID | +| `/diag` | Bot startup diagnostics and loop status | +| `/help` | Help and usage | ## Documentation Index +- Chinese overview: `README_ZH.md` - Chinese API guide: `docs/API_ZH.md` - Commercial roadmap: `docs/COMMERCIALIZATION.md` - Tech debt (EN): `docs/TECH_DEBT.md` - Tech debt (ZH): `docs/TECH_DEBT_ZH.md` -- Chinese overview: `README_ZH.md` +- Frontend delivery report: `FRONTEND_REDESIGN_REPORT.md` ## Status - Version: `v1.3` +- Test status: `31 passed` (`.\\venv\\Scripts\\python.exe -m pytest -q`) - Last Updated: `2026-03-12` -- Runtime: Stable (web + bot + market read-only layer in production) diff --git a/README_ZH.md b/README_ZH.md index 9d42f085..8492be95 100644 --- a/README_ZH.md +++ b/README_ZH.md @@ -14,120 +14,99 @@ ![PolyWeather Ankara 分析页](docs/images/demo_ankara.png) -## 这个项目在做什么 +## 核心能力 -- 聚合监控城市的实测与预报数据。 -- 用 DEB(Dynamic Error Balancing)做动态融合预测。 -- 计算结算导向的温度概率分布(`μ` + 温度桶)。 -- 将模型概率与 Polymarket 只读市场数据对齐,输出错价/风险信号。 -- Web 仪表盘与 Telegram 机器人共用同一套核心逻辑。 +- 聚合 20 个监控城市的实时实测与预报数据。 +- 通过 DEB(Dynamic Error Balancing)融合多模型最高温。 +- 输出结算导向的概率分布(`mu` + 温度桶)。 +- 将模型观点映射到 Polymarket 只读市场,做错价扫描。 +- Web 仪表盘与 Telegram 机器人复用同一套分析内核。 -## 概览图 +## 当前架构 + +```mermaid +flowchart LR + U["用户(Web / Telegram)"] --> FE["Next.js 前端(Vercel)"] + U --> BOT["Telegram Bot(VPS)"] + FE --> API["FastAPI /web/app.py"] + BOT --> API + + API --> WX["Weather Collector"] + WX --> METAR["Aviation Weather(METAR)"] + WX --> MGM["MGM(土耳其站网)"] + WX --> OM["Open-Meteo"] + WX --> NWS["weather.gov(美国城市)"] + + API --> ANALYSIS["DEB + 趋势 + 概率 + 市场扫描"] + ANALYSIS --> PM["Polymarket 只读层"] +``` + +## Bot 运行分层 ```mermaid flowchart TD - A["PolyWeather Pro"] - - subgraph DL["数据层"] - DL1["METAR (Aviation Weather / METAR)"] - DL2["MGM (土耳其 MGM)"] - DL3["安卡拉主站 (17130 Center)"] - DL4["Open-Meteo"] - DL5["weather.gov (美国城市)"] - DL6["Polymarket (P0 只读)"] - end - - subgraph AL["分析层"] - AL1["DEB (动态误差平衡)"] - AL2["概率引擎 (mu + 桶分布)"] - AL3["趋势引擎"] - AL4["城市风险档案"] - AL5["错价雷达"] - end - - subgraph DEL["交付层"] - DEL1["FastAPI"] - DEL2["Next.js 仪表盘"] - DEL3["Telegram Bot"] - DEL4["预警推送"] - end - - subgraph OL["运维层"] - OL1["Docker Compose (VPS)"] - OL2["Vercel (前端)"] - OL3["缓存 + force_refresh"] - OL4["Speed Insights"] - end - - A --> DL - A --> AL - A --> DEL - A --> OL + E["bot_listener.py"] --> O["src/bot/orchestrator.py"] + O --> H["src/bot/handlers/*"] + O --> S["src/bot/services/*"] + O --> A["src/bot/analysis/*"] + O --> G["src/bot/command_guard.py"] + O --> R["src/bot/runtime_coordinator.py"] ``` -## 系统架构 +## 数据源口径 -```mermaid -graph TD - User[Web / Telegram 用户] --> FE[Vercel Next.js 前端] - User --> Bot[VPS Telegram Bot] - FE --> API[FastAPI 服务] - Bot --> API +| 领域 | 当前口径 | +| :-- | :-- | +| 主观测源 | Aviation Weather / METAR | +| Ankara 增强 | MGM + 周边站,领先站固定 `17130` | +| 预报基线 | Open-Meteo + 多模型(ECMWF/GFS/ICON/GEM/JMA) | +| 美国官方语义层 | weather.gov | +| 市场层 | Polymarket P0 只读发现 + 报价 | +| 已移除 | Meteoblue(代码与文档已彻底移除) | - API --> WX[Weather Collector] - WX --> METAR[METAR / Aviation Weather] - WX --> MGM[MGM API / 周边站] - WX --> OM[Open-Meteo] - WX --> NWS[weather.gov] +## 监控城市(20) - API --> DEB[DEB + 趋势 + 概率引擎] - API --> PM[Polymarket 只读层] - PM --> Gamma[Gamma API] - PM --> CLOB[CLOB / py-clob-client] -``` +- 欧洲/中东:Ankara、London、Paris、Munich +- 亚太:Seoul、Hong Kong、Shanghai、Singapore、Tokyo、Wellington +- 美洲:Toronto、New York、Chicago、Dallas、Miami、Atlanta、Seattle、Buenos Aires、Sao Paulo +- 南亚:Lucknow -## 当前数据源口径 +## 本轮主要更新(2026-03-12) -| 领域 | 当前口径 | -| :------------- | :-------------------------------- | -| 主观测源 | Aviation Weather / METAR | -| Ankara 增强 | MGM + 周边站,领先站固定 `17130` | -| 预报基线 | Open-Meteo | -| 美国官方语义层 | weather.gov | -| 市场层 | Polymarket P0 只读发现 + 报价 | -| 已移除 | Meteoblue(代码与文档已全部移除) | - -## 最近更新(2026-03-12) - -- 完整移除 Meteoblue API 及全部引用。 -- 前端 BFF 增加 `ETag + Cache-Control`: - - `/api/cities` - - `/api/city/{name}/summary`(`force_refresh=true` 仍保持 `no-store`) - - `/api/history/{name}` -- 前端状态持久化优化: - - 记住上次选中城市(`localStorage`) - - 记住侧边栏风险分组折叠状态(`localStorage`) - - 详情命中缓存时做后台 revision 检查,静默更新陈旧数据 -- 错价雷达安全加固: - - 市场 `closed` / 不活跃 / 不接受下单 / 超过 `endDate` 时跳过推送 - - `market_scan.primary_market` 透传可交易状态字段 -- AI 决策时段约束: - - 上下文显式注入峰值窗口状态(`before` / `in_window` / `past`) - - 峰值窗口前禁止“已锁定/已确认底线”结论 -- 修复市场“最热温度桶”重复温度刷屏问题(后端按温度去重 + 前端兜底去重)。 -- 修复详情面板可访问性告警(`aria-hidden` 焦点冲突),改为 `inert + blur`。 -- 集成 Vercel Speed Insights(`frontend/app/layout.tsx`)。 +1. Bot 分层改造完成: + - `bot_listener.py` 变为极薄入口。 + - 运行时迁移到 orchestrator + handlers/services/analysis 分层。 + - 启动循环由 `StartupCoordinator` 统一编排,并通过 `/diag` 暴露诊断。 +2. 错价雷达口径升级: + - 锚点从“单一 Open-Meteo 结算”改为“多模型最高温锚点”。 + - 不可交易市场硬拦截(`closed` / inactive / 不接单 / 过结束时间)。 + - 未来日期分析支持 `target_date`(聚合详情接口)。 +3. 钱包异动监听升级: + - 支持钱包昵称映射(`POLYMARKET_WALLET_ACTIVITY_USER_ALIASES`)。 + - 支持 Telegram 链接预览开关(`POLYMARKET_WALLET_ACTIVITY_LINK_PREVIEW`)。 + - 增加 debounce + 立即推送控制,减少连续下单刷屏。 +4. 前端 P0+P1 缓存与体验优化: + - BFF 在 `/api/cities`、`/api/city/{name}/summary`、`/api/history/{name}` 返回 `ETag + 304`。 + - `summary?force_refresh=true` 保持 `Cache-Control: no-store`。 + - `sessionStorage` 详情缓存 + 后台 revision 静默探测。 + - `localStorage` 持久化“选中城市”和“风险分组折叠状态”。 + - 详情面板可访问性修复(`inert + active-element blur`)。 +5. 可观测性: + - 前端集成 Vercel Speed Insights。 + - Bot 启动和后台循环状态可通过 `/diag` 查看。 ## 目录说明 -- 前端:`frontend/`(Next.js App Router) -- 后端:`web/app.py` 与 `src/` -- 机器人:`bot_listener.py` + `src/analysis/*` +- 前端:`frontend/` +- 后端 API:`web/app.py`、`src/` +- Telegram 机器人:`bot_listener.py`、`src/bot/*` +- 钱包监听:`src/onchain/*` +- 运维脚本:`scripts/` - 文档:`docs/` ## 快速启动 -### 后端 + 机器人(VPS / Docker) +### 后端 + Bot(Docker) ```bash docker compose up -d --build @@ -141,7 +120,7 @@ npm install npm run dev ``` -### 前端构建校验 +### 前端生产构建 ```bash cd frontend @@ -150,37 +129,52 @@ npm run build ## 运维验收 -### 验证前端缓存头(`ETag` / `304` / `force_refresh=no-store`) +### 校验前端缓存头(`ETag` / `304` / `force_refresh=no-store`) ```bash ./scripts/validate_frontend_cache.sh "https://polyweather-pro.vercel.app" ``` -### 观察错价雷达推送决策日志 +### 观察错价雷达决策日志 ```bash docker compose logs -f polyweather | egrep "market not tradable|trade alert pushed|mispricing cap" ``` -## Telegram 命令 +### 观察钱包异动监听日志 -| 命令 | 用途 | -| :------------- | :----------- | +```bash +docker compose logs -f polyweather | egrep "wallet activity watcher started|wallet activity pushed|wallet activity cycle failed" +``` + +### Telegram 启动诊断 + +```text +/diag +``` + +## Telegram 指令面 + +| 指令 | 用途 | +| :-- | :-- | | `/city ` | 城市实时分析 | -| `/deb ` | DEB 历史对账 | -| `/top` | 用户排行榜 | -| `/help` | 帮助说明 | +| `/deb ` | DEB 历史对账 | +| `/top` | 用户积分排行 | +| `/id` | 查看当前聊天 Chat ID | +| `/diag` | Bot 启动诊断与后台循环状态 | +| `/help` | 帮助与用法 | ## 文档索引 +- 英文总览:`README.md` - API 文档(中文):`docs/API_ZH.md` - 商业化路线:`docs/COMMERCIALIZATION.md` - 技术债(英文):`docs/TECH_DEBT.md` - 技术债(中文):`docs/TECH_DEBT_ZH.md` -- 英文总览:`README.md` +- 前端交付报告:`FRONTEND_REDESIGN_REPORT.md` ## 当前状态 - 版本:`v1.3` +- 测试状态:`31 passed`(`.\\venv\\Scripts\\python.exe -m pytest -q`) - 最后更新:`2026-03-12` -- 状态:稳定运行(Web + Bot + 市场只读层) diff --git a/docs/API_ZH.md b/docs/API_ZH.md index e295940a..24cf35c9 100644 --- a/docs/API_ZH.md +++ b/docs/API_ZH.md @@ -1,130 +1,90 @@ # PolyWeather API 文档(v1.3) -本文档描述当前后端真实可用接口(`web/app.py`)。 -前端一般通过 Next.js BFF 路由代理访问这些接口。 +本文档基于当前代码(`web/app.py` + `frontend/app/api/*`)整理。 +前端默认通过 Next.js BFF 路由访问后端。 --- ## 1. 基础信息 -- 本地地址:`http://127.0.0.1:8000` -- 生产地址:`http://:8000` 或你绑定的 HTTPS 域名 +- 后端直连:`http://127.0.0.1:8000` +- 前端 BFF:`https://polyweather-pro.vercel.app/api/*` - 返回格式:`application/json` -- 缓存策略: - - 后端分析缓存:默认 5 分钟(Ankara 特殊口径 60 秒) - - 前端详情缓存:5 分钟 + revision 检查 + 后台静默刷新 - - 前端 BFF HTTP 缓存(Vercel 层): - - `/api/cities`:`ETag` + `Cache-Control`(`s-maxage=300`) - - `/api/city/{name}/summary`:`ETag` + `Cache-Control`(`s-maxage=20`) - - `/api/history/{name}`:`ETag` + `Cache-Control`(`s-maxage=60`) - - `summary?force_refresh=true`:`Cache-Control: no-store` - - 手动刷新:`force_refresh=true` 强制绕过缓存 +- 口径说明: + - 结算导向分析以温度最高值和温度桶概率为核心。 + - Ankara 增强使用 MGM,主站固定 `17130`。 + - Meteoblue 已移除,不再出现在任何有效字段中。 --- -## 2. API 思维导图 +## 2. 请求链路 ```mermaid -flowchart TD - A["PolyWeather API"] - - subgraph E["接口分组"] - E1["GET /api/cities"] - E2["GET /api/city/{name}"] - E3["GET /api/city/{name}/summary"] - E4["GET /api/city/{name}/detail"] - E5["GET /api/history/{name}"] - end - - subgraph O["关键对象"] - O1["current"] - O2["forecast"] - O3["probabilities (mu + distribution)"] - O4["multi_model / multi_model_daily"] - O5["market_scan (P0 只读)"] - end - - A --> E - A --> O +flowchart LR + FE["Browser / Dashboard"] --> BFF["Next.js Route Handlers (/api/*)"] + BFF --> API["FastAPI (/web/app.py)"] + API --> WX["Weather Collector"] + API --> ANA["DEB + Trend + Probabilities + Market Scan"] + ANA --> PM["Polymarket Read-only Layer"] ``` --- ## 3. 接口总览 -| 接口 | 方法 | 用途 | -| :------------------------- | :--- | :------------------------------------ | -| `/api/cities` | GET | 城市清单与地图基础信息 | -| `/api/city/{name}` | GET | 城市主分析数据(侧栏/今日分析主来源) | -| `/api/city/{name}/summary` | GET | 轻量摘要(首屏预热/低开销更新) | -| `/api/city/{name}/detail` | GET | 聚合详情 + Polymarket P0 只读市场层 | -| `/api/history/{name}` | GET | 历史对账数据 | +| 接口 | 方法 | 用途 | +| :-- | :-- | :-- | +| `/api/cities` | GET | 监控城市列表(地图/侧栏) | +| `/api/city/{name}` | GET | 城市主分析(今日分析核心数据) | +| `/api/city/{name}/summary` | GET | 轻量摘要(首屏预热/低成本轮询) | +| `/api/city/{name}/detail` | GET | 聚合详情(含 `market_scan`) | +| `/api/history/{name}` | GET | 历史对账数据 | --- -## 4. 关键接口详解 +## 4. 关键接口说明 ### 4.1 `GET /api/cities` -返回监控城市列表(地图 Marker 与侧边栏基础数据)。 +返回监控城市清单。 -示例: +关键字段: -```json -{ - "cities": [ - { - "name": "ankara", - "display_name": "Ankara", - "lat": 39.9334, - "lon": 32.8597, - "risk_level": "medium", - "risk_emoji": "🟠", - "airport": "Esenboğa", - "icao": "LTAC", - "temp_unit": "celsius", - "is_major": true - } - ] -} -``` +- `name`, `display_name` +- `lat`, `lon` +- `risk_level`, `risk_emoji` +- `airport`, `icao` +- `temp_unit`(`celsius` / `fahrenheit`) ### 4.2 `GET /api/city/{name}` -主数据接口,前端详情面板和今日分析最常用。 +主分析接口,返回当前实况、预报、概率、趋势、AI 分析等。 可选参数: - `force_refresh=true|false` -核心字段: +关键字段: -- `name`, `display_name`, `local_date`, `local_time`, `temp_symbol` -- `risk` -- `current` -- `forecast` +- `current`(温度、今日最高、METAR 观测时间、原始 METAR) +- `forecast`(今日及多日高温、日出日落、日照时长) - `mgm`, `mgm_nearby` - `multi_model`, `multi_model_daily` -- `deb` -- `ensemble` +- `deb`, `ensemble` - `probabilities`(`mu` + `distribution`) - `trend`, `peak` - `hourly`, `hourly_next_48h` -- `source_forecasts`(当前只保留 `weather_gov`) -- `market_scan` -- `updated_at` - -说明: - -- `current.raw_metar` 是原始 METAR 报文。 -- Ankara 专项增强使用 MGM 站网,领先站固定 `17130`。 -- Meteoblue 已彻底移除,不再出现在接口字段中。 +- `source_forecasts.weather_gov` ### 4.3 `GET /api/city/{name}/summary` -轻量温度摘要,用于地图首屏预热和低成本刷新。 +轻量摘要接口,适合高频刷新列表。 -典型字段: +可选参数: + +- `force_refresh=true|false` + +关键字段: - `name`, `display_name`, `icao` - `local_time`, `temp_symbol` @@ -133,21 +93,17 @@ flowchart TD - `risk.level`, `risk.warning` - `updated_at` -缓存说明: - -- 通过前端 BFF 访问时,默认返回 `ETag` 与可缓存 `Cache-Control`。 -- 当 `force_refresh=true` 时,BFF 强制 `no-store`,用于人工排障与即时刷新。 - ### 4.4 `GET /api/city/{name}/detail` -聚合视图接口,包含天气分析和市场只读层。 +聚合详情接口,市场分析与未来日期分析都依赖该接口。 可选参数: - `force_refresh=true|false` -- `market_slug=`(调试/定向市场匹配) +- `market_slug=` +- `target_date=YYYY-MM-DD` -关键结构: +关键返回块: - `overview` - `official` @@ -158,133 +114,112 @@ flowchart TD - `risk` - `ai_analysis` -`market_scan`(P0 只读)重点字段: +`market_scan` 重点字段: -- `primary_market`, `selected_condition_id`, `selected_slug` -- `yes_token`, `no_token` +- `available`, `selected_date`, `selected_slug`, `signal_label` - `yes_buy`, `yes_sell`, `no_buy`, `no_sell` -- `market_price`, `model_probability`, `edge_percent` -- `temperature_bucket` -- `top_buckets`(前端展示前会再去重) -- `signal_label`(`BUY YES` / `BUY NO` / `MONITOR`) -- `websocket.asset_ids`, `websocket.condition_ids`(订阅标识,不涉及下单) -- `primary_market.tradable`(是否可交易) -- `primary_market.tradable_reason`(不可交易原因) -- `primary_market.ended_at_utc`(UTC 结束时刻) -- `primary_market.accepting_orders`(是否仍接收订单) +- `temperature_bucket`, `forecast_bucket`, `top_buckets` +- `anchor_model`, `anchor_high`, `anchor_settlement` +- `open_meteo_settlement`(兼容旧字段,当前与 `anchor_settlement` 同值) +- `primary_market.tradable`, `primary_market.tradable_reason` +- `primary_market.accepting_orders`, `primary_market.ended_at_utc` -注意: +说明: -- 后端已做温度桶去重与方向优先(优先与主市场同方向的 `or higher`/`or lower` 桶)。 -- 前端还有二次去重兜底,避免重复温度桶刷屏。 -- 错价雷达推送前会二次校验交易状态,若市场已不可交易(`closed` / inactive / 不接单 / 过 `endDate`)会跳过。 +- 当前错价锚点不是单一 Open-Meteo,而是“多模型最高温锚点”。 +- 推送层会再次校验市场可交易性,不可交易市场会跳过。 ### 4.5 `GET /api/history/{name}` -历史对账数据来源。 +历史对账接口。 -示例: +关键字段: -```json -{ - "history": [ - { - "date": "2026-03-07", - "actual": 7.0, - "deb": 6.5, - "mu": 7.2, - "mgm": 8.0 - } - ] -} +- `date` +- `actual` +- `deb` +- `mu` +- `mgm` + +--- + +## 5. 缓存与刷新策略(当前已实现) + +### 5.1 FastAPI 后端缓存 + +- `_analyze` 结果内存缓存:默认 5 分钟 +- Ankara 特例:60 秒 +- `force_refresh=true`:绕过后端缓存 + +### 5.2 Next.js BFF HTTP 缓存(Vercel) + +- `GET /api/cities` + - `ETag` + - `Cache-Control: public, max-age=0, s-maxage=300, stale-while-revalidate=1800` +- `GET /api/city/{name}/summary` + - `ETag` + - `Cache-Control: public, max-age=0, s-maxage=20, stale-while-revalidate=60` +- `GET /api/history/{name}` + - `ETag` + - `Cache-Control: public, max-age=0, s-maxage=60, stale-while-revalidate=300` +- `summary?force_refresh=true` + - `Cache-Control: no-store` + +### 5.3 前端本地缓存 + +- `sessionStorage` + - 城市详情缓存(5 分钟 TTL + revision 探测) +- `localStorage` + - 上次选中城市 + - 侧栏风险分组折叠状态 + +### 5.4 尚未引入(当前明确未做) + +- Service Worker Cache API +- IndexedDB + +--- + +## 6. 常用调试示例 + +### 6.1 查询未来日期 `market_scan` + +```bash +curl -s "http://127.0.0.1:8000/api/city/ankara/detail?force_refresh=true&target_date=2026-03-12" \ +| python3 -c "import sys,json; m=json.load(sys.stdin).get('market_scan',{}); print({k:m.get(k) for k in ['available','selected_date','anchor_model','anchor_high','anchor_settlement','yes_buy','no_buy']})" ``` ---- - -## 5. 请求链路(以 `/api/city/{name}` 为例) - -```mermaid -sequenceDiagram - participant FE as Frontend - participant API as FastAPI - participant WX as Weather Collector - participant PM as Polymarket RO Layer - - FE->>API: GET /api/city/{name}?force_refresh=... - API->>WX: fetch_all_sources(city) - WX-->>API: METAR / MGM / Open-Meteo / weather.gov / Multi-model - API->>API: DEB + trend + probability - API->>PM: build_market_scan(...) - PM-->>API: market_scan (read-only) - API-->>FE: merged city payload -``` - ---- - -## 6. 数据口径 - -### 6.1 主观测 - -- Aviation Weather / METAR 是全局主观测源。 -- Ankara:结算主站仍是 `LTAC`,领先信号强化使用 MGM(`17130`)。 - -### 6.2 预测源 - -- Open-Meteo -- weather.gov(美国城市) -- 多模型:ECMWF / GFS / ICON / GEM / JMA - -### 6.3 概率口径 - -- `mu`:动态分布中心,不是固定结算值。 -- `distribution`:按温度桶输出概率分布,面向结算决策而非通用天气展示。 - ---- - -## 7. 常见问题 - -### 7.1 接口 500 - -- 先检查容器是否启动:`docker compose ps` -- 查看日志:`docker compose logs -f polyweather_web` - -### 7.2 METAR 看起来“延迟” - -优先核对: - -- `current.obs_time` -- `current.report_time` -- `current.receipt_time` - -通常是上游发布节奏,不一定是本地轮询问题。 - -### 7.3 前端仍显示旧内容 - -- 确认 Vercel 已部署最新构建 -- 浏览器强刷(`Ctrl+F5`) -- 检查是否命中前端 5 分钟 TTL - -### 7.4 为什么 VPS `:8000` 看不到 `ETag`? - -- `:8000` 是 FastAPI 后端直连口径,主要负责分析与数据聚合。 -- `ETag/304` 主要由前端 BFF 路由返回(Vercel 域名下的 `/api/*`)。 -- 验证缓存头请用前端域名,而不是后端直连 IP。 - ---- - -## 8. 验收脚本 - -项目内置缓存验收脚本: +### 6.2 验证前端缓存头 ```bash ./scripts/validate_frontend_cache.sh "https://polyweather-pro.vercel.app" ``` -输出 `Result: PASS` 代表以下链路均正常: +### 6.3 观察错价雷达跳过原因 -- `ETag` 返回 -- `If-None-Match -> 304` -- `force_refresh=true -> no-store` +```bash +docker compose logs -f polyweather | egrep "market not tradable|trade alert pushed|mispricing cap" +``` + +--- + +## 7. 常见问题 + +### 7.1 VPS `:8000` 为什么看不到 `ETag`? + +- `:8000` 是 FastAPI 直连层,主要负责聚合分析。 +- `ETag/304` 在前端 BFF(Vercel 的 `/api/*`)侧实现。 + +### 7.2 为什么 `target_date` 有时没有市场价格? + +- 该日期可能没有可交易市场。 +- 或目标桶在市场里无可用报价(`yes_buy/no_buy` 缺失)。 +- 可先看 `market_scan.available` 与 `primary_market.tradable`。 + +### 7.3 如何确认 Bot 后台循环是否启动? + +- Telegram 里发送 `/diag`。 +- 查看三类循环状态:错价雷达、Polygon 钱包监听、Polymarket 钱包异动监听。 --- diff --git a/docs/COMMERCIALIZATION.md b/docs/COMMERCIALIZATION.md index 2bccc06b..9563b826 100644 --- a/docs/COMMERCIALIZATION.md +++ b/docs/COMMERCIALIZATION.md @@ -6,115 +6,113 @@ Target: make PolyWeather a sustainable paid weather-intelligence product. ## 1. Product Positioning -PolyWeather is not a generic weather app. -It is a decision-support layer for temperature-settlement markets: +PolyWeather is not a generic weather app. It is a settlement decision layer for temperature markets: - observation-first (METAR/MGM), -- settlement-aware probability modeling (DEB + mu/buckets), -- market mapping (Polymarket read-only) for actionable edge detection. +- settlement-aware modeling (DEB + mu/buckets), +- market mapping (Polymarket read-only) for actionable mispricing checks. --- -## 2. Business Overview Diagram +## 2. Current Monetization Readiness (2026-03-12) + +| Capability | Status | Notes | +| :-- | :-- | :-- | +| Frontend entitlement gate | Implemented | Next middleware supports token gate + session cookie | +| Backend entitlement guard | Implemented | `POLYWEATHER_REQUIRE_ENTITLEMENT` + backend token header | +| Bot command entitlement pre-hook | Implemented | `/city` and `/deb` can be protected (`POLYWEATHER_BOT_REQUIRE_ENTITLEMENT`) | +| Payment event ingestion | Not implemented | No automated USDC payment reconciliation yet | +| Subscriber persistence | Not implemented | Still missing managed subscriber DB | +| Self-serve billing UI | Not implemented | No user billing center yet | + +--- + +## 3. Access Model ```mermaid -flowchart TD - A["PolyWeather Monetization"] +flowchart LR + U["User"] --> FE["Frontend (Vercel)"] + FE --> MW["Entitlement Middleware"] + MW --> BFF["BFF /api/*"] + BFF --> API["FastAPI"] + API --> G["Backend Entitlement Guard"] - subgraph P["Product"] - P1["Telegram Signal Channel"] - P2["Web Dashboard"] - P3["VIP Bundle"] - end - - subgraph R["Pricing"] - R1["Entry 1 USD"] - R2["Dashboard 5 USD"] - R3["Bundle 5.5 USD"] - end - - subgraph AC["Access Control"] - AC1["Manual activation (P1)"] - AC2["Wallet/USDC detection (P2)"] - AC3["Entitlement middleware"] - end - - subgraph G["Growth"] - G1["Accuracy reports"] - G2["Retention analytics"] - G3["User preference center"] - end - - A --> P - A --> R - A --> AC - A --> G + P["Payment Source (USDC / Wallet)"] --> S["Subscriber State (to build)"] + S --> MW + S --> API ``` +### Do we need login/register to start charging? + +Short answer: **no for phase 1, yes for scale**. + +- Phase 1 can run with token/wallet-based entitlement and manual ops. +- For scale (self-serve renewals, refunds, support, analytics), account identity and subscriber DB become mandatory. + --- -## 3. Packaging and Pricing +## 4. Packaging and Pricing (Draft) -| Tier | Price | Value | -| :--------------- | :----------- | :---------------------------------------- | -| Telegram Channel | $1 / month | Low-noise proactive signal feed | -| Web Dashboard | $5 / month | Full multi-model context + reconciliation | -| VIP Bundle | $5.5 / month | Dashboard + signal stream | +| Tier | Price | Value | +| :-- | :-- | :-- | +| Telegram Signal Channel | $1 / month | Low-noise proactive signal stream | +| Web Dashboard | $5 / month | Full model context + historical reconciliation | +| VIP Bundle | $5.5 / month | Dashboard + signal stream | Payment direction: -- Currency: Polygon USDC -- Phasing: manual activation first, then automated entitlement sync +- Settlement/network: Polygon USDC +- Rollout: manual confirmation first, then automated entitlement sync --- -## 4. Execution Phases +## 5. Execution Phases -```mermaid -graph LR - P1[Phase 1 Manual Beta] --> P2[Phase 2 Payment Automation] - P2 --> P3[Phase 3 Growth and B2B] -``` +### Phase 1: Manual Paid Beta -### Phase 1: Manual Beta - -- Keep paid channel small, optimize signal quality first. -- Manual payment confirmation + manual entitlement grant. -- Invite-gated dashboard while access control hardens. +- Keep user set small and quality-focused. +- Manual payment confirmation + manual entitlement issue. +- Weekly accuracy report as trust anchor. ### Phase 2: Payment Automation -- Detect wallet payment events (USDC). -- Auto-issue/refresh entitlement. -- Enforce route-level and API-level access guards. +- Ingest payment events (wallet/tx). +- Auto-issue and auto-expire entitlement. +- Full parity across frontend middleware, backend API, and bot command guard. -### Phase 3: Growth and Expansion +### Phase 3: Growth and B2B -- Self-serve billing and subscription panel. -- Operator analytics and feature usage telemetry. -- Optional B2B API package for quant teams. +- Self-serve billing and subscriber console. +- Retention analytics and feature usage telemetry. +- Optional B2B/API package. --- -## 5. Technical Dependencies for Revenue +## 6. P0/P1 Commercial Engineering Backlog -| Dependency | Why it matters | -| :------------------- | :--------------------------------------------------------------- | -| Entitlement guard | Prevents unpaid dashboard/API access | -| Subscriber store | Persistent paid user state | -| Audit trail | Explains why each alert fired | -| Observability | Detects degradation before churn | -| Frontend performance | Impacts conversion and retention (Speed Insights now integrated) | +### P0 (before public paid launch) + +1. Subscriber store (managed PostgreSQL/Supabase) with entitlement expiry. +2. Payment event pipeline (idempotent ingest + reconciliation + retry). +3. Unified entitlement policy matrix (frontend/backend/bot). +4. Ops audit trail for alerts and entitlement changes. + +### P1 (after initial paid users) + +1. Billing/entitlement admin console. +2. User-level support tooling (manual override, extension, refund notes). +3. Conversion and retention dashboards. +4. Churn diagnostics linked to alert quality and latency. --- -## 6. Immediate Commercial Priorities +## 7. Commercial Risk Controls -1. Finish robust entitlement middleware in frontend and backend. -2. Persist subscriber/payment state in managed DB. -3. Publish transparent monthly accuracy and signal-quality reports. -4. Add support playbooks for false-alert and stale-data incidents. +- Revenue leakage: deny by default when entitlement token/state is missing. +- Signal quality drift: publish monthly transparent accuracy summary. +- Support load: keep alert evidence standardized in push payloads. +- Compliance/ops: preserve immutable entitlement and push logs. --- -Last Updated: `2026-03-11` +Last Updated: `2026-03-12` diff --git a/docs/TECH_DEBT.md b/docs/TECH_DEBT.md index 888411ce..29ef1e73 100644 --- a/docs/TECH_DEBT.md +++ b/docs/TECH_DEBT.md @@ -4,91 +4,90 @@ Purpose: keep engineering debt explicit while shipping production features. --- -## 1. Debt Landscape +## 1. Debt Snapshot + +Current estimate: **90% stable / 10% debt**. ```mermaid flowchart TD A["Tech Debt"] - subgraph AR["Architecture"] - AR1["Monolithic bot entry"] - AR2["Shared runtime coupling"] - end - - subgraph PI["Product Infra"] - PI1["Entitlement hardening"] - PI2["Subscription persistence"] + subgraph PI["Payment Infra"] + PI1["Payment event ingestion"] + PI2["Subscriber persistence"] + PI3["Entitlement parity"] end subgraph Q["Quality"] Q1["Replay harness"] - Q2["Broader regression tests"] + Q2["Mixed integration tests"] end subgraph O["Observability"] - O1["Alert evidence trace"] - O2["SLO dashboards"] + O1["Alert evidence schema"] + O2["Ops dashboards"] end - A --> AR A --> PI A --> Q A --> O ``` -Current system health estimate: **86% stable / 14% debt**. - --- ## 2. Recently Closed (2026-03-12) -- Meteoblue API path fully removed from backend, frontend, config and docs. -- Market top-bucket duplicate temperature issue fixed (backend dedupe + frontend guard). -- Detail panel a11y conflict fixed (`aria-hidden` focus conflict resolved with `inert` + blur). -- Vercel Speed Insights integrated for frontend performance telemetry. -- Frontend BFF `ETag + Cache-Control` landed for cities/summary/history (`force_refresh` keeps `no-store`). -- Mispricing radar now hard-skips non-tradable markets (closed/inactive/not accepting orders/past endDate). -- AI analysis now includes peak-window hard constraints (before-window cannot claim "locked"/"confirmed floor"). +- Bot entry refactor completed: + - `bot_listener.py` simplified to thin entrypoint. + - Runtime split into orchestrator/handlers/services/analysis/guard/coordinator layers. +- Startup diagnostics landed: + - `/diag` command + - loop-level startup status reporting (trade alerts, polygon watcher, polymarket watcher) +- Multi-model anchor migration completed for mispricing radar (replaced single Open-Meteo anchor). +- Non-tradable market hard-skip guard completed (closed/inactive/not accepting orders/past end time). +- Wallet activity watcher upgraded with alias parsing, link preview switch, and anti-spam debounce/immediate controls. +- Frontend BFF HTTP caching (`ETag`/`304`) completed for cities/summary/history. +- Meteoblue fully removed from runtime paths and docs. --- -## 3. High Priority Debt +## 3. Active High-Priority Debt | Item | Impact | Suggested Work | | :-- | :-- | :-- | -| Monolithic bot entry (`bot_listener.py`) | Hard to test and safely refactor | Split orchestration, IO and analysis modules | -| Entitlement enforcement consistency | Revenue leakage risk | Align frontend middleware and backend enforcement | -| Subscriber persistence model | Manual operations do not scale | Move to managed PostgreSQL/Supabase state | -| Alert explainability | Operator trust and debugging cost | Standardize evidence payload per alert | +| Payment event ingestion pipeline | Cannot automate paid access reliably | Build idempotent onchain payment ingest + reconciliation worker | +| Subscriber persistence model | Manual entitlement ops do not scale | Add managed PostgreSQL/Supabase subscriber state | +| Entitlement parity matrix | Access leaks/false denies across channels | Unify policy across frontend middleware, backend API, and bot guard | +| Alert evidence contract | Harder to debug false positives quickly | Standardize machine-readable evidence schema for each push | --- -## 4. Medium Priority Debt +## 4. Active Medium-Priority Debt | Item | Impact | Suggested Work | | :-- | :-- | :-- | -| Replay simulation harness | Hard to reproduce edge cases | Build deterministic replay over stored records | -| Chart/UI regression coverage | Visual regressions can slip | Add snapshot + interaction test coverage | -| Config centralization | Threshold changes are error-prone | Consolidate runtime knobs into structured config | -| Naming cleanup | Legacy terms reduce clarity | Refactor naming in market/weather boundary layer | +| Replay simulation harness | Edge-case regressions hard to reproduce | Deterministic replay from stored weather + market snapshots | +| End-to-end integration coverage | Runtime regressions can slip | Add integration tests for `/api/city/{name}/detail` + push decisions | +| Config sprawl | Tuning is error-prone | Consolidate env knobs into structured config groups | +| Naming and data contracts | Boundary confusion persists | Normalize model/market field naming and compatibility aliases | --- -## 5. Low Priority Debt +## 5. Active Low-Priority Debt | Item | Impact | Suggested Work | | :-- | :-- | :-- | -| Cold-start behavior | First request latency variance | Add warming strategy for top city routes | -| Storage abstraction | Local file assumptions remain | Continue moving state to remote services | +| Cold-start variance | First request latency jitter | Add prewarm strategy for top city routes | +| Local state files | Harder multi-instance scaling | Continue migration to managed storage | --- ## 6. Next Milestones -1. Entitlement parity: one policy across frontend and backend. -2. Subscriber DB integration and migration scripts. -3. Alert evidence schema + tooling for quick operator audit. -4. Replay runner for weather/market mixed regression scenarios. +1. Land subscriber DB + entitlement expiry model. +2. Ship payment ingest + automatic entitlement sync. +3. Add replay harness for weather/market mixed scenarios. +4. Publish alert evidence schema and operator tooling. --- diff --git a/docs/TECH_DEBT_ZH.md b/docs/TECH_DEBT_ZH.md index ca875059..5f7784c3 100644 --- a/docs/TECH_DEBT_ZH.md +++ b/docs/TECH_DEBT_ZH.md @@ -1,94 +1,93 @@ # 技术债与工程待办 -目标:在持续交付的同时,把关键技术债显式化、可追踪化。 +目标:在持续交付的同时,让技术债可见、可追踪、可关闭。 --- -## 1. 技术债全景 +## 1. 债务快照 + +当前估计:**90% 稳定 / 10% 技术债**。 ```mermaid flowchart TD A["技术债"] - subgraph AR["架构层"] - AR1["机器人入口过于集中"] - AR2["共享运行时耦合"] - end - - subgraph PI["产品基础设施"] - PI1["订阅权限一致性"] - PI2["付费用户持久化"] + subgraph PI["支付基础设施"] + PI1["支付事件入库与对账"] + PI2["订阅用户持久化"] + PI3["权限策略一致化"] end subgraph Q["质量保障"] - Q1["回放测试能力"] - Q2["UI 回归覆盖不足"] + Q1["回放仿真能力"] + Q2["端到端集成覆盖"] end subgraph O["可观测性"] - O1["告警证据链"] - O2["SLO 看板"] + O1["告警证据标准"] + O2["运维看板"] end - A --> AR A --> PI A --> Q A --> O ``` -当前系统健康度估计:**86% 稳定 / 14% 技术债**。 +--- + +## 2. 近期已关闭(2026-03-12) + +- Bot 入口重构完成: + - `bot_listener.py` 已收敛为薄入口。 + - 运行时拆分为编排层/处理层/服务层/分析层/守卫层/协调层。 +- 启动诊断完成: + - 新增 `/diag` 指令 + - 后台循环启动状态可视化(错价雷达、Polygon 钱包、Polymarket 异动) +- 错价锚点完成升级:从单一 Open-Meteo 改为多模型最高温锚点。 +- 不可交易市场硬拦截完成:`closed`/inactive/不接单/超结束时间全部跳过。 +- 钱包异动监听增强完成:昵称映射、链接预览开关、去抖与即时推送控制。 +- 前端 BFF `ETag/304` 缓存完成(cities/summary/history)。 +- Meteoblue 已从运行链路与文档中彻底移除。 --- -## 2. 最近已关闭项(2026-03-12) - -- Meteoblue API 全链路移除(后端/前端/配置/文档)。 -- 市场温度桶重复刷屏问题修复(后端去重 + 前端兜底)。 -- 详情面板可访问性告警修复(`aria-hidden` 焦点冲突改为 `inert + blur`)。 -- 前端已接入 Vercel Speed Insights。 -- 前端 BFF 增加 `ETag + Cache-Control`(cities/summary/history)与 `force_refresh=no-store` 语义。 -- 错价雷达增加“不可交易市场硬拦截”(closed/inactive/不接单/过 endDate)。 -- AI 分析增加峰值时段硬约束(before 状态禁止“已锁定/已确认底线”)。 - ---- - -## 3. 高优先级技术债 +## 3. 当前高优先级技术债 | 项目 | 影响 | 建议动作 | | :-- | :-- | :-- | -| 机器人入口单体化(`bot_listener.py`) | 测试和重构风险高 | 拆分为编排层、IO 层、分析层 | -| 订阅权限策略不完全统一 | 可能造成付费泄露 | 前后端统一权限校验策略 | -| 付费用户状态持久化不足 | 人工运营不可扩展 | 迁移到托管 DB(PostgreSQL/Supabase) | -| 告警可解释性不足 | 运维排障成本高 | 统一告警证据字段(Evidence Schema) | +| 支付事件采集与对账流水线 | 无法稳定自动开通付费权限 | 构建幂等 payment ingest + reconciliation worker | +| 订阅用户持久化模型 | 人工开通不可扩展 | 落地 PostgreSQL/Supabase 订阅状态 | +| 权限策略一致性矩阵 | 存在漏放行/误拦截风险 | 统一前端中间件、后端 API、Bot 守卫策略 | +| 告警证据协议 | 假阳性排障成本高 | 统一机器可读 Evidence Schema | --- -## 4. 中优先级技术债 +## 4. 当前中优先级技术债 | 项目 | 影响 | 建议动作 | | :-- | :-- | :-- | -| 回放仿真能力不足 | 边缘场景难复现 | 基于历史记录构建可重复 Replay | -| 图表/UI 回归覆盖不足 | 视觉回归风险 | 增加快照与交互自动化测试 | -| 阈值配置分散 | 改动成本高且易错 | 统一收口到结构化配置 | -| 命名历史包袱 | 认知成本高 | 系统化命名治理 | +| 回放仿真能力不足 | 边缘场景回归难复现 | 基于天气+市场快照构建确定性 Replay | +| 端到端集成覆盖不足 | 运行时回归难提前发现 | 增加 `/api/city/{name}/detail` 与推送链路集成测试 | +| 配置项分散 | 阈值调优易出错 | 将关键 env 聚合为结构化配置分组 | +| 命名与字段兼容历史包袱 | 认知与维护成本高 | 统一模型/市场字段命名与兼容层 | --- -## 5. 低优先级技术债 +## 5. 当前低优先级技术债 | 项目 | 影响 | 建议动作 | | :-- | :-- | :-- | -| 冷启动波动 | 首次请求延迟不稳定 | 热点城市路由预热 | -| 本地文件状态依赖 | 云端弹性场景受限 | 持续迁移到远程存储 | +| 冷启动波动 | 首次请求延迟抖动 | 对热点城市路由做预热 | +| 本地文件状态依赖 | 多实例扩展受限 | 继续迁移到托管存储 | --- ## 6. 下阶段里程碑 -1. 完成前后端订阅权限一致化。 -2. 上线付费用户持久化与迁移脚本。 -3. 建立告警证据标准并接入运维排障流。 -4. 落地天气+市场混合回放回归测试。 +1. 上线订阅用户 DB 与权限过期模型。 +2. 完成支付事件入库与自动授权同步。 +3. 落地天气+市场混合回放回归。 +4. 发布告警证据标准与运维排障工具。 --- diff --git a/frontend/README.md b/frontend/README.md index 4a990159..b24695cf 100644 --- a/frontend/README.md +++ b/frontend/README.md @@ -1,6 +1,6 @@ # PolyWeather Frontend -This directory is the only web frontend in production. +This directory contains the production web frontend. Production URL: - https://polyweather-pro.vercel.app/ @@ -8,23 +8,23 @@ Production URL: ## Stack - Next.js App Router -- React (component-driven dashboard) +- React (dashboard component architecture) - Tailwind CSS -- Leaflet (map runtime) -- Chart.js (charts with manual lifecycle wrapper) -- Typed store + typed data client +- Leaflet (map) +- Chart.js +- Typed dashboard store + typed data client -## Production Model +## Runtime Model -- Vercel serves the web UI and BFF route handlers -- FastAPI on VPS serves weather APIs only -- The old FastAPI static website has been removed -- The production page shell is React-driven (`components/dashboard/*`), with no runtime dependency on `public/static/app.js` +- Vercel hosts UI + BFF route handlers. +- FastAPI on VPS provides weather/analysis APIs. +- Browser never calls backend directly in normal flow. -Current request flow: -- Browser -> Vercel frontend -- React store/client -> Next route handlers -- Next route handlers -> FastAPI API +Request path: + +1. Browser -> `https://polyweather-pro.vercel.app` +2. Frontend -> Next route handlers (`/api/*`) +3. Route handlers -> FastAPI (`POLYWEATHER_API_BASE_URL`) ## Local Development @@ -38,41 +38,73 @@ npm run dev Default local URL: - http://localhost:3000 -## Required Environment Variable +## Required Environment Variables ```env POLYWEATHER_API_BASE_URL=https:// ``` -Examples: -- `http://38.54.27.70:8000` -- `https://api.example.com` +Optional entitlement variables: + +```env +POLYWEATHER_DASHBOARD_ACCESS_TOKEN= +POLYWEATHER_BACKEND_ENTITLEMENT_TOKEN= +``` ## Route Handlers -Thin BFF routes currently exposed by Next: - `GET /api/cities` - `GET /api/city/[name]` - `GET /api/city/[name]/summary` +- `GET /api/city/[name]/detail` - `GET /api/history/[name]` -Current frontend behavior: -- `/` keeps the world overview layout and initial city temperatures preload -- Marker click: focus map + open right city card + render nearby stations -- Right-card "今日日内分析": opens modal and freezes map motion -- Blank-map click: closes right card only, without resetting camera +Cache behavior: + +- `cities` / `summary` / `history` return `ETag` + `Cache-Control`. +- `summary?force_refresh=true` returns `Cache-Control: no-store`. +- `city/[name]` and `city/[name]/detail` are dynamic pass-through (no shared HTTP cache). + +## Frontend State & Local Cache + +- `sessionStorage`: + - city detail cache bundle (TTL 5 minutes) +- `localStorage`: + - selected city + - sidebar risk-group collapse state +- in-flight request de-duplication for city detail/summary/history/market scan + +## Entitlement + +- `frontend/middleware.ts` enforces dashboard/API access when `POLYWEATHER_DASHBOARD_ACCESS_TOKEN` is set. +- BFF forwards backend entitlement token via `x-polyweather-entitlement` header when configured. + +## UI Notes + +- Left sidebar supports risk-group collapsible sections. +- City rows keep local time and peak-time hints visible. +- Future-date modal requests market scan with `target_date`. +- Detail panel accessibility uses `inert` + blur when hidden. + +## Icons & Manifest + +- `frontend/app/favicon.ico` +- `frontend/app/favicon-16x16.png` +- `frontend/app/favicon-32x32.png` +- `frontend/app/apple-touch-icon.png` +- `frontend/app/site.webmanifest` ## Vercel Deployment -1. Import the repo into Vercel -2. Set Root Directory to `frontend` -3. Set `POLYWEATHER_API_BASE_URL` +1. Import repo into Vercel +2. Set Root Directory = `frontend` +3. Set env vars 4. Deploy -## Notes +## Verification -- Backend CORS must allow `https://polyweather-pro.vercel.app` -- City detail cache TTL is 5 minutes with revision probe; manual refresh bypasses cache -- UI layout and sizing remain aligned with the legacy visual contract after React migration +```bash +./scripts/validate_frontend_cache.sh "https://polyweather-pro.vercel.app" +``` -Last updated: 2026-03-09 +Last updated: `2026-03-12`