dca4f2d618
- web/core.py 858→236行,拆出 schemas/middleware/auth/diagnostics - ops_api.py 2876→4个 domain 模块 (users/payments/health/config) - DBManager Supabase HTTP 调用提取到 SupabaseAdminClient - 新增 LockedSQLiteConnection 统一多进程读写锁 - 新增 WeatherCacheManager 替代 12 个独立缓存字典 - METAR 缓存迁移至统一缓存管理器 - analysis_service 提取 _build_intraday_meteorology 到独立模块 - DEB 改进:偏差惩罚、分歧回退、自适应 lookback (MAE ↓12.6%) - 新增 PyTorch 注意力模型 deb_attention.py (数据积累后启用) - 新增 torch 到 requirements.lock
147 lines
6.9 KiB
Markdown
147 lines
6.9 KiB
Markdown
# CLAUDE.md
|
|
|
|
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
|
|
## Project Overview
|
|
|
|
PolyWeather Pro — a paid institutional weather-intelligence terminal. 50 monitored cities with real-time METAR/AMOS/MADIS observations, DEB multi-model temperature blending, Mu probability calibration, and intraday bias correction. Pure meteorological decision workspace; no market/price layer. Next.js 15 + React 19 frontend (Docker / VPS, behind Cloudflare + Nginx), FastAPI backend (VPS), Telegram bot.
|
|
|
|
**Business model**: Paid-only, 29.9 USDC/month or 79.9 USDC/quarter, referral first month 20 USDC. New users get a one-time 3-day trial. Landing page is public; `/terminal` requires login + active subscription.
|
|
|
|
## Environment & Preferences
|
|
|
|
- Working directory: repo root
|
|
- Python: `python` (not python3), venv at `venv/`
|
|
- Frontend: `cd frontend && npm run dev` → localhost:3000
|
|
- Backend: `uvicorn web.app:app --reload --host 0.0.0.0 --port 8000`
|
|
- Package manager: **npm** (not yarn/pnpm)
|
|
- **Commit language: Chinese (简体中文) ONLY**
|
|
- **NEVER start commit messages with `@`** — Chinese directly, no prefix
|
|
|
|
## Commands
|
|
|
|
```bash
|
|
# Frontend
|
|
cd frontend
|
|
npm run dev # dev server :3000
|
|
npm run build # production build
|
|
npm run typecheck # tsc --noEmit
|
|
npm run test:business # 19 business state tests
|
|
|
|
# Backend
|
|
uvicorn web.app:app --reload --host 0.0.0.0 --port 8000
|
|
python bot_listener.py # Telegram bot
|
|
|
|
# Python tests
|
|
python -m pytest tests/
|
|
python -m pytest tests/test_supabase_entitlement.py
|
|
|
|
# Lint
|
|
ruff check .
|
|
ruff format .
|
|
|
|
# Docker (VPS)
|
|
docker compose down && docker compose up -d --build
|
|
```
|
|
|
|
## Architecture
|
|
|
|
```
|
|
Users → Cloudflare → Nginx → Docker Compose (VPS)
|
|
├── Next.js frontend → FastAPI :8000
|
|
│ /terminal (paid gate) Weather Collector
|
|
│ / (landing page) Analysis (DEB + Mu)
|
|
│ Payment Layer (USDC on Polygon)
|
|
└── Redis (SSE event store)
|
|
Telegram Bot → bot_listener.py
|
|
```
|
|
|
|
### Frontend Structure
|
|
|
|
| Path | Purpose |
|
|
|------|---------|
|
|
| `app/page.tsx` | Landing page (`InstitutionalLandingPage`) |
|
|
| `app/terminal/page.tsx` | Paid terminal (`ScanTerminalDashboard`) |
|
|
| `app/account/` | Account center with payment/subscription |
|
|
| `app/auth/` | Supabase login/signup |
|
|
| `components/dashboard/scan-terminal/` | Terminal sub-components |
|
|
| `components/account/` | Account + payment hooks |
|
|
| `components/landing/` | Institutional landing page |
|
|
| `components/subscription/` | `UnlockProOverlay` payment overlay |
|
|
| `lib/dashboard-types.ts` | All TypeScript types |
|
|
|
|
### Terminal Component Map
|
|
|
|
- `ScanTerminalDashboard.tsx` — entry, auth gate, `ProductAccessRequired`
|
|
- `PolyWeatherTerminal` — main layout: sidebar + region tabs + 2-column grid
|
|
- `CityRegionList` — city list panel (left top)
|
|
- `CityContractDetail` — contract table panel (left bottom)
|
|
- `LiveTemperatureThresholdChart` — multi-source overlay: obs + DEB + model curves + thresholds
|
|
- `RealtimeScrollChart` — lightweight realtime scrolling temperature + threshold bars
|
|
- `TrainingDashboard` — DEB + Mu accuracy charts (sidebar "训练数据" tab)
|
|
- `continent-grouping.ts` — 7 trading regions (`TRADING_REGIONS`), city-to-region fallback (`CITY_REGION_FALLBACK`), timezone detection (`detectLocalRegion`)
|
|
|
|
### Account Module
|
|
|
|
- `AccountCenter.tsx` (~1280 lines) — main component
|
|
- `useAccountPayment.ts` — master payment hook, composes sub-hooks
|
|
- `useWalletBind.ts` — EVM/WalletConnect binding
|
|
- `usePaymentFlow.ts` — intent creation, payment, confirmation
|
|
- `useBilling.ts` — subscription recovery, billing computation
|
|
|
|
### Backend Key Files
|
|
|
|
| Path | Purpose |
|
|
|------|---------|
|
|
| `web/routers/city.py` | City detail/summary/realtime-stream endpoints |
|
|
| `web/routers/scan.py` | Scan terminal aggregation |
|
|
| `web/services/city_payloads.py` | City detail and summary payload builders |
|
|
| `web/scan_terminal_city_row.py` | Builds terminal rows from analysis data |
|
|
| `src/data_collection/city_registry.py` | 50-city registry with tz_offset |
|
|
| `src/analysis/deb_algorithm.py` | DEB prediction + Mu calibration + accuracy |
|
|
| `web/services/analysis_utils.py` | Clock helpers, bucket labeling, time parsing |
|
|
| `web/services/observation_freshness.py` | Source profiles and freshness computation |
|
|
| `web/services/scan_ai_config.py` | Scan terminal and AI configuration constants |
|
|
|
|
## Auth Gating
|
|
|
|
Middleware (`middleware.ts`) handles two layers:
|
|
1. **Terminal gate** (`handleTerminalGate`): `/terminal/*` → redirect to `/auth/login` if no Supabase session
|
|
2. **Global auth** (`handleSupabaseAuthGate`): enforced when `POLYWEATHER_AUTH_REQUIRED=true`
|
|
|
|
Client-side gate (`ProductAccessRequired`): `/terminal` checks auth + subscription via `/api/auth/me`, shows paywall if needed.
|
|
|
|
Local dev bypass: set `NEXT_PUBLIC_POLYWEATHER_LOCAL_FULL_ACCESS=false` to test auth locally.
|
|
|
|
## Polymarket Integration
|
|
|
|
**Removed.** No Polymarket price fetching, no market scan, no WS cache. Terminal operates on weather data only (Live observations + DEB predictions + model probabilities). All `polymarket_readonly.py`, `polymarket_ws_cache.py`, and market-scan API routes have been deleted.
|
|
|
|
## Trading Regions
|
|
|
|
7 regions: east_asia, southeast_asia, central_asia, west_asia, europe_africa, south_america, north_america. Mappings in `continent-grouping.ts` (`CITY_REGION_FALLBACK` — all 50 cities hardcoded) and `scan_terminal_filters.py` (`market_region_from_tz_offset`). Default region auto-detected from browser timezone.
|
|
|
|
## Scan Terminal Performance
|
|
|
|
- **Region lazy-loading**: `region=east_asia` filters cities server-side before scanning (see `_market_region_from_tz_offset`)
|
|
- **Weather-only**: Terminal returns 1 row per city with Live/DEB/probability data; no market contract matching
|
|
- **DB**: SQLite WAL mode + `busy_timeout=5000` enabled in `db_manager.py` (fixes "database is locked" with parallel workers)
|
|
- **VPS env**: `POLYWEATHER_SCAN_TERMINAL_MAX_WORKERS=2`, `POLYWEATHER_SCAN_TERMINAL_BUILD_TIMEOUT_SEC=180`
|
|
- **Caching**: `_cache` is `LRUDict(256)` with `_CACHE_LOCK`; `_SUMMARY_CACHE` is `LRUDict(128)`; weather caches trimmed every 200 writes
|
|
|
|
## Intraday Bias Correction
|
|
|
|
`analysis_service.py:_analyze()` applies intraday correction after probability generation:
|
|
- Compares current observed temp vs model hourly forecast for current hour
|
|
- Time-of-day weight: 0.15↗0.35 pre-peak, 0.40↗0.75 during peak, 0.80 post-peak
|
|
- Also checks if max-so-far already exceeds DEB prediction (strong upward nudge)
|
|
- Correction capped at ±5°F / ±3°C, applied to both `deb_val` and `mu`
|
|
|
|
## Code Style
|
|
|
|
- No `\uXXXX` escapes — write characters directly in UTF-8
|
|
- Use `var(--color-*)` CSS tokens, not hardcoded hex
|
|
- Minimum font size: 10px (`text-[10px]`)
|
|
- Avoid `!important` except Leaflet map overrides
|
|
- Remove dead code immediately when features are removed
|