11 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Project Overview
PolyWeather Pro — a production weather-intelligence stack for temperature settlement markets. Aggregates observations and forecasts for 52 monitored cities globally, blends multi-model highs using DEB (Dynamic Error Balancing), generates calibrated probability buckets for settlement, maps weather to Polymarket quotes for mispricing scans, and serves both a Next.js dashboard (Vercel) and a Telegram bot.
Environment & Preferences (ALWAYS follow)
Working Directory
- All commands run from the repo root:
E:/web/PolyWeather - Frontend dev server:
cd frontend && npm run dev→ http://localhost:3000 - Backend API server:
uvicorn web.app:app --reload --host 0.0.0.0 --port 8000→ http://localhost:8000 - When I say "start the server", assume the correct working directory is
E:/web/PolyWeather
Git Conventions
- Commit language: Chinese (简体中文) ONLY
- Format: Lore Commit Protocol — intent line in Chinese, trailers in English
- Examples:
重构城市决策卡 hero 布局or统一 DEB 数据源为单一计算路径 - NEVER use English for commit subject lines
Tooling
- Package manager: npm (not yarn/pnpm)
- Python:
python(not python3), venv atvenv/ - Lint:
ruff check .(Python) +npx tsc --noEmit(TypeScript) - NEVER ask me about these preferences again — commit to memory
Architecture
Users (Web / Telegram) → Next.js Frontend (Vercel) → FastAPI /web/app.py
↓
Weather Collector (METAR, TAF, Open-Meteo, country networks)
↓
Analysis (DEB + Trend + Probability + Market Scan)
↓
Payment Layer (Intent + Event + Confirm Loop)
- Backend: FastAPI on port 8000 (
web/app.py→web/app_factory.py→web/routers/(8 route modules) +web/services/(14 service modules) +web/core.py) - Frontend: Next.js 15 + React 19 + TypeScript + Tailwind CSS 3 + shadcn/ui (new-york style) on port 3000 (dev)
- Bot: Telegram bot via
bot_listener.py→src/bot/ - Shared analysis core in
src/is used by both web API and bot - Scan Terminal: Real-time city opportunity scanning (
web/scan_terminal_service.pyandfrontend/components/dashboard/scan-terminal/) - Dashboard: Main dashboard with interactive map, city sidebar, detail panels, and probability views
- Market Monitor (
MonitorPanel): Real-time temperature monitoring board for 22 trading cities. Uses a temperature resolution chain (AMOS runway → AMOS →airport_primary→airport_current→current) defined infrontend/components/dashboard/monitoring/monitor-temperature.ts. Per-city refresh decisions driven by source-aware freshness (source-freshness.ts) instead of uniformobs_age_min. Seoul/Busan display runway surface temperature from AMOS; US cities get 5-min MADIS HFMETAR viaairport_primary; others fall back to METAR. - High-Freq Airport Pipeline: 19 of 22 monitor cities have dedicated realtime sources (AMOS, MADIS, JMA, MGM, FMI, KNMI, AROME). Data flows:
weather_sources.py(fetch) →country_networks.py(_airport_primary_from_raw, per-country providers) → APIairport_primaryfield. Plain METAR stays inairport_current. Documented indocs/AIRPORT_REALTIME_SOURCES.md. - Country Network Providers:
country_networks.pyroutes per-city to the right provider (Turkey→MGM, Korea→KMA, Japan→JMA, etc.) viaget_country_network_provider(). Each provider controlsairport_primary_current,official_nearby_current, andofficial_network_status. US cities use the defaultGlobalMetarNetworkProviderbut get MADIS overrides injected viaresults["madis_hfmetar_current"].
Commands
Frontend (dev on port 3000)
cd frontend
npm ci
npm run dev # Next.js dev server (runs sync-next-server-chunks.mjs first)
npm run build # Production build (runs sync-next-server-chunks.mjs after)
npm run start # Production server
npm run lint # ESLint via next lint
npm run typecheck # tsc --noEmit
npm run test:business # Business state tests (also runs in CI)
Backend (dev on port 8000)
uvicorn web.app:app --reload --host 0.0.0.0 --port 8000
Telegram Bot
python bot_listener.py
# or via wrapper:
python run.py
Docker (production-like stack)
docker compose up -d --build # bot + web API (polyweather + polyweather_web)
The compose file defines two services: polyweather (bot) and polyweather_web (FastAPI on :8000). Prewarm worker and monitoring profiles were removed in v1.6.0.
Python tests
pytest tests/ # all tests
pytest tests/test_web_observability.py # single test file
Lint & Format
ruff check . # Python lint (pycodestyle + Pyflakes, line-length 88)
ruff format . # Python format (Black-compatible, double quotes)
Health & Ops checks
curl http://127.0.0.1:8000/healthz
curl http://127.0.0.1:8000/api/system/status
curl http://127.0.0.1:8000/metrics
Key Directories
| Directory | Purpose |
|---|---|
src/analysis/ |
DEB algorithm, trend engine, probability calibration (EMOS/LGBM), market alert engine, settlement rounding |
src/auth/ |
Supabase entitlement checks, Telegram group pricing |
src/bot/ |
Telegram bot handlers and orchestrator |
src/database/ |
SQLite-based runtime state, DB manager, daily/truth/training feature repositories |
src/data_collection/ |
Weather sources (METAR, TAF, Open-Meteo, JMA, KMA, MGM, NMC, Russia stations, settlement sources), city registry (52 cities), Polymarket readonly layer. Also: madis_sources.py (NOAA 5-min NetCDF), amos_station_sources.py (Korean runway sensors), country_networks.py (per-country provider routing + _airport_primary_from_raw) |
src/data_mining/ |
Historical data fetch utilities |
src/models/ |
LightGBM daily-high model training and feature engineering |
src/onchain/ |
Polygon wallet watcher, Polymarket wallet activity watcher |
src/payments/ |
Onchain checkout, event listener, confirm loop, contract audit |
src/strategy/ |
Trading strategy modules |
src/trading/ |
Trading execution modules |
src/utils/ |
Shared utilities: config loader, logging, metrics, Telegram push, chat ID helpers |
web/ |
FastAPI app (app.py → app_factory.py), routers/ (8 route modules), services/ (14 service modules), core.py, scan terminal modules (AI fallback, AI prompts, METAR gate, city rows, ranker, cache) |
frontend/app/ |
Next.js App Router pages (dashboard, account, auth, docs, ops, probabilities, scan) |
frontend/components/dashboard/ |
Dashboard UI components (map, sidebar, detail panel, modals, charts, scan terminal). scan-root-styles.ts is the CSS Module barrel, combining 22 module roots into one pre-composed className. monitoring/ subdirectory: MonitorPanel, monitor-temperature.ts (temp resolution chain), monitor-refresh-policy.ts. |
frontend/lib/ |
Shared client logic: types (dashboard-types.ts, including AirportCurrentConditions, CityDetail), API client, chart utils, i18n, source-freshness.ts (per-source freshness with expected_next_update_at), dashboard utils |
frontend/hooks/ |
React hooks: dashboard store (global state), Leaflet map, chart helper |
scripts/ |
Operational scripts: probability calibration training, backfills, payment reconciliation. supabase/ subdirectory: DB schema and migration SQL. |
config/ |
YAML config (city list, weather settings, logging) |
docs/ |
Bilingual product & technical docs |
Key Technical Details
- Python version: 3.11 (target), type hints use
from __future__ import annotationsin most modules - Package manager: pip (requirements.txt) + uv cache is present but not the primary tool; no pyproject.toml build system defined
- Frontend package manager: npm
- State storage: SQLite primary path (set via
POLYWEATHER_STATE_STORAGE_MODE=sqlite+POLYWEATHER_DB_PATH). Legacy JSON/JSONL files are migration/fallback only. - Runtime data: External dir recommended (
POLYWEATHER_RUNTIME_DATA_DIR=/var/lib/polyweather) to avoid git conflicts - Configuration:
.env.exampleis the comprehensive reference (8 config sections: runtime, Telegram, weather cache, auth, ops, frontend, optional modules, Polygon monitor). Copy to.envand fill in secrets. - Auth gating (frontend middleware): Token-based (
POLYWEATHER_DASHBOARD_ACCESS_TOKEN) or Supabase session-based (POLYWEATHER_AUTH_ENABLED). Local dev hosts bypass auth. - CORS: Allowed origins from
WEB_CORS_ORIGINSenv var (defaults: localhost:3000, polyweather-pro.vercel.app) - EMOS/CRPS calibration: Trainable but production should use
legacyoremos_shadowengine;emos_primaryonly after local evaluation + manual rollout - API proxy: Frontend uses Next.js rewrites to proxy
/api/*to the FastAPI backend; seefrontend/lib/api-proxy.tsandfrontend/lib/backend-api.ts
Commit Convention
This repo uses the Lore Commit Protocol — structured decision records with git trailers (Constraint:, Rejected:, Confidence:, Scope-risk:, Directive:, Tested:, Not-tested:). Intent line first (why, not what).
- Always write git commit messages in Chinese (简体中文).
Code Style
- Never use Unicode escape sequences (
\uXXXX) in source code; write characters directly in UTF-8 encoding. - When modifying UI components, update both dark-mode and light-mode CSS files in the same edit batch.
- CSS Variables First: Prefer
var(--color-*)/var(--color-signal-*)tokens over hardcoded hex values. The token system is defined inglobals.csswith light-theme overrides underhtml.light. - Avoid
!important: Only use it for Leaflet map overrides (inline style conflict) and chart canvas sizing. For light-theme overrides, usehtml.light .rootprefix for higher specificity. - Monitoring CSS note:
MonitorPanel.module.cssscopes its light-theme overrides to.scan-terminal.light(the terminal's built-in toggle), NOThtml.light. When adding light styles for monitoring components, match this scoping. - New CSS Modules: Add the module root class to
scan-root-styles.tsbarrel file instead of importing it separately inScanTerminalDashboard.tsx.
Quality Gates (MANDATORY)
Before marking any task as complete, you MUST:
- Type check — Run
npx tsc --noEmit(frontend) orpython -m ruff check .(backend) on modified files - No Unicode escapes — Verify that NO
\uXXXXsequences were introduced; if found, revert and fix - Dual-theme CSS — For any UI change, confirm BOTH dark and light styles. Most components need
ScanTerminalLightTheme.module.cssupdated; monitoring components (MonitorPanel.module.css) contain their own.scan-terminal.lightblocks inline. - No new hardcoded palette colors — Use
var(--color-*)token references instead of#4DA3FF/#E6EDF3/#9FB2C7/#6B7A90hex values - Show the diff — Output
git diff --statand test results before declaring success
If any gate fails, fix it BEFORE reporting success.