From 14838fde4dfaa4b484c8d8c639e813f5dda920d5 Mon Sep 17 00:00:00 2001
From: "2569718930@qq.com" <2569718930@qq.com>
Date: Fri, 6 Mar 2026 19:10:05 +0800
Subject: [PATCH] feat: Add database-backed user and subscription management,
update project architecture documentation, and outline technical debt.
---
README.md | 331 +++++++++++++++++-------------------
README_ZH.md | 332 +++++++++++++++++--------------------
bot_listener.py | 42 ++++-
docs/COMMERCIALIZATION.md | 150 ++++++++++++++---
docs/TECH_DEBT.md | 165 +++++++++---------
frontend/README.md | 62 ++++---
src/database/db_manager.py | 109 ++++++++++++
7 files changed, 696 insertions(+), 495 deletions(-)
create mode 100644 src/database/db_manager.py
diff --git a/README.md b/README.md
index ff9a7b8e..ded9310e 100644
--- a/README.md
+++ b/README.md
@@ -1,10 +1,14 @@
-# 🌡️ PolyWeather: Intelligent Weather Quant Analysis Bot
+# PolyWeather
-[](https://www.python.org/downloads/)
-[](https://opensource.org/licenses/MIT)
-[](https://deepwiki.com/yangyuan-zhen/PolyWeather)
+PolyWeather is a weather intelligence system built around live airport observations, multi-model forecasts, DEB blending, and Telegram alert delivery.
-PolyWeather is a multi-source weather analysis and quantification tool. It aggregates high-precision forecasts, real-time airport METAR observations, a math-based probability engine, and AI-driven decision support to provide deep insights for weather-related risk assessment and data-driven decision making.
+Current production layout:
+
+- Frontend: Next.js on Vercel
+- Backend API: FastAPI on VPS
+- Bot / alert loop: Telegram bot on VPS
+
+The old FastAPI static web page has been removed. Vercel is the only web entry point.
@@ -18,203 +22,164 @@ PolyWeather is a multi-source weather analysis and quantification tool. It aggre
🗺️ Interactive Web Map: Real-time global monitoring with rich data visualization
----
+## Features
-## ✨ Core Features
+- Multi-source weather aggregation
+ - Open-Meteo
+ - METAR live observations
+ - MGM official data for Ankara
+ - Multi-model highs such as ECMWF / GFS / ICON / GEM / JMA when available
+- DEB blended forecast
+ - Dynamic weighting based on recent model error
+- City dashboard
+ - Global city list
+ - City detail panel
+ - Nearby station map markers
+ - Trend chart
+ - Multi-model comparison
+ - Daily forecast table
+- Telegram proactive alerts
+ - Ankara Center reached DEB
+ - Momentum spike
+ - Forecast breakthrough
+ - Advection / nearby lead station signal
+- Late-day suppression
+ - If the local daily high has likely already passed and the market is cooling off, active alerts are downgraded to status only and are not pushed
-### 1. 🌐 Interactive Web Map Dashboard
+## Alert Rules
-- **Global Overview**: Real-time Leaflet-based dark-themed map pinpointed to official Polymarket settlement airport coordinates.
-- **Progressive Background Loading**: Intelligently fetches multi-source data across all cities without hitting API rate limits.
-- **Rich Visualization**: Chart.js-powered temperature trends with METAR scatter overlay, multi-model comparison bars, Gaussian probability distribution, and dynamic risk badges.
-- **Zoom-based Intelligence**: Map automatically filters minor cities (e.g., Atlanta/Ankara) and local station labels at lower zoom levels to maintain clarity, showing only major global hubs when zoomed out.
-- **Technical Guide Interface**: Features an interactive on-map technical guide explaining DEB prediction curves, probability bands, and risk factors.
-- **Cinematic Interaction & Sync**: City selection triggers a smooth fly-to zoom animation. The **Multi-Model Forecast** panel automatically synchronizes with the selected day in the 5-day forecast table, showing historical model performance and future projections.
-- **Forced Sync & Cache Control**: For specific regions like Ankara, the dashboard supports a 60-second real-time cache TTL with a manual "Force Refresh" button to bypass global caches and fetch the absolute latest MGM/METAR data.
-- **Dual-Engine Architecture**: Runs concurrently with the Telegram bot via a FastAPI backend, sharing the same data collection, analysis logic (`analyze_weather_trend`), and AI prompt pipeline.
+Implemented rules:
-### 2. 🧬 Dynamic Ensemble Blending (DEB Algorithm)
+- `ankara_center_deb_hit`
+ - Only uses `Ankara (Bolge/Center)` station / `istNo=17130`
+ - This is the official Ankara center station used for the Center signal
+- `momentum_spike`
+ - 30-minute slope exceeds the configured threshold
+- `forecast_breakthrough`
+ - Current observed temperature is above the highest available major model high by margin
+- `advection`
+ - Nearby station leads the airport station and wind regime supports warm advection
-The system automatically tracks the historical performance of weather models (ECMWF, GFS, ICON, GEM, JMA) per city:
+Suppression rule:
-- **Error-Based Weighting**: Dynamically adjusts model weights based on their Mean Absolute Error (MAE) over the past 7 days. Lower error = higher weight.
-- **Blended Forecast**: Provides a bias-corrected "DEB Blended High Temperature" recommendation.
-- **Multi-Source Training**: Integrates official regional sources (like Turkey's MGM) into the training pipeline alongside international models (ECMWF, GFS, etc.).
-- **Accuracy Tracking**: Use the `/deb` command to view DEB's historical settlement hit rate and MAE, compared against individual models.
-- **Auto-Cleanup**: Only retains the last 14 days of records to prevent unbounded data growth.
+- `peak_passed_guard`
+ - No active push if the city's local peak has already passed, enough time has elapsed, and the current temperature has materially rolled over from the day's high
-### 3. 🎲 Math Probability Engine (Settlement Probability)
+Push dedupe rule:
-Automatically computes the probability for each possible settlement integer using a Gaussian distribution:
+- Same city + same trigger type only pushes once while still active
+- It can push again only after the signal clears and re-arms
+- Cooldown still applies at city level
-- **Reality-Anchored μ**: When actual max temperature is significantly below forecasts during/after the peak window (forecast bust), μ anchors on the observed max instead of failed predictions. Otherwise, uses a weighted average of DEB/multi-model median (70%) and ensemble median (30%).
-- **Standard Deviation σ — Three-Layer Pipeline**:
- 1. **Ensemble Base**: σ = (P90-P10) / 2.56
- 2. **MAE Floor**: Uses DEB's historical MAE as σ minimum—prevents ensembles from underestimating true uncertainty
- 3. **Shock Score Amplifier**: σ × (1 + 0.5 × shock_score) when weather is changing rapidly
-- **Time Decay**: Before peak σ×1.0 → During peak σ×0.7 → After peak σ×0.3
-- **Observed Floor**: Temperatures below the current METAR max WU value are excluded
-- **Dead Market Override**: When a dead market is confirmed, probability collapses to 100% at the settled value
+## Data Semantics
-#### 💥 Shock Score: Weather Disruption Soft Scorer (0~1)
+Alert message fields:
-Evaluates environmental stability from the last 4 METAR observations. Higher = more unstable = wider σ:
+- `实测 / Now`
+ - Uses `METAR current.temp` first
+ - Falls back to `MGM current.temp` if METAR current temperature is unavailable
+- `时间 / Time`
+ - `local`: city local clock time
+ - `observed`: observation time attached to the current reading
-| Component | Weight | Trigger |
-| :-------------------- | :----- | :---------------------------------------------------------------- |
-| Wind Direction Change | 0~0.4 | Angle difference × wind speed amplifier (weak winds downweighted) |
-| Cloud Cover Jump | 0~0.35 | Cloud code escalation (FEW→BKN, etc.) |
-| Pressure Change | 0~0.25 | >2hPa change within 2 hours |
+## Deployment
-### 4. 🤖 AI Deep Analysis (Groq LLaMA 3.3 70B)
+### Backend / bot on VPS
-Feeds all weather data into LLaMA 70B, analyzed via a **P0→P4 Priority Chain**:
+Requirements:
-- **P0 Forecast Bust Detection** (highest priority): Graded severity (light/medium/heavy) when actual temps diverge from forecasts. Requires slope + wind/cloud verification before declaring settlement locked. "Bust ≠ locked" — still checks for second-wave warming.
-- **P1 Real-Time Rhythm**: 2 consecutive METAR highs → still warming; 2 non-highs with slope ≤ 0 → dead market. Low-radiation warming → multi-factor (advection/mixing layer/heat island), no single-factor attribution.
-- **P2 Inhibitors** (city-aware): Precipitation → strong suppression. High humidity + thick clouds sustained 2+ reports → possible suppression, but thresholds vary by city type (maritime vs. continental). Single factor insufficient.
-- **P3 Probability Cross-Check**: References settlement probability for consistency check with P1. Contradictions explained with deviation rationale.
-- **P4 Forecast Background**: DEB/forecasts for ceiling estimation; silenced when actuals significantly deviate.
-- **Single Source of Truth**: Both web and Telegram bot share the same `analyze_weather_trend` function and `get_ai_analysis` prompt — identical context, identical decisions.
-- **High Availability**: Auto-retry + fallback model degradation (70B → 8B). Proxy support for restricted networks.
+- Docker
+- Docker Compose
+- `.env`
-### 5. ⏱️ Real-time Airport Observations (Zero-Cache METAR)
-
-- **Precise Timing**: Extracts actual observation time from raw METAR text (`rawOb`), not the API's rounded `reportTime`. Accurate to the minute.
-- **Live Passthrough**: Bypasses CDN caching via dynamic headers and randomized timestamps to obtain first-hand METAR/MGM reports.
-- **Settlement Warning**: Automatically calculates the rounding boundary for integer-based settlement (X.5 line).
-- **MGM Primary (Ankara)**: For Turkish cities like Ankara, PolyWeather uses official MGM data as a primary source for both real-time observations and 5-day hourly forecasts, ensuring maximum local accuracy.
-- **Anomaly Filtering**: Automatically filters out -9999 sentinel values to prevent garbage data in output.
-
-### 6. 📈 Historical Data Collection
-
-- Includes `fetch_history.py` to retrieve up to 3 years of hourly historical weather data (temperature, humidity, radiation, pressure, 10+ dimensions), providing data foundation for future ML models (XGBoost/MOS).
-
----
-
-## ⚡ Deployment
-
-### Requirements
-
-- **Python 3.11+** or **Docker & Docker Compose**
-- **Environment Variables**: Set parameters in your `.env` file (copy from `.env.example`).
-
-### 🐳 Docker Deployment (Recommended)
-
-The easiest and most stable way to deploy without system dependency conflicts.
-
-1. **Clone and configure**
- ```bash
- git clone https://github.com/yangyuan-zhen/PolyWeather.git
- cd PolyWeather
- cp .env.example .env
- # Edit .env to add TELEGRAM_BOT_TOKEN, GROQ_API_KEY, etc.
- nano .env
- ```
-2. **Start the service in the background**
- ```bash
- docker-compose up -d --build
- ```
-3. **View live logs**
- ```bash
- docker-compose logs -f
- ```
-
-### 💻 Traditional VPS Deployment
-
-1. Install dependencies: `pip install -r requirements.txt`
-2. Configure your `.env` file.
-3. Use the included `update.sh` script for one-click updates and restarts for both the Telegram Bot and the Web Map:
-
-```bash
-# Run the script to update code and restart both services in the background
-./update.sh
-```
-
-_(Note: The `update.sh` script automatically fetches the latest code, kills old processes, clears ports, and launches both `bot_listener.py` and `web/app.py` via `nohup`.)_
-
----
-
-## 🕹️ Bot Commands
-
-| Command | Description |
-| :------------------ | :---------------------------------------------------------------------------------------------------------------------------------- |
-| `/city [city_name]` | Get weather analysis, settlement probabilities, METAR tracking, and AI insights. (Includes "Bölge/Center" detail for Ankara). |
-| `/deb [city_name]` | View DEB accuracy: daily hit/miss breakdown, bias analysis (underestimate/overestimate), model MAE comparison, trading suggestions. |
-| `/id` | View the Chat ID of the current conversation. |
-| `/help` | Display help information. |
-
-### Supported Cities
-
-`lon` (London), `par` (Paris), `ank` (Ankara), `nyc` (New York), `chi` (Chicago), `dal` (Dallas), `mia` (Miami), `atl` (Atlanta), `sea` (Seattle), `tor` (Toronto), `sel` (Seoul), `ba` (Buenos Aires), `wel` (Wellington), etc.
-
----
-
-## 🏗️ Architecture
-
-```mermaid
-graph TD
- User[User] -->|Query| Bot["bot_listener.py (Core Scheduler)"]
- User -->|Browser| Web["web/app.py (FastAPI)"]
-
- subgraph Data Acquisition
- Bot --> Collector[WeatherDataCollector]
- Web --> Collector
- Collector --> OM[Open-Meteo Forecast/Ensemble]
- Collector --> MM[Multi-Model ECMWF/GFS/ICON/GEM/JMA]
- Collector --> METAR["Live Airport METAR (rawOb)"]
- Collector --> MGM["MGM Official (Ankara)"]
- end
-
- subgraph Algorithm Layer
- Collector --> Peak[Peak Hour Prediction]
- Collector --> DEB[DEB Dynamic Weighting]
- DEB --> DB[(daily_records Database)]
- Peak --> Prob["Probability Engine (Reality-Anchored μ)"]
- Collector --> Prob
- METAR --> Shock[Shock Score]
- Shock --> Prob
- Collector --> Logic["Settlement Boundary / Dead Market"]
- end
-
- subgraph Shared Analysis
- Bot --> ATF["analyze_weather_trend()"]
- Web --> ATF
- ATF --> AI["Groq LLaMA 70B (P0→P4)"]
- end
-
- AI -->|Market Call + Logic + Confidence| Bot
- AI -->|Market Call + Logic + Confidence| Web
-```
-
----
-
-## 💡 Trading Tips
-
-1. **Real-time Rhythm First**: AI analysis follows P0→P4 priority. If live METAR trends (P1) conflict with math probabilities (P3), always prioritize the live trend.
-2. **Watch Settlement Probabilities**: Based on Gaussian models, direction is most certain when a temperature has > 70% probability while P1 rhythm is flat.
-3. **Reference DEB Bias**: Use `/deb` to check for systematic bias. If a city is consistently "underestimated," habitually bid one WU notch higher.
-4. **Identify Dead Market Signals**: When the system declares a "Dead Market," probability collapses to 100% at the settled value. Warming power is exhausted.
-5. **Mind the Boundaries**: When the observed high is near X.5 (e.g., 7.50°C), be wary of rounding up due to tiny fluctuations.
-6. **Forecast Bust Awareness**: When the AI reports a forecast bust (especially medium/heavy grade), all model predictions have lost reference value. Focus exclusively on METAR actuals.
-
----
-
-## 🛠️ Development & Testing
-
-Run unit tests for the core trend engine and probability models:
-
-```bash
-python -m pytest tests/test_trend_engine.py -v
-```
-
-Deploying updates to the server:
+Deploy:
```bash
git pull
-./update.sh
+docker-compose up -d --build
```
----
+Main services:
-_Updated 2026-03-05_
+- `polyweather_bot`
+- `polyweather_web`
+
+The FastAPI service is now API-only. It does not serve a static website.
+
+### Frontend on Vercel
+
+The Vercel project uses the `frontend` directory as root.
+
+After pushing to Git, Vercel deploys automatically.
+
+## Environment Variables
+
+Minimum practical set:
+
+```env
+TELEGRAM_BOT_TOKEN=...
+TELEGRAM_CHAT_ID=...
+GROQ_API_KEY=...
+POLYWEATHER_MAP_URL=https://polyweather-pro.vercel.app/
+WEB_CORS_ORIGINS=http://localhost:3000,http://127.0.0.1:3000,https://polyweather-pro.vercel.app
+```
+
+Push tuning:
+
+```env
+TELEGRAM_ALERT_PUSH_ENABLED=true
+TELEGRAM_ALERT_PUSH_INTERVAL_SEC=300
+TELEGRAM_ALERT_PUSH_COOLDOWN_SEC=3600
+TELEGRAM_ALERT_MIN_TRIGGER_COUNT=2
+TELEGRAM_ALERT_MIN_SEVERITY=medium
+TELEGRAM_ALERT_CITIES=ankara,london,paris,seoul,toronto,buenos aires,wellington,new york,chicago,dallas,miami,atlanta,seattle,lucknow,sao paulo,munich
+```
+
+Recommended:
+
+- Use `3600` seconds cooldown for production paid groups unless you explicitly want more aggressive alerting
+
+## Bot Commands
+
+Supported user commands:
+
+- `/city [city]`
+- `/deb [city]`
+- `/id`
+- `/help`
+
+`/tradealert` has been removed. Alerts are proactive push only.
+
+## Architecture
+
+```mermaid
+graph TD
+ User[Telegram User] --> Bot[bot_listener.py]
+ User2[Web User] --> Vercel[Next.js on Vercel]
+ Vercel --> API[FastAPI API on VPS]
+ Bot --> API
+ API --> Collector[WeatherDataCollector]
+ Collector --> OM[Open-Meteo]
+ Collector --> METAR[METAR]
+ Collector --> MGM[MGM]
+ Collector --> MM[Multi-model sources]
+ API --> DEB[DEB blending]
+ API --> Alerts[Alert engine]
+ Alerts --> Bot
+```
+
+## Testing
+
+Quick checks used in development:
+
+```bash
+python -m py_compile src/analysis/market_alert_engine.py src/utils/telegram_push.py web/app.py bot_listener.py
+node --check frontend/public/static/app.js
+npm run build --prefix frontend
+```
+
+If you want to run pytest, install it first.
+
+## Status
+
+Last updated: 2026-03-06
diff --git a/README_ZH.md b/README_ZH.md
index 11d39c7b..58d0b093 100644
--- a/README_ZH.md
+++ b/README_ZH.md
@@ -1,10 +1,14 @@
-# 🌡️ PolyWeather: 智能天气量化分析机器人
+# PolyWeather
-[](https://www.python.org/downloads/)
-[](https://opensource.org/licenses/MIT)
-[](https://deepwiki.com/yangyuan-zhen/PolyWeather)
+PolyWeather 是一套围绕实时机场观测、多模型预报、DEB 融合和 Telegram 主动推送构建的天气情报系统。
-PolyWeather 是一款多模型气象分析与量化工具。它通过聚合高精度气象预报、实时机场 METAR 观测,并引入数学概率模型与 AI 决策支持,为气象风险评估和数据驱动的交易决策提供深度洞察。
+当前生产架构:
+
+- 前端:Vercel 上的 Next.js
+- 后端 API:VPS 上的 FastAPI
+- 机器人与预警循环:VPS 上的 Telegram Bot
+
+FastAPI 旧静态网页已经移除。Vercel 是唯一网页入口。
@@ -18,204 +22,164 @@ PolyWeather 是一款多模型气象分析与量化工具。它通过聚合高
🗺️ 交互式网页地图:全球城市实时监控与丰富的数据可视化
----
+## 当前功能
-## ✨ 核心功能
+- 多源天气采集
+ - Open-Meteo
+ - METAR 实时观测
+ - 安卡拉官方 MGM 数据
+ - ECMWF / GFS / ICON / GEM / JMA 等多模型最高温
+- DEB 融合预报
+ - 基于近期误差动态调权
+- 网页仪表盘
+ - 全球监控城市列表
+ - 城市详情面板
+ - 周边站点地图标记
+ - 今日趋势图
+ - 多模型对比
+ - 多日预报表
+- Telegram 主动预警
+ - Ankara Center 达到 DEB
+ - 动量突变
+ - 预测突破
+ - 暖平流 / 周边站联动
+- 晚盘压制逻辑
+ - 当地高温大概率已经兑现且开始回落时,预警降级为状态快照,不主动推送
-### 1. 🌐 交互式网页地图面板
+## 预警规则
-- **全球纵览**:基于 Leaflet 的暗黑全屏实时地图,直接采用官方结算机场经纬度进行追踪与显示。
-- **渐进式数据流加载**:进图后智能在后台无感知拉取,不触发 API 频率限制。
-- **数据可视化**:Chart.js 温度走势图叠加 METAR 实测散点,多模型对比条形图,高斯概率分布条,实时风险等级色彩系统。
-- **智能缩放过滤**:地图会根据缩放等级自动隐藏次要城市(如亚特兰大、安卡拉)和局部观测点标签,以保持全局视野清晰,仅在放大时显示细节。
-- **内置技术指南**:新增交互式技术手册面板,详细解释 DEB 预测曲线、概率区间及各类风险因子。
-- **镜头与日期联动**:点击城市平滑飞入面板。**多模型预报区域**会根据“逐日预报”选中的日期自动刷新,支持查看未来 5 天各模型的历史表现与融合预测值。
-- **强制同步与缓存控制**:针对安卡拉等重点区域,Web 端支持 60 秒极速缓存 TTL,并提供手动“强制刷新”按钮,可穿透全局缓存获取最及时的 MGM/METAR 实测数据。
-- **周边测站热力图**:不仅追踪目标机场,还能并发抓取目标城市周边 20~50 公里内的所有气象站实测。通过地图上的“微型标签”可视化城市热岛效应与锋面推进,辅助判断冷空气过境的时间差。
-- **双引擎共生**:FastAPI 后端与 Telegram Bot 共享同一份分析逻辑(`analyze_weather_trend`)和 AI Prompt 管线。
+当前启用的规则:
-### 2. 🧬 动态权重集合预报 (DEB 算法)
+- `ankara_center_deb_hit`
+ - 只使用 `Ankara (Bolge/Center)` 站点,`istNo=17130`
+ - 这是安卡拉 Center 信号唯一认可的官方站点
+- `momentum_spike`
+ - 30 分钟温度斜率超过阈值
+- `forecast_breakthrough`
+ - 当前实测温度高于主流模型最高值,并超过安全边际
+- `advection`
+ - 周边站领先升温,且风向与暖平流传播方向匹配
-系统会自动追踪各个气象模型(ECMWF, GFS, ICON, GEM, JMA)在特定城市的历史表现:
+压制规则:
-- **误差加权**:根据过去 7 天的平均绝对误差(MAE),动态调整各模型的权重。误差越小的模型,话语权越大。
-- **融合预报**:给出经过历史偏差修正后的"DEB 融合最高温"建议值。
-- **多源训练集成**:将区域性官方数据源(如土耳其 MGM)同步纳入 DEB 训练管线,与 ECMWF、GFS 等国际模型共同参与权重博弈。
-- **准确率追踪**:通过 `/deb` 命令查看 DEB 融合预测的历史结算命中率和 MAE,并与各个单一模型对比。
-- **自动清理**:只保留最近 14 天的记录,防止数据无限增长。
+- `peak_passed_guard`
+ - 当地高点已经过去、间隔足够长、且温度已从日内高点明显回落时,不再主动推送
-### 3. 🎲 数学概率引擎 (Settlement Probability)
+去重规则:
-基于集合预报的正态分布拟合,自动计算每个结算整数温度的概率:
+- 同一城市、同一 trigger type,只会在激活时推送一次
+- 只有信号先解除,再重新触发,才允许再次推送
+- 同时仍保留城市级 cooldown
-- **实况锚定 μ**:当实测最高温在峰值窗口期间/之后显著低于预报中位数(预报崩盘),μ 直接锚定在实测值上,而非失败的预报。正常情况下使用 DEB/多模型中位数(70%)和集合中位数(30%)的加权平均。
-- **标准差 σ 三层修正管线**:
- 1. **集合基础**:σ = (P90-P10) / 2.56
- 2. **MAE 兜底**:用 DEB 历史 MAE 作为 σ 下限——防止集合预报低估真实不确定性
- 3. **Shock Score 放宽**:σ × (1 + 0.5 × shock_score),气象突变时自动加宽
-- **时间衰减**:峰值前 σ×1.0 → 峰值窗口 σ×0.7 → 峰值后 σ×0.3
-- **实测过滤**:已实测 WU 值以下的候选自动排除
-- **死盘覆盖**:确认死盘后,概率直接坍缩为结算值 100%
+## 数据语义
-#### 💥 Shock Score:气象突变软评分 (0~1)
+预警文案中的字段:
-用近 4 条 METAR 报文的风向/云量/气压变化评估环境稳定性,越高 = 越不稳定 = σ 放宽:
+- `实测`
+ - 优先使用 `METAR current.temp`
+ - 如果 METAR 当前温度不可用,再退回 `MGM current.temp`
+- `时间`
+ - `当地`:城市本地当前时间
+ - `观测`:这条实测温度对应的观测时间
-| 分项 | 权重 | 触发条件 |
-| :------- | :----- | :------------------------------------ |
-| 风向变化 | 0~0.4 | 角度差 × 风速放大系数(弱风降权避噪) |
-| 云量阶跃 | 0~0.35 | FEW→BKN 等云码跳变 |
-| 气压变化 | 0~0.25 | 2h 内气压差 > 2hPa |
+## 部署
-### 4. 🤖 AI 深度分析 (Groq LLaMA 3.3 70B)
+### VPS 后端 / 机器人
-将全部气象数据投喂给 LLaMA 70B,按 **P0→P4 分析框架** 决策:
+要求:
-- **P0 预报失准检测**(最高优先级):分级失准(轻/中/重),根据偏差幅度自动标记。"失准 ≠ 已定局"——还需检查斜率 + 风云条件。支持二次抬升判断。
-- **P1 实况节奏**:连续 2 报创新高 → 升温未止;连续 2 报未创新高且斜率 ≤ 0 → 偏死盘。低辐射升温 → 可能多因子叠加(平流/混合层/热岛),不做单因子归因。
-- **P2 阻碍因子**(需结合城市特性判断):降水 → 强压温。高湿度 + 厚云层持续 2 报以上 → 可能压温,但阈值因城市类型(海洋 vs 大陆)而异。单因子不足以断定。
-- **P3 概率与一致性校验**:参考结算概率分布,与 P1 实况做交叉检查。矛盾时以实况为准并说明偏离原因。
-- **P4 预报背景**(最低优先级):可参考 DEB/预报做上沿评估。实测显著偏离时禁止引用。
-- **统一分析源**:Web 和 Telegram Bot 共用同一个 `analyze_weather_trend` 函数和 `get_ai_analysis` 提示词——完全相同的上下文,完全相同的决策。
-- **高可用保障**:自动重试 + 备用模型降级(70B → 8B)。支持代理配置。
+- Docker
+- Docker Compose
+- `.env`
-### 5. ⏱️ 实时机场观测 (Zero-Cache METAR)
-
-- **精确时间**:从 METAR 原始报文 (`rawOb`) 中提取真实观测时间,精确到分钟。
-- **实时穿透**:通过动态请求头和随机时间戳绕过 CDN 缓存,获取机场第一手 METAR/MGM 报文。
-- **结算预警**:自动计算结算边界(X.5 进位线),提醒潜在波动。
-- **MGM 官方直连 (安卡拉)**:针对安卡拉,PolyWeather 已将 MGM 提升为一级数据源,同步采集实时观测数据与 5 天逐小时预报,确保本地精度最大化。
-- **异常过滤**:自动过滤 -9999 等哨兵值,避免垃圾数据污染输出。
-
-### 6. 📈 历史数据采集
-
-- 提供 `fetch_history.py` 脚本,可一键获取各城市过去 3 年的小时级历史气象数据(温度、湿度、辐射、气压等 10+ 维度),为后续机器学习模型(XGBoost/MOS)提供数据基础。
-
----
-
-## ⚡ 部署说明
-
-### 环境要求
-
-- **Python 3.11+** 或 **Docker & Docker Compose**
-- **环境变量**: 在 `.env` 中设置关键参数(参考 `.env.example`)。
-
-### 🐳 Docker 部署 (推荐)
-
-最简单、稳定的部署方式,避免系统依赖冲突。
-
-1. **克隆项目并配置环境**
- ```bash
- git clone https://github.com/yangyuan-zhen/PolyWeather.git
- cd PolyWeather
- cp .env.example .env
- # 编辑 .env 文件填入 TELEGRAM_BOT_TOKEN 和 GROQ_API_KEY 等
- nano .env
- ```
-2. **后台一键启动服务**
- ```bash
- docker-compose up -d --build
- ```
-3. **查看实时日志**
- ```bash
- docker-compose logs -f
- ```
-
-### 💻 传统 VPS 部署方案
-
-1. 安装依赖: `pip install -r requirements.txt`
-2. 配置 `.env` 文件。
-3. 利用项目中已包含的 `update.sh` 实现机器人和网站的双轨后台一键重启:
-
-```bash
-# 每次代码变更后,只需在 VPS 执行此命令
-./update.sh
-```
-
-_(该脚本将自动执行 git 抓取、杀僵尸进程、解绑端口、并分别利用 nohup 重新唤醒 bot_listener.py 和 FastAPI app.py 服务。)_
-
----
-
-## 🕹️ 机器人指令
-
-| 指令 | 说明 |
-| :--------------- | :--------------------------------------------------------------------------------------- |
-| `/city [城市名]` | 获取深度气象分析、结算概率、实测追踪及 AI 决策建议。(安卡拉支持显示市区 Center 细节)。 |
-| `/deb [城市名]` | 查看 DEB 准确率:逐日命中明细、偏差分析(低估/高估)、模型 MAE 对比、交易建议。 |
-| `/id` | 查看当前对话的 Chat ID。 |
-| `/help` | 显示说明信息。 |
-
-### 支持城市示例
-
-`lon`(伦敦)、`par`(巴黎)、`ank`(安卡拉)、`nyc`(纽约)、`chi`(芝加哥)、`dal`(达拉斯)、`mia`(迈阿密)、`atl`(亚特兰大)、`sea`(西雅图)、`tor`(多伦多)、`sel`(首尔)、`ba`(布宜诺斯艾利斯)、`wel`(惠灵顿) 等。
-
----
-
-## 🏗️ 系统架构
-
-```mermaid
-graph TD
- User[用户] -->|查询指令| Bot["bot_listener.py (核心调度器)"]
- User -->|浏览器| Web["web/app.py (FastAPI)"]
-
- subgraph 数据获取层
- Bot --> Collector[WeatherDataCollector]
- Web --> Collector
- Collector --> OM[Open-Meteo 预报/集合]
- Collector --> MM[多模型 ECMWF/GFS/ICON/GEM/JMA]
- Collector --> METAR["机场实时 METAR (rawOb)"]
- Collector --> MGM["MGM 官方直连 (安卡拉)"]
- end
-
- subgraph 算法层
- Collector --> Peak[峰值时段预测]
- Collector --> DEB[DEB 动态权重融合]
- DEB --> DB[(每日记录数据库)]
- Peak --> Prob["概率引擎 (实况锚定μ)"]
- Collector --> Prob
- METAR --> Shock[Shock Score 突变评分]
- Shock --> Prob
- Collector --> Logic["结算边界 / 死盘检测"]
- end
-
- subgraph 共享分析层
- Bot --> ATF["analyze_weather_trend()"]
- Web --> ATF
- ATF --> AI["Groq LLaMA 70B (P0→P4)"]
- end
-
- AI -->|盘口 + 逻辑 + 置信度| Bot
- AI -->|盘口 + 逻辑 + 置信度| Web
-```
-
----
-
-## 💡 交易提示
-
-1. **实况节奏优先**:AI 分析遵循 P0→P4 优先级。如果实况趋势(P1)与数学概率(P3)冲突,以实况走势为准。
-2. **紧盯结算概率**:概率引擎基于数学模型,当某个温度概率 > 70% 且 P1 节奏持平时,方向最为明确。
-3. **参考 DEB 偏差**:通过 `/deb` 查看城市的系统性偏差。如果某个城市经常"低估",交易时应看高 1 个 WU 档位。
-4. **识别死盘信号**:系统判定"死盘"时,概率会直接坍缩为结算值 100%。升温动力彻底枯竭。
-5. **注意结算边界**:实测最高温接近 X.5 时,微小波动可能导致进位,需防范"偷鸡"。
-6. **预报崩盘意识**:当 AI 标记预报失准(尤其中/重级),所有模型预测已失去参考价值,需专注 METAR 实测。
-
----
-
-## 🛠️ 开发与测试
-
-运行核心分析引擎和概率模型的单元测试:
-
-```bash
-python -m pytest tests/test_trend_engine.py -v
-```
-
-部署代码更新到服务器:
+部署命令:
```bash
git pull
-./update.sh
+docker-compose up -d --build
```
----
+主要服务:
-_更新于 2026-03-05_
+- `polyweather_bot`
+- `polyweather_web`
+
+现在的 FastAPI 只提供 API,不再承载网页静态资源。
+
+### Vercel 前端
+
+Vercel 项目根目录使用 `frontend`。
+
+代码推送后,Vercel 会自动部署。
+
+## 环境变量
+
+最小可用集合:
+
+```env
+TELEGRAM_BOT_TOKEN=...
+TELEGRAM_CHAT_ID=...
+GROQ_API_KEY=...
+POLYWEATHER_MAP_URL=https://polyweather-pro.vercel.app/
+WEB_CORS_ORIGINS=http://localhost:3000,http://127.0.0.1:3000,https://polyweather-pro.vercel.app
+```
+
+预警推送调优:
+
+```env
+TELEGRAM_ALERT_PUSH_ENABLED=true
+TELEGRAM_ALERT_PUSH_INTERVAL_SEC=300
+TELEGRAM_ALERT_PUSH_COOLDOWN_SEC=3600
+TELEGRAM_ALERT_MIN_TRIGGER_COUNT=2
+TELEGRAM_ALERT_MIN_SEVERITY=medium
+TELEGRAM_ALERT_CITIES=ankara,london,paris,seoul,toronto,buenos aires,wellington,new york,chicago,dallas,miami,atlanta,seattle,lucknow,sao paulo,munich
+```
+
+生产环境建议:
+
+- 付费群默认使用 `3600` 秒 cooldown,避免同一城市短时间内刷屏
+
+## 机器人命令
+
+当前保留的命令:
+
+- `/city [city]`
+- `/deb [city]`
+- `/id`
+- `/help`
+
+`/tradealert` 已移除。预警只支持主动推送。
+
+## 架构
+
+```mermaid
+graph TD
+ User[Telegram 用户] --> Bot[bot_listener.py]
+ User2[网页用户] --> Vercel[Next.js on Vercel]
+ Vercel --> API[FastAPI API on VPS]
+ Bot --> API
+ API --> Collector[WeatherDataCollector]
+ Collector --> OM[Open-Meteo]
+ Collector --> METAR[METAR]
+ Collector --> MGM[MGM]
+ Collector --> MM[多模型数据源]
+ API --> DEB[DEB 融合]
+ API --> Alerts[预警引擎]
+ Alerts --> Bot
+```
+
+## 测试
+
+开发时常用快速检查:
+
+```bash
+python -m py_compile src/analysis/market_alert_engine.py src/utils/telegram_push.py web/app.py bot_listener.py
+node --check frontend/public/static/app.js
+npm run build --prefix frontend
+```
+
+如果要跑 pytest,请先安装 pytest。
+
+## 状态
+
+最后更新:2026-03-06
diff --git a/bot_listener.py b/bot_listener.py
index d6854b73..70bcd7ea 100644
--- a/bot_listener.py
+++ b/bot_listener.py
@@ -14,6 +14,7 @@ from src.utils.telegram_push import start_trade_alert_push_loop # type: ignore
from src.data_collection.weather_sources import WeatherDataCollector # type: ignore # noqa: E402
from src.data_collection.city_risk_profiles import get_city_risk_profile # type: ignore # noqa: E402
from src.analysis.deb_algorithm import calculate_dynamic_weights, update_daily_record # noqa: E402
+from src.database.db_manager import DBManager
def analyze_weather_trend(weather_data, temp_symbol, city_name=None):
@@ -31,6 +32,7 @@ def start_bot():
return
bot = telebot.TeleBot(token)
+ db = DBManager()
weather = WeatherDataCollector(config)
start_trade_alert_push_loop(bot, config)
@@ -41,8 +43,10 @@ def start_bot():
"可用指令:\n"
"/city [城市名] - 查询城市天气预测与实测\n"
"/deb [城市名] - 查看 DEB 融合预测准确率\n"
+ "/points - 查看你的积分与排行榜\n"
"/id - 获取当前聊天的 Chat ID\n\n"
- "示例: /city 伦敦"
+ "示例: /city 伦敦\n"
+ "💡 提示: 在群内发言可获得积分,积分可用于后续解锁高级版。"
)
bot.reply_to(message, welcome_text, parse_mode="HTML")
@@ -54,6 +58,29 @@ def start_bot():
parse_mode="HTML",
)
+ @bot.message_handler(commands=["points", "rank", "top"])
+ def show_points(message):
+ """显示当前用户的积分及排行榜"""
+ user = message.from_user
+ user_info = db.get_user(user.id)
+
+ leaderboard = db.get_leaderboard(limit=5)
+ rank_text = "🏆 PolyWeather 活跃度排行榜\n"
+ rank_text += "────────────────────\n"
+ for i, entry in enumerate(leaderboard):
+ medal = ["🥇", "🥈", "🥉", " ", " "][i] if i < 5 else " "
+ rank_text += f"{medal} {entry['username'][:12]}: {entry['points']} 点\n"
+
+ if user_info:
+ rank_text += "────────────────────\n"
+ rank_text += (
+ f"👤 我的状态:\n"
+ f"└ 积分: {user_info['points']}\n"
+ f"└ 发言: {user_info['message_count']} 次"
+ )
+
+ bot.send_message(message.chat.id, rank_text, parse_mode="HTML")
+
@bot.message_handler(commands=["deb"])
def deb_accuracy(message):
"""查询 DEB 融合预测的历史准确率"""
@@ -705,6 +732,19 @@ def start_bot():
logger.error(f"查询失败: {e}\n{traceback.format_exc()}")
bot.reply_to(message, f"❌ 查询失败: {e}")
+ @bot.message_handler(func=lambda message: True, content_types=['text'])
+ def track_activity(message):
+ """全量监听消息,用于记录群内发言积分(非指令消息)"""
+ if message.text.startswith('/'):
+ return
+
+ user = message.from_user
+ username = user.username or user.first_name or f"User_{user.id}"
+ db.upsert_user(user.id, username)
+
+ # 增加积分 (5秒冷却防刷屏,每个自然发言给 1 分)
+ db.add_message_activity(user.id, points_to_add=1)
+
logger.info("🤖 Bot 启动中...")
bot.infinity_polling()
diff --git a/docs/COMMERCIALIZATION.md b/docs/COMMERCIALIZATION.md
index 6f6b0bf4..ff509b37 100644
--- a/docs/COMMERCIALIZATION.md
+++ b/docs/COMMERCIALIZATION.md
@@ -1,35 +1,141 @@
-# PolyWeather 商业化技术升级草案
+# Commercialization Plan
-## 1. 核心目标
+## Product Direction
-将 PolyWeather 从单人工具转型为支持多用户的 SaaS 产品。
+PolyWeather is being positioned as a paid weather intelligence product built around:
+- Web dashboard subscription
+- Telegram paid group subscription
+- Fast, rules-based weather alerting
+- High-confidence Ankara specialization
-## 2. 架构调整 (Architecture Upgrade)
+Current pricing target:
+- Web dashboard: $5 / month
+- Telegram paid group: $1 / month
-### 2.1 用户与订阅系统 (Auth & Sub)
+Current payment direction under discussion:
+- Polygon / USDC
-- **前端**: 增加 Login 模态框,支持 Telegram 一键登录。
-- **后端 (FastAPI)**: 增加用户数据库 (`users` 表),存储 `telegram_id`, `subscription_status`, `expiry_date`。
-- **权限中间件**: 拦截未经授权的实时 API 请求。
+Important current state:
+- Polymarket market-price integration has been removed from the codebase
+- The current product focuses on weather intelligence, not exchange/orderbook execution data
-### 2.2 网页功能增强 (Web Premium)
+## Production Architecture
-- **实时性**: 付费用户 30s 刷新一次,免费用户 15min 刷新。
-- **专业视图**: 增加各模型历史 MAE (平均绝对误差) 实时排行榜,让用户知道安卡拉今天该信 MGM 还是 GFS。
-- **推送配置**: 允许用户在网页端订阅特定城市的“突破预警”。
+### Web
+- Next.js frontend on Vercel
+- Public URL: `https://polyweather-pro.vercel.app/`
+- FastAPI backend serves API only
-### 2.3 电报机器人深度集成 (Bot Monitization)
+### Backend
+- FastAPI on VPS
+- Shared analysis layer for web and bot
+- City data cache in-process
-- **邀请管理**: 自动生成独一无二的支付链接或入群链接。
-- **私人简报**: 每小时向 $1 订阅用户私聊发送其关注城市的“结算风险报告”。
+### Telegram
+- Bot runs on VPS
+- Paid group receives proactive alerts
+- Push engine includes dedupe, cooldown, and late-day suppression
-## 3. 支付方案 (Payment Integration)
+## Alert Product Strategy
-- **Polygon (USDC)**: 完美契合 Polymarket 生态。
-- **逻辑**: 用户转账 -> Webhook 回调 -> 自动激活账户权限。
+Current alert strategy is weather-first:
+- Ankara Center reached DEB
+- Momentum spike
+- Forecast breakthrough
+- Advection / nearby lead station
-## 4. 商业化阶段
+Operational controls already implemented:
+- Same city + same trigger type only pushes once while active
+- City-level cooldown
+- Peak-passed suppression for late-day rollover
-- **Phase 1 (Beta)**: 邀请制内测,验证安卡拉等重点城市的数据准确性。
-- **Phase 2 (MVP)**: 上线手动支付激活模式(人工进群)。
-- **Phase 3 (Full)**: 全自动 Web3 登录 + USDC 支付 + 自动入群。
+Ankara special handling:
+- Center signal only uses `Ankara (Bolge/Center)` / `17130`
+- This should remain a product differentiator and be documented clearly in sales copy
+
+## Recommended Subscription Structure
+
+### Tier A: Telegram Group
+- Price: $1 / month
+- Value proposition:
+ - Real-time proactive weather alerts
+ - Fast anomaly delivery
+ - Focused operational signal, minimal clutter
+- Suggested restrictions:
+ - No raw API access
+ - No historical analytics export
+ - No advanced chart controls
+
+### Tier B: Web Dashboard
+- Price: $5 / month
+- Value proposition:
+ - Full city dashboard
+ - Trend and nearby-station visualization
+ - Multi-model comparison
+ - Historical view
+- Suggested restrictions:
+ - View-only unless future premium tools are added
+
+### Bundle Option
+- Optional future bundle: Web + Group
+- Use only if conversion data shows users want both together
+
+## Payment Roadmap
+
+### Phase 1: Manual Ops
+- User pays manually
+- Operator manually activates web access / Telegram access
+- Lowest engineering cost, fastest launch
+
+### Phase 2: Polygon / USDC Automation
+- Generate unique deposit address or payment intent
+- Confirm on-chain payment
+- Activate subscription automatically
+- Telegram bot issues one-time group invite link
+
+### Phase 3: Full Subscription Management
+- Renewal reminders
+- Grace period handling
+- Automatic expiry / revocation
+- Self-serve billing status page
+
+## Recommended Near-Term Roadmap
+
+### Step 1: Stabilize Current Product
+- Finish cleaning docs and deployment flow
+- Keep Vercel as the only web entry point
+- Keep backend API-only
+- Tune Telegram cooldown and trigger quality
+
+### Step 2: Launch Manual Paid Beta
+- Start with a small paid Telegram group
+- Start web dashboard on invite basis
+- Track which alert types users actually value
+
+### Step 3: Add Access Control
+- Web login and session layer
+- Subscription table in backend
+- Telegram membership verification
+
+### Step 4: Add Polygon / USDC Collection
+- Payment detection
+- Subscription activation
+- One-time Telegram invite issuance
+
+## Metrics To Track
+
+Minimum metrics before scaling:
+- Alert-to-action usefulness feedback
+- Daily active dashboard users
+- Telegram retention after first payment cycle
+- Most valuable cities by engagement
+- False-positive complaint rate for alerts
+
+## Constraints To Keep In Mind
+
+- The current system is strongest in weather intelligence, not execution plumbing
+- Ankara is a differentiated niche and should be treated as premium signal inventory
+- Over-pushing alerts will destroy paid-group value faster than under-pushing
+- Payment automation should come after alert quality is operationally stable
+
+Last updated: 2026-03-06
diff --git a/docs/TECH_DEBT.md b/docs/TECH_DEBT.md
index 32f78856..61a1ad63 100644
--- a/docs/TECH_DEBT.md
+++ b/docs/TECH_DEBT.md
@@ -1,116 +1,115 @@
-# PolyWeather 技术债与演进路线
+# Technical Debt
-> 最后更新:2026-03-05
+Last updated: 2026-03-06
----
+## Current State
-## 一、当前完成度:约 65%
+Overall system status: usable and deployable.
-### ✅ 已经可用
+Stable pieces:
+- Multi-source weather collection
+- DEB forecast blending
+- Web dashboard on Vercel
+- FastAPI API backend
+- Telegram proactive push loop
+- Alert dedupe and cooldown
+- Late-day peak suppression
-| 模块 | 状态 | 说明 |
-| ---------------- | ------------ | -------------------------------------------------------------- |
-| 多源数据采集 | **可用** | Open-Meteo / ECMWF / GFS / ICON / GEM / JMA / METAR / MGM |
-| DEB 动态融合预报 | **可用** | 误差加权 + 自学习 + 冷启动处理 |
-| 概率引擎 | **基本可用** | Gaussian 拟合 + Shock Score + 时间衰减 + 实况锚定 μ + 死盘覆盖 |
-| AI 决策 | **基本可用** | P0→P4 分级框架 + 预报失准分级 + 高可用降级 |
-| Telegram Bot | **稳定运行** | 当前最成熟的交互端 |
-| Web 仪表盘 | **基本可用** | 全功能地图 + 面板 + 图表,支持 5rd/多模型联动与强制刷新 |
-| 部署 | **可用** | Docker + 传统 VPS 双通道,`update.sh` 一键部署 |
+Recently removed:
+- Old FastAPI static web page
+- Polymarket market-price integration
+- `/tradealert` preview command
-### ⚠️ 真实能力边界
+## High-Priority Debt
-1. **概率引擎的 μ 是手工规则(非统计学习的)**。70/30 加权 + 实况锚定的逻辑在多数情况下"看起来合理",但没有经过回测校准,在极端天气下的准确性无统计保障。
-2. **AI 决策是"结构化的猜测"**。Prompt 再精巧,底层仍是 LLM 概率续写。AI 有时自相矛盾,置信度是自评的,不代表真实概率。
-3. **Shock Score 是启发式指标**。风向/云量/气压权重(0.4/0.35/0.25)未经回归验证。
-4. **DEB 自学习窗口只有 7 天**,无法捕捉季节性趋势。
-5. **Web 端图表已对齐实测**。利用 MGM 逐小时预报和实测数据,安卡拉等重点城市的日内曲线已实现预报与实况的实时拟合叠加。
+### 1. Bot orchestration is still too centralized
+`bot_listener.py` is operational, but too much runtime behavior is still coordinated from a single entrypoint.
----
+Impact:
+- Harder to test
+- Harder to evolve subscription logic
+- Harder to isolate push bugs
-## 二、技术债
+Suggested direction:
+- Keep moving push and analysis concerns into `src/utils` and `src/analysis`
-### 🔴 高优先级 (✅ 本期已全部清理)
+### 2. Alert transparency needs better operator visibility
+The system now pushes the correct trigger types more conservatively, but group operators still need better evidence lines.
-| 问题 | 影响 | 状态 |
-| -------------------------- | ------------------------------------------------------------------------ | --------------------------------------------------------------------------- |
-| `bot_listener.py` 过于臃肿 | 单文件 1200 行,混杂数据处理、概率计算、趋势分析、AI 调用。可维护性极差 | ✅ **已拆分**:提取近 500 行核心逻辑至 `src/analysis/trend_engine.py` |
-| Web 与 Bot 概率引擎重复 | 两端各有独立的概率计算代码。AI 上下文已统一,但概率分布仍各算各的 | ✅ **已统一**:Web 端已完全删除自己的引擎,直接复用 `trend_engine` 输出结果 |
-| 无测试覆盖 | 概率引擎、DEB 算法、趋势分析等核心逻辑没有单元测试,任何改动只能人肉验证 | ✅ **已覆盖**:建立 `pytest` 机制,编写 15 个用例完全覆盖核心引擎逻辑 |
+Impact:
+- Hard to audit why a message fired
+- Hard to distinguish strong vs weak advection calls
-### 🟡 中优先级
+Suggested direction:
+- Add a compact `依据 / Evidence` line to alert messages
+- Expose raw trigger metrics in a debug API or operator log
-| 问题 | 影响 | 建议 |
-| ------------------ | --------------------------------------------------------------------------- | -------------------------------------------------------------------------------- |
-| 无回测框架 | 无法用历史数据验证算法改动是否真的提升了准确率,改代码全凭直觉 | 用 `fetch_history.py` 的数据搭回测管线 |
-| 硬编码阈值散落各处 | 死盘 (3°C/1.5°C)、forecast bust (2°C)、Shock Score 权重等直接写在业务代码里 | 提取到配置文件或 `constants.py` |
-| MGM 数据源不稳定 | 经常 403,数据频率受限 | ✅ **已解决**:采用自定义 Header + 随机时间戳 + 5级 API 遍历抓取,稳定性大幅提升 |
+### 3. No persistent application store for subscriptions
+Current architecture is ready for commercialization planning, but there is no real subscription state model yet.
-### 🟢 低优先级
+Impact:
+- No paid access enforcement
+- No renewal logic
+- No expiry / access revocation
-| 问题 | 影响 | 建议 |
-| ----------------- | --------------------------------------------------- | -------------------------- |
-| 缓存策略粗糙 | Web 端用简单 dict + 过期时间,无 LRU 或容量限制 | 引入 `cachetools` 或 Redis |
-| 日志没有结构化 | loguru 直接 print,上线后难做分析和报警 | 改用 JSON 格式 + 集中收集 |
-| CI badge 链接失效 | 已移除 GitHub Actions 但 README 之前还留着 CI badge | 已在本次文档更新中修复 |
+Suggested direction:
+- Add a database-backed subscription table before automating billing
----
+## Medium-Priority Debt
-## 三、未完成功能
+### 4. Backtesting is still missing
+The system has live rules, but no proper replay framework for validating whether rule changes improve quality.
-| # | 功能 | 说明 |
-| --- | ------------------- | ---------------------------------------------------------------- |
-| 1 | 历史数据消费 | `fetch_history.py` 可采集 3 年数据,但没有任何模型在使用 |
-| 2 | 结算自动对账 | 系统已支持通过 `/deb` 查看命中率,但尚未实现自动生成昨日总结推送 |
-| 3 | 交易信号输出 | 系统只给分析建议,不输出可执行的交易信号 |
-| 4 | Web 身份认证 | 任何人都可以访问 Web 面板 |
-| 5 | 主动推送 | 预报崩盘或结算边界预警时不会主动通知用户 |
-| 6 | 完整日内 METAR 走势 | `trend.recent` 只保留最近 4 条,无法展示完整日内观测曲线 |
+Impact:
+- Rule changes are hard to evaluate objectively
+- Alert tuning is still partly manual
----
+Suggested direction:
+- Build a replay harness from stored observations and forecasts
-## 四、演进路线
+### 5. Thresholds remain code-defined
+Important thresholds are still embedded in Python.
-### 短期(1-2 周)— 偿还核心债务
+Examples:
+- Momentum slope threshold
+- Peak-passed rollback threshold
+- Advection lead delta threshold
+- Cooldown defaults
-1. **拆分 `bot_listener.py`**
- - 将 `analyze_weather_trend` 移到 `src/analysis/trend_engine.py`
- - 将概率引擎移到 `src/analysis/probability.py`
- - `bot_listener.py` 只保留 Telegram 交互逻辑
+Suggested direction:
+- Extract to constants or structured config
-2. **概率引擎统一**
- - Web 端概率计算应直接调用共享模块的结果
- - 消除两份独立实现
+### 6. Frontend still uses a legacy shell inside Next
+The production frontend is on Vercel, but the page is still driven by `public/legacy/index.html` plus static scripts.
-3. **核心单元测试**
- - 测试范围:μ/σ 计算、死盘判定、forecast bust 检测、DEB 权重计算
- - 不追求覆盖率,追求"改代码时有安全网"
+Impact:
+- Slower UI evolution
+- Harder component-level reuse
+- Harder design-system integration
-### 中期(1-2 月)— 建立校验能力
+Suggested direction:
+- Migrate the legacy dashboard into native Next components incrementally
-4. **回测框架**
- - 用历史数据跑"过去 90 天每天的 μ 偏差是多少"
- - 这是证明概率引擎有效的唯一方式
+## Low-Priority Debt
-5. **结算自动对账**
- - 每天自动拉取合约实际结算结果
- - 与系统前一天的预测做比对,自动生成准确率报告
+### 7. Caching is simple in-process cache only
+Current cache is sufficient for the current deployment size, but not ideal long term.
-6. **推送机制**
- - 检测到 forecast bust 或结算边界预警时主动推送 Telegram 通知
+Suggested direction:
+- Move to Redis or another shared cache if multi-instance deployment is needed
-### 长期(3+ 月)— 从规则到模型
+### 8. Test tooling is not fully provisioned everywhere
+The repository has tests, but some environments still do not have `pytest` installed.
-7. **MOS/XGBoost 替代手工 μ**
- - 用历史 METAR + 模型预报训练后处理模型
- - 概率引擎从"合理的猜测"升级到"可校验的预测"
+Impact:
+- Harder to run full verification on every host
-8. **多市场适配**
- - 当前只针对温度合约
- - 扩展到降水、风速等需要重构分析框架
+Suggested direction:
+- Standardize test dependencies in deployment and CI environments
----
+## Immediate Next Steps
-## 五、一句话总结
-
-> PolyWeather 目前最大的价值是**信息聚合和格式化**——把分散在多个 API 的气象数据整合成可快速消化的仪表盘。至于"预测准不准",诚实的回答是:**不知道,因为还没有建立衡量准确率的机制**。
+1. Add evidence lines to Telegram alerts
+2. Finish cleaning backend naming after removal of old static web flow
+3. Design subscription storage for commercialization
+4. Start replay/backtest tooling for alert-quality tuning
diff --git a/frontend/README.md b/frontend/README.md
index ce15b96f..065f8d68 100644
--- a/frontend/README.md
+++ b/frontend/README.md
@@ -1,14 +1,27 @@
-# PolyWeather Frontend (Next.js)
+# PolyWeather Frontend
-Standalone web frontend for `polyweather.vercel.app`.
+This directory is the only web frontend in production.
+
+Production URL:
+- https://polyweather-pro.vercel.app/
## Stack
-- Next.js 14+ (App Router)
+- Next.js App Router
- Tailwind CSS
- Lucide React
-- shadcn/ui base components
-- Leaflet (react-leaflet)
+- shadcn/ui base layer
+- Legacy dashboard shell loaded from `public/legacy/index.html`
+
+## Production Model
+
+- Vercel serves the web UI
+- FastAPI on VPS serves API only
+- The old FastAPI static website has been removed
+
+Current request flow:
+- Browser -> Vercel frontend
+- Vercel route handlers -> FastAPI API
## Local Development
@@ -19,32 +32,37 @@ npm install
npm run dev
```
-Default frontend URL: `http://localhost:3000`
+Default local URL:
+- http://localhost:3000
-## Backend API
+## Required Environment Variable
-Set `POLYWEATHER_API_BASE_URL` to your FastAPI service URL.
-
-Example:
-
-```bash
-POLYWEATHER_API_BASE_URL=https://api.yourdomain.com
+```env
+POLYWEATHER_API_BASE_URL=https://
```
-The frontend uses Next Route Handlers as a thin BFF layer:
+Examples:
+- `http://38.54.27.70:8000`
+- `https://api.example.com`
+## Route Handlers
+
+Thin BFF routes currently exposed by Next:
- `GET /api/cities`
-- `GET /api/city/:name`
+- `GET /api/city/[name]`
+- `GET /api/history/[name]`
## Vercel Deployment
-1. Import this repo in Vercel.
-2. Set **Root Directory** to `frontend`.
-3. Add environment variable:
- - `POLYWEATHER_API_BASE_URL=https://`
-4. Deploy.
+1. Import the repo into Vercel
+2. Set Root Directory to `frontend`
+3. Set `POLYWEATHER_API_BASE_URL`
+4. Deploy
## Notes
-- Backend CORS must allow `https://polyweather.vercel.app`.
-- This is phase-1 split: map + city list + detail panel are migrated first.
+- Backend CORS must allow `https://polyweather-pro.vercel.app`
+- The page shell currently embeds the legacy dashboard HTML from `public/legacy/index.html`
+- If you change files under `public/static`, deploy to Vercel to make them live
+
+Last updated: 2026-03-06
diff --git a/src/database/db_manager.py b/src/database/db_manager.py
new file mode 100644
index 00000000..bf9c583c
--- /dev/null
+++ b/src/database/db_manager.py
@@ -0,0 +1,109 @@
+import sqlite3
+import os
+from datetime import datetime, timedelta
+from typing import Optional, Dict, Any
+from loguru import logger
+
+class DBManager:
+ def __init__(self, db_path: str = "polyweather.db"):
+ self.db_path = db_path
+ self._init_db()
+
+ def _get_connection(self):
+ return sqlite3.connect(self.db_path)
+
+ def _init_db(self):
+ """Create tables if they don't exist."""
+ # Ensure directory exists
+ os.makedirs(os.path.dirname(self.db_path), exist_ok=True)
+ with self._get_connection() as conn:
+ conn.execute("""
+ CREATE TABLE IF NOT EXISTS users (
+ telegram_id INTEGER PRIMARY KEY,
+ username TEXT,
+ is_web_premium BOOLEAN DEFAULT 0,
+ web_expiry TIMESTAMP,
+ is_group_premium BOOLEAN DEFAULT 0,
+ group_expiry TIMESTAMP,
+ points INTEGER DEFAULT 0,
+ message_count INTEGER DEFAULT 0,
+ last_message_at TIMESTAMP,
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
+ )
+ """)
+ conn.commit()
+ logger.info("Database initialized successfully.")
+
+ def get_user(self, telegram_id: int) -> Optional[Dict[str, Any]]:
+ with self._get_connection() as conn:
+ conn.row_factory = sqlite3.Row
+ cursor = conn.execute("SELECT * FROM users WHERE telegram_id = ?", (telegram_id,))
+ row = cursor.fetchone()
+ if row:
+ user = dict(row)
+ now = datetime.now()
+ if user['web_expiry']:
+ expiry = datetime.fromisoformat(user['web_expiry'])
+ if expiry < now:
+ user['is_web_premium'] = False
+ if user['group_expiry']:
+ expiry = datetime.fromisoformat(user['group_expiry'])
+ if expiry < now:
+ user['is_group_premium'] = False
+ return user
+ return None
+
+ def upsert_user(self, telegram_id: int, username: str):
+ with self._get_connection() as conn:
+ conn.execute("""
+ INSERT INTO users (telegram_id, username)
+ VALUES (?, ?)
+ ON CONFLICT(telegram_id) DO UPDATE SET
+ username = excluded.username
+ """, (telegram_id, username))
+ conn.commit()
+
+ def add_message_activity(self, telegram_id: int, points_to_add: int = 1):
+ """Update message count and add points with simple anti-spam logic."""
+ now = datetime.now()
+ with self._get_connection() as conn:
+ cursor = conn.execute("SELECT last_message_at FROM users WHERE telegram_id = ?", (telegram_id,))
+ row = cursor.fetchone()
+ if row and row[0]:
+ last_at = datetime.fromisoformat(row[0])
+ if (now - last_at).total_seconds() < 5: # 5 second cooldown
+ return False
+
+ conn.execute("""
+ UPDATE users
+ SET message_count = message_count + 1,
+ points = points + ?,
+ last_message_at = ?
+ WHERE telegram_id = ?
+ """, (points_to_add, now.isoformat(), telegram_id))
+ conn.commit()
+ return True
+
+ def set_premium(self, telegram_id: int, plan: str, months: int = 1):
+ expiry = datetime.now() + timedelta(days=30 * months)
+ col_is = f"is_{plan}_premium"
+ col_expiry = f"{plan}_expiry"
+ with self._get_connection() as conn:
+ conn.execute(f"""
+ UPDATE users
+ SET {col_is} = 1, {col_expiry} = ?
+ WHERE telegram_id = ?
+ """, (expiry.isoformat(), telegram_id))
+ conn.commit()
+ logger.info(f"User {telegram_id} upgraded to {plan} premium until {expiry}")
+
+ def get_leaderboard(self, limit: int = 10):
+ with self._get_connection() as conn:
+ conn.row_factory = sqlite3.Row
+ cursor = conn.execute("""
+ SELECT username, points, message_count
+ FROM users
+ ORDER BY points DESC
+ LIMIT ?
+ """, (limit,))
+ return [dict(row) for row in cursor.fetchall()]