Commit Graph

508 Commits

Author SHA1 Message Date
2569718930@qq.com 13a67cdc85 修复温度走势图不显示:移除 IntersectionObserver 延迟渲染
问题:图表只在 IntersectionObserver 检测到视口交叉后才渲染
- 卡片折叠时图表区域永远不可见,IntersectionObserver 不触发
- 小屏幕/快速滚动时图表可能来不及渲染

修复:
- 移除 IntersectionObserver 懒加载逻辑
- 图表始终立即渲染(useChart 在挂载时初始化)
- Chart.js animation:false 确保快速渲染,无性能代价
- 清理未使用的 useState/useEffect 导入
2026-05-10 18:34:00 +08:00
2569718930@qq.com fe3f48f255 城市决策卡新增 AMOS 跑道温度面板
- 新增 AmosRunwayPanel 组件:展示每条跑道的温度/露点/能见度/RVR/风速
- 跑道卡片网格布局 (auto-fit minmax 160px)
- 每条跑道独立显示:跑道编号、温度(含露点)、能见度、RVR、风速范围
- 官方 METAR 标签 vs 跑道中位数标签
- CityDetail 类型新增 AmosData 接口
- 暗色/浅色主题均已适配
- 仅首尔/釜山(有 AMOS 数据)时显示
2026-05-10 18:30:59 +08:00
2569718930@qq.com fe681503ae UX 审查收尾:AI 解读过渡标记 + 极端温度视觉强化
P2-17:AI 快速判断→完整解读过渡标记
- AiEvidencePanel 新增 useTransitionMarker hook
- AI 从 loading→ready 后显示"✓ Updated/已更新"徽标(4 秒后消失)
- 绿色动画徽标 fadeUpIn,避免用户以为信息没变

P2-18:极端温度视觉强化
- globals.css 新增 temp-extreme-hot(橙红辉光 ≥40°C/≥104°F)
- globals.css 新增 temp-extreme-cold(冰蓝辉光 ≤-5°C/≤23°F)
- PanelSections Hero 温度值自动应用极端温度样式

Tested: npx tsc --noEmit
2026-05-10 17:44:45 +08:00
2569718930@qq.com 341825747f UX 审查 P2 修复:X轴标签密度、极端温度视觉强化
- AiCityTemperatureChart:X轴标签从每4个→每3个显示,maxTicksLimit 6→8
- globals.css:新增 temp-extreme-hot(≥40°C)和 temp-extreme-cold(≤-5°C)样式
- PanelSections:Hero 温度值自动应用极端温度 CSS 类(橙色辉光/蓝色辉光)
- 华氏度自动适配:≥104°F 为极热,≤23°F 为极冷

Tested: npx tsc --noEmit
2026-05-10 17:39:22 +08:00
2569718930@qq.com d94476f943 UX 审查修复:统一修正术语、图表"现在"标记、专业术语解释、异常行动建议
P0-1 术语统一:
- WeatherDecisionBand 改用"上修/下修/维持"替代"偏高温/暂不追/等待确认"
- 与 AI 后端提示词使用的术语体系一致

P0-9 图表"现在"标记:
- chart-utils.ts 导出 currentIndex
- AiCityTemperatureChart 在 currentIndex 处绘制竖线(蓝色虚线)

P0-13 专业术语解释:
- DataFreshnessBar 新增 labelTitle 属性(hover tooltip)
- METAR → "机场气象观测报文" / "Meteorological Aerodrome Report"
- HKO → "香港天文台官方实测" / "Hong Kong Observatory official readings"

P0-16 异常行动建议:
- primaryReason 追加行动指引(实测突破→建议关注偏高温区间等待确认 / 峰值已过→建议避免追高 / 观测过旧→建议等待新报文)

P1-8 DEB 路径分段样式:
- 过去部分实线(已确定),未来部分虚线(预测不确定)

P1-11 HistoryChart 单位:
- tooltip 使用 temp_symbol 替代硬编码 °

Tested: npx tsc --noEmit
2026-05-10 17:33:15 +08:00
2569718930@qq.com 2b2784d811 数据链路 P2 修复:stale-while-revalidate + 扫描数据复用
P2-7 stale-while-revalidate:
- ensureCityDetail 过期缓存不再阻塞等待刷新
- 立即返回缓存数据,后台异步更新
- 用户打开已有缓存的城市时不再看到 loading spinner

P2-8 扫描终端数据复用:
- 新增 store.preloadCityFromRow():从 ScanOpportunityRow 预填充 cityDetails 缓存
- handleSelectRow / handleMapCitySelect / handleOpenDecisionRow 均调用预加载
- 用户从地图/列表/决策卡选城市后,详情面板立即显示缓存数据
- 后台自动拉取完整 detail(stale-while-revalidate)

Tested: npx tsc --noEmit
2026-05-10 17:00:12 +08:00
2569718930@qq.com b3ea8dcfa7 数据链路 P1 修复:ETag 缓存 + 校准漂移检测
P1-5 ETag 支持:
- 后端新增 _etag_middleware:GET /api/* 自动返回 ETag (MD5)
- 支持 If-None-Match 请求头,匹配时返回 304 + 30s Cache-Control
- 前端 cache: no-store → default,浏览器自动处理 ETag/304 节省带宽

P1-6 校准漂移检测:
- probability_calibration.py 新增 check_calibration_drift()
- 对比最近 200 条 daily_records 的 CRPS 与校准基线
- 漂移 >15% 时返回 warning 提示重新训练
- 集成到 /api/system/status 的 probability.drift 字段

Tested: python -m ruff check ., npx tsc --noEmit
2026-05-10 16:54:48 +08:00
2569718930@qq.com c0bb2acf78 修复数据链路 P0 瓶颈:缓存炸弹、Context 重渲染、LGBM 循环、TTL 不匹配
P0-1 sessionStorage 限制:
- writeCityDetailCacheBundle 只保留最近 3 个城市的详情
- 避免 3-10MB JSON 序列化阻塞主线程

P0-2 Context 拆分:
- 新增 CityDetailsContext 独立管理 cityDetailsByName 变更
- 新增 useCityDetails hook,只订阅详情的组件不再因 cities/proAccess 变化重渲染
- DashboardStoreContext 保持不变,向后兼容

P0-3 扫描终端 TTL:
- SCAN_TERMINAL_PAYLOAD_TTL_SEC 30s → 120s
- 匹配 ThreadPoolExecutor(4) x 60 城的实际重算耗时

P0-4 LGBM 循环依赖:
- LGBM 预测值不再作为 DEB 输入参与权重计算
- 保留为独立参考字段 lgbm.prediction 输出给前端展示
- 消除 DEB → LGBM 训练 → DEB 的循环

新增 docs/data-architecture-review.md 完整数据链路审查报告

Tested: npx tsc --noEmit, python -m ruff check .
2026-05-10 16:48:28 +08:00
2569718930@qq.com ce1da6a686 完成产品审查剩余修复:新手指引、反馈入口、付费墙预览
P1-4:新增 WelcomeOverlay 新手指引
- 首次访问时显示 3 步引导:①从地图选城市 ②查看城市简报 ③解锁 Pro 深入分析
- 圆点进度指示、跳过/下一步按钮、点背景可关闭
- 看过一次后 localStorage 标记不再显示

P1-5:付费墙增加功能预览
- HistoryModal 在付费墙上方展示功能说明文案
- 新增 i18n 键 history.previewTitle / history.previewDesc(中英双语)

P2-9:新增反馈入口
- 顶栏增加 Telegram 反馈按钮(MessageCircle 图标)
- 点击跳转 PolyWeather 社群

Tested: npx tsc --noEmit
2026-05-10 16:19:21 +08:00
2569718930@qq.com de0f037bf4 产品体验修复:P0 阻塞 + P1/P2 改善(产品审查 14 项中修复 10 项)
P0 阻塞:
- Pro 加载不再阻塞整个看板:只显示精简顶栏 + 加载状态,不再遮盖整个页面
- Scan 失败加重试按钮:所有用户(含免费)均可手动重试
- Detail Panel 同步超时后显示提示:"同步时间较长,当前展示的数据可能不完整"

P1 体验:
- 登录页增加"忘记密码"链接:调用 Supabase 密码重置流程
- 登录失败/邮箱未验证增加明确提示:"如刚注册,请先点击验证链接"
- 公告横幅增加 ✕ 关闭按钮:点击后永久隐藏

P2 改善:
- entitlement-required 页面重设计:品牌化、增加返回首页和登录按钮
- 订阅帮助页中英双语:所有 FAQ 和 UI 文案支持中英文切换
- 新增产品审查文档 docs/product-review-jun-2026.md

Tested: npx tsc --noEmit
2026-05-10 16:13:34 +08:00
2569718930@qq.com 9635387beb 移除日历视图:功能与决策卡重叠,维护成本高于价值
- 删除 CalendarView.tsx、calendar-action-utils.ts 及其测试文件
- 删除 ScanTerminalCalendar.module.css
- ScanTerminalDashboard:移除日历 tab 按钮、日历渲染分支、ContentView 类型中的 calendar
- ScanTerminalLightTheme:清理所有 .scan-calendar-* 规则(~40 行)
- scan-root-styles.ts:移除 ScanTerminalCalendar 导入

同时完善地理排序:
- scan_terminal_filters.py:market_region_from_tz_offset 细化为 7 个区域(东亚/东南亚/中亚/西亚/欧洲非洲/南美/北美)并增加 sort_order
- scan_terminal_city_row.py:传递 trading_region_sort
- dashboard-types.ts:增加 trading_region_sort 字段
- decision-utils.ts:sortRowsByUserTime 按 trading_region_sort 优先排序

Rejected: keep-calendar-view, calendar-actions-overlap-with-decision-cards
Tested: npx tsc --noEmit, python -m ruff check .
2026-05-10 15:48:18 +08:00
2569718930@qq.com 5ff9fade5f 重新设计日历视图:以用户本地时区为主视角
- CalendarView 组件重写:添加实时用户时钟头部(HH:MM:SS + 完整日期)
- 卡片重新设计:用户本地时间为主要展示,城市窗口时间为次要
- 新增 urgency badge(进行中/即将/稍后/已过)视觉标识
- 优化卡片布局:顶部城市+徽标 → 用户时间 → 倒计时 → 原因 → 底部 DEB+阶段
- CSS 全面重写:用户时钟头部、卡片分层、计时器颜色编码
- 浅色主题同步更新所有新 class 名称
2026-05-10 15:34:46 +08:00
2569718930@qq.com 0e529358c9 移除 scan-topbar-logo 品牌标记
- 从 ScanTerminalDashboard.tsx 移除 logo div 和 brand 容器
- 从 ScanTerminalShell.module.css 移除 .scan-topbar-brand / .scan-topbar-logo 样式
- 从 ScanTerminalLightTheme.module.css 移除对应的浅色主题覆盖
2026-05-10 15:13:32 +08:00
2569718930@qq.com 00e1845f2c 全面修复前端 UI 设计审查问题:消除工程债务、统一 token 体系、提升可维护性
- 消除 !important 滥用:134 → 49(仅保留 Leaflet/图表所必需项),浅色主题使用 html.light 选择器获得更高优先级
- 修复 font-weight:13 个文件中所有 760/850/860/880/950 等非标准值已映射为 Inter 支持的 300–800
- 移除未加载的 Geist 字体声明,替换为 Inter
- 添加全局 :focus-visible 轮廓环、跳过链接、Tab ARIA 属性(role/aria-selected)
- 统一断点体系:18 → 10(480/640/768/960/1024/1200/1280/1360/1440/1680)
- 创建 scan-root-styles.ts 桶文件,将 22 个 CSS Module 导入合并为 1 个
- Token 迁移:10 个文件中数百处硬编码颜色(#4DA3FF/#E6EDF3/#9FB2C7/#6B7A90)已替换为 CSS 变量
- 去重 @keyframes:spin 4→1、loading-spin 2→0、pulse-pending 已移至 globals.css
- 添加统一的 empty/error/retry 状态组件
- 添加全局 prefers-reduced-motion 支持
- 修复 accent-primary 与 accent-secondary 相同值的问题
- 修复 accent-green 类错误渲染为蓝色
- 添加 CSS 渐变品牌 Logo
- 移除死代码(1,697 行):public/static/style.css + public/legacy/index.html
- Dashboard.module.css 本地变量已桥接至全局 token
- 提升文字对比度:#6B7A90 → #7D8FA3

Fixed: !important-134-to-49, font-weight-13-files, Geist-removal, focus-visible, breakpoints-18-to-10, CSS-module-barrel, token-migration-10-files, keyframe-dedup, dead-code-removal, accent-color-fix, contrast-improvement
Scope: frontend CSS architecture, design tokens, accessibility, responsive breakpoints
Tested: npx tsc --noEmit
2026-05-10 14:21:10 +08:00
2569718930@qq.com f47de115c8 Reduce duplicate scan terminal decision copy and chrome
Removed the scan KPI bar, trimmed redundant decision-card content, and shortened the primary reason text so the city analysis cards read like concise signals instead of repeating the same state across sections.

Constraint: Keep existing city decision logic and data flow unchanged while simplifying the UI
Rejected: Rework the full card layout or mobile card flow | larger surface area than requested
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Keep hero, decision band, and market line responsibilities separate to avoid duplicate copy returning
Tested: frontend npm run build
Not-tested: Manual visual QA in browser across desktop/mobile breakpoints
2026-05-10 12:20:22 +08:00
2569718930@qq.com 30faac989c 秒开 AI 预测最高温:preview 事件提前下发确定性预测值
之前 predicted_max 只在 AI 流式 final 事件返回后才显示(10-25 秒),
但后端 fallback 早在 1ms 内就算好了 cluster median / DEB 中枢。
现在 preview 事件同步下发确定性 predicted_max + range_low/high,
前端也在 fallback payload 中自动从 multi_model + DEB 计算预测值,
用户点击城市后 ~100ms 即可看到 AI 预测最高温。
2026-05-07 21:04:26 +08:00
2569718930@qq.com 30a6ff7986 新增 v1.5.6 升级公告,3 天后自动消失
公告展示决策终端 hero 重设计、DEB 统一、亮色补全等变更摘要。
localStorage 记录首次访问时间,超过 3 天自动隐藏。
补全 scan-upgrade-announcement 暗色主题基础样式。

Tested: tsc 全过
2026-05-06 18:59:20 +08:00
2569718930@qq.com 52fa7b0bb3 移除城市快捷跳转栏 sticky 固定效果,更新 LGBM 模型至 1247 样本
scan-ai-city-jumpbar 不再吸附顶部,anchor scroll-margin 同步清理。
LGBM 模型用 prod DB 重训练:1247 样本 → 验证 MAE 2.63°C vs DEB 2.75°C。

Tested: tsc + ruff 全过
2026-05-06 18:50:10 +08:00
2569718930@qq.com a684586cb4 统一 DEB 数据源为单一计算路径
getModelView 优先使用根级 detail.deb.prediction 保证与 AI 证据面板一致,
_build_city_detail_payload 补上缺失的 deb 和 multi_model_daily 字段,
_analyze_summary 补上 LGBM 增强步骤使其与 _analyze 产出相同的 DEB 值。

Constraint: 三个入口 (panel/full/summary) 的 DEB 必须经过同一套 calculate_dynamic_weights + LGBM 重算流程
Tested: ruff + tsc 全过
2026-05-06 18:24:15 +08:00
2569718930@qq.com 2f73828d4d 重构城市决策卡 hero 布局:去除 sticky 固定效果,右侧改为三指标并列对比
将 scan-ai-city-hero 从"左重右轻"改为左右均衡布局,右侧从单一预计高温数字
替换为当前温度/预计最高温/峰值时间三列并排指标卡,中间列高亮为主指标。
移除冗余的 pills 行和隐藏的 mobile-priority div,新鲜度条改为水平单行。
同步更新亮色主题 CSS 新增 metrics 样式。修复 fallback 模块未使用变量。

Constraint: dark/light 双主题完整覆盖
Scope-risk: hero 高度缩减约 30%,需确认移动端 MobileDecisionCard 不受影响
2026-05-06 17:57:40 +08:00
2569718930@qq.com 227fe7906c 补全证据面板和决策波段在亮色模式下的文字颜色覆盖
- .scan-ai-city-section-title: #4da3ff → #1d4ed8(与背景对比度从 2.93 提升到 5.8)
- .scan-ai-decision-band span/strong/p: 显式覆盖暗色文字
- .scan-ai-city-body 滚动条: 适配浅色主题
2026-05-06 17:01:28 +08:00
2569718930@qq.com a3052767d7 补全 AI 预测双卡片组件的亮色模式 CSS
此前新增的预测卡片(scan-ai-prediction-card/confidence 等)
只有暗色模式样式,在亮色模式下白底上显示深色背景块,严重
影响可读性。现补全 30 条亮色覆盖规则。
2026-05-06 16:54:48 +08:00
2569718930@qq.com 59e099a56d 修复 AI 报文解读缓存未在首帧生效的问题
此前 useState 初始化为 idle,useEffect 异步读缓存后才切到 ready,
导致重新打开城市卡片时先闪烁"等待 AI 解读..."再跳转到缓存数据。
现在用 lazy initializer 在首帧同步读取缓存,命中则直接渲染 ready
状态,零闪烁。
2026-05-06 16:34:19 +08:00
2569718930@qq.com 1a40802dcb 移除 AI 机场报文解读面板的折叠收起按钮
将 <details>/<summary> 改为普通 <section>/<div>,面板始终展开。
移除 isCompactCard prop 及相关的 open/onToggle 状态管理。
2026-05-06 16:27:06 +08:00
2569718930@qq.com 13025f5c77 证据面板加载态立即显示 DEB + AI 预测中占位卡片
此前 AI 预测卡片需等流式 SSE 返回后才显示,loading 期间整个双卡片
区域消失。现在:DEB 卡片立即显示,AI 侧显示"预测中…"呼吸动画占位,
流式返回后自动替换为真实预测值。
2026-05-06 16:08:09 +08:00
2569718930@qq.com f9d0ea31bc 证据面板新增 AI 预测最高温 vs DEB 双锚对比卡片
在 AI 机场报文解读面板顶部加入双卡片布局:左侧展示 AI 预测最高温
(含置信区间和置信度),右侧展示 DEB 融合值,形成可对比的"双锚"
视图。同时更新加载态文案为"AI 正在基于最新报文预测今日最高温"。
2026-05-06 15:48:27 +08:00
2569718930@qq.com 4186a2662b 移除过时的 v1.5.5 升级公告
公告内容已过时,且功能说明已融入产品本身,无需常驻展示。
2026-05-06 15:31:36 +08:00
2569718930@qq.com cdfde1624c 移除今日机会榜,简化决策台为三视图(地图/决策卡/日历)
机会榜作为决策卡的聚合摘要层,与决策卡视图功能重叠,增加了
不必要的代码和认知负担。移除后将地图作为默认入口,用户从
地图选城市后直接进入决策卡验证天气证据。
2026-05-06 15:26:37 +08:00
2569718930@qq.com 118d4e44df This version of Antigravity is no longer supported. Please upgrade to receive the latest features. 2026-05-01 11:37:09 +08:00
2569718930@qq.com 6c203bee60 This version of Antigravity is no longer supported. Please upgrade to receive the latest features. 2026-05-01 11:27:16 +08:00
2569718930@qq.com 113c0131b5 This version of Antigravity is no longer supported. Please upgrade to receive the latest features. 2026-05-01 11:17:20 +08:00
2569718930@qq.com 9d0570a36b This version of Antigravity is no longer supported. Please upgrade to receive the latest features. 2026-05-01 11:11:17 +08:00
2569718930@qq.com 6603515433 This version of Antigravity is no longer supported. Please upgrade to receive the latest features. 2026-04-30 09:59:40 +08:00
2569718930@qq.com a984c22b62 This version of Antigravity is no longer supported. Please upgrade to receive the latest features. 2026-04-30 08:05:10 +08:00
2569718930@qq.com 94995c5006 This version of Antigravity is no longer supported. Please upgrade to receive the latest features. 2026-04-29 20:07:31 +08:00
2569718930@qq.com 1ccc275a23 Make mobile account surfaces readable
Mobile review found that account payment rows could collapse labels vertically and several secondary links had small touch targets on narrow phones. The patch keeps the existing visual system but allows account rows to stack on mobile, improves tap height, and tightens the Scan Terminal narrow-screen container.

Constraint: Must keep the current desktop layout and avoid adding dependencies

Rejected: Rebuild the account page layout wholesale | too broad for a targeted mobile audit

Confidence: high

Scope-risk: narrow

Directive: Keep long account/payment identifiers breakable on narrow screens

Tested: iPhone SE and iPhone 12 Playwright mobile audits show no horizontal overflow on checked pages

Tested: npx tsc --noEmit --pretty false --project frontend/tsconfig.json

Tested: npm run build

Tested: npm run test:business

Not-tested: Authenticated /ops data state because local Supabase/admin gating redirects to the public shell
2026-04-29 12:40:37 +08:00
2569718930@qq.com 569f3eef97 Make weather-market UI reliable before shipping
Proxy routes now share one upstream-error adapter so client-actionable statuses such as auth, entitlement, validation, and rate limits survive the BFF instead of becoming opaque 502s. The scan terminal mobile overrides also load last and remove desktop rail constraints so phones get a single readable column.

Constraint: Mobile users reported the dashboard was unreadable, and BFF proxy errors were masking expected client states.

Rejected: Let every route keep bespoke error JSON | continued inconsistent status codes and production detail leakage.

Confidence: high

Scope-risk: moderate

Directive: Keep ScanTerminalMobile.module.css imported after desktop scan-terminal CSS so mobile breakpoints win.

Tested: npx tsc --noEmit --pretty false --project frontend/tsconfig.json

Tested: npm run build

Tested: npm run test:business

Tested: Chrome mobile smoke test at 390px with no horizontal overflow

Not-tested: Real device Safari/Android manual QA
2026-04-29 11:22:49 +08:00
2569718930@qq.com 4630cee06f feat: implement FutureForecastForwardView component and associated modal styles 2026-04-28 21:16:54 +08:00
2569718930@qq.com 2b1d7c0b65 Improve dashboard maintainability before the next release
The dashboard had several oversized orchestration, component, and CSS files that made product-copy changes and mobile/performance work risky. This refactor preserves behavior while splitting scan terminal CSS, opportunity helpers, future forecast panels, history/detail charts, and probability/model sections into smaller ownership boundaries.

Constraint: No user-visible version bump because this batch is architecture and performance cleanup, not a release announcement.

Rejected: Rewrite dashboard state management in the same batch | too broad for a safe upload after CSS and component splitting.

Confidence: high

Scope-risk: moderate

Reversibility: clean

Directive: Keep new component/CSS boundaries instead of moving product copy back into the large dashboard files.

Tested: npm run build; npm run test:business; git diff --check

Not-tested: Browser visual smoke test after push
2026-04-28 20:19:17 +08:00
2569718930@qq.com b122e7cbae Stabilize the decision workspace data boundaries
The scan terminal had grown into overlapping CSS, request-state, AI-provider, and city-card data responsibilities. This refactor separates those boundaries without changing product behavior: CSS modules are split by surface, city AI prompt/provider/fallback logic is isolated, and scan terminal request state now has reusable RemoteData adapters plus business-state tests.

Constraint: Preserve existing global scan-terminal class names and API responses during the refactor

Constraint: No new dependencies; keep this as a file-boundary cleanup

Rejected: Introduce React Query now | higher migration risk than the requested lightweight query-client path

Rejected: Rewrite AI stream behavior | progressive/fallback states are product-sensitive and were only adapter-split

Confidence: high

Scope-risk: moderate

Reversibility: clean

Directive: Keep AI stream state changes covered by business snapshots before changing fallback/cache wording

Tested: npm run test:business; npx tsc --noEmit; npm run build; python pytest -q; ruff check; py_compile targeted city AI modules

Not-tested: Live DeepSeek provider network replay and browser visual QA
2026-04-28 14:45:34 +08:00
2569718930@qq.com 12d90c5051 Lock decision edge cases with business state tests
The dashboard risk is now mostly contradictory state combinations rather than styling. This extracts calendar action grouping into a pure utility and adds a lightweight TypeScript business-state runner so key decision states can be asserted without adding a test dependency.

Constraint: No new dependencies; use the existing TypeScript package for a local runner.

Rejected: Only rely on Next build/typecheck | it cannot catch product-language regressions such as fallback AI being labeled complete.

Confidence: high

Scope-risk: moderate

Reversibility: clean

Tested: npm run test:business

Tested: npm run build

Not-tested: Browser-rendered mobile fold interaction snapshots.
2026-04-28 13:13:57 +08:00
2569718930@qq.com fbd98dd59c Give mobile city cards their own action layout
Phone users need the city card to answer what matters first instead of inheriting the full desktop analysis hierarchy. This adds a MobileDecisionCard that leads with city, observed temperature, expected high, peak window, one decision reason, status tags, freshness, and a separate market-price row, while keeping AI, model evidence, and the chart behind collapsible sections.

Constraint: Preserve the existing desktop city-card layout and decision state semantics.

Rejected: Continue relying only on CSS hide/show | it keeps mobile coupled to the desktop information architecture.

Confidence: high

Scope-risk: moderate

Reversibility: clean

Tested: TypeScript diagnostics for AiPinnedCityCard and MobileDecisionCard

Tested: npm run build

Not-tested: Device screenshot QA across iOS/Android viewport sizes.
2026-04-28 13:00:40 +08:00
2569718930@qq.com a77d613c2b Move weather summaries out of the dashboard utility bulk
Weather labels, METAR translation, risk badges, and hero meta chips were still embedded in dashboard-utils even though panel, modal, and detail views use them as focused presentation helpers. This moves them into weather-summary-utils while keeping dashboard-utils re-export compatibility.

Constraint: Preserve existing weather/METAR/risk/hero meta wording.

Rejected: Move airport narrative in the same pass | it has broader AI narrative coupling and should be separated independently.

Confidence: high

Scope-risk: narrow

Reversibility: clean

Tested: TypeScript diagnostics for weather-summary-utils, dashboard-utils, PanelSections, DetailPanel, and FutureForecastModal

Tested: npm run build

Not-tested: Visual snapshot of every weather icon/label combination.
2026-04-28 12:17:42 +08:00
2569718930@qq.com 5dc39b1573 Move model views out of the dashboard utility bulk
Probability and multi-model view adapters were still embedded in dashboard-utils even though table, panel, modal, and city-card views use them as small pure selectors. This moves them into model-utils and keeps dashboard-utils re-export compatibility.

Constraint: Preserve model/probability return shapes and existing fallback behavior.

Rejected: Merge model-utils with chart-utils | model selectors and chart data preparation change at different rates.

Confidence: high

Scope-risk: narrow

Reversibility: clean

Tested: TypeScript diagnostics for model-utils, dashboard-utils, and PanelSections

Tested: npm run build

Not-tested: Bundle analyzer size comparison.
2026-04-28 12:07:43 +08:00
2569718930@qq.com ecbba9160d Let chart views avoid the dashboard utility bulk
The intraday chart data builder lived inside dashboard-utils with observation-source and TAF helpers, so chart consumers had to depend on the large dashboard utility surface. This moves chart data preparation, observation-source helpers, and TAF marker labels into focused modules while keeping dashboard-utils re-export compatibility.

Constraint: Preserve existing chart data shape, observation labels, TAF labels, and legacy dashboard-utils exports.

Rejected: Rewrite chart data generation while moving it | this pass is a boundary move only so visual behavior remains stable.

Confidence: high

Scope-risk: moderate

Reversibility: clean

Tested: TypeScript diagnostics for chart-utils, dashboard-utils, observation-source-utils, and taf-utils

Tested: npm run build

Not-tested: Browser visual regression across every chart city.
2026-04-28 11:58:58 +08:00
2569718930@qq.com c476ad2123 Move pace math out of the dashboard utility bulk
Pace-adjusted high calculations were embedded in dashboard-utils alongside chart, profile, and modal helpers. This moves the pure pace model and reusable HM time helpers into focused modules while keeping dashboard-utils re-export compatibility for older callers.

Constraint: Preserve existing pace wording, thresholds, and calculation output.

Rejected: Split all remaining dashboard-utils helpers at once | model/chart/modal helpers have wider call surfaces and should move in separate reversible passes.

Confidence: high

Scope-risk: narrow

Reversibility: clean

Tested: TypeScript diagnostics for pace-utils, time-utils, dashboard-utils, and FutureForecastModal

Tested: npm run build

Not-tested: Bundle analyzer size comparison.
2026-04-28 11:45:34 +08:00
2569718930@qq.com be41becb30 Let temperature formatting ship without dashboard bulk
Temperature formatting was embedded in the large dashboard utility module, so small scan-terminal views had to import the heavy utility surface for simple labels. This moves the pure temperature helpers into a lightweight module while keeping dashboard-utils re-exports for compatibility.

Constraint: Preserve existing temperature text output and all dashboard-utils import compatibility.

Rejected: Split chart, pace, and model helpers in the same pass | those helpers have wider coupling and should move one boundary at a time.

Confidence: high

Scope-risk: narrow

Reversibility: clean

Tested: TypeScript diagnostics for temperature-utils, dashboard-utils, and OpportunityTable

Tested: npm run build

Not-tested: Bundle analyzer size comparison.
2026-04-28 11:32:03 +08:00
2569718930@qq.com 8d05812a7e Keep dense dashboard lists stable during selection changes
Opportunity and calendar cards now isolate item rendering behind memoized components. This preserves the current action grouping and copy while preventing selection or parent dashboard updates from re-rendering every dense card body.

Constraint: Do not change ranking, grouping, or product wording in this performance pass.

Rejected: Introduce virtual list dependency | the current list size can benefit from memo boundaries first without new dependencies.

Confidence: high

Scope-risk: narrow

Reversibility: clean

Tested: TypeScript diagnostics for CalendarView and OpportunityOverview

Tested: npm run build

Not-tested: Browser profiler capture with a large production city set.
2026-04-28 11:25:14 +08:00
2569718930@qq.com 2e5bdfd1b6 Defer heavy city card rendering until users need it
City decision cards rendered Chart.js canvases and AI evidence bodies before the user could see or expand those sections. This keeps the card shell visible while delaying chart data/canvas work until the section nears the viewport and skipping the AI evidence body while its details panel is collapsed.

Constraint: Preserve existing decision-card layout and evidence copy.

Rejected: Add list virtualization in the same pass | card-level render costs should be reduced before changing list mechanics.

Confidence: high

Scope-risk: narrow

Reversibility: clean

Tested: npm run build

Not-tested: Runtime scroll benchmark on a large production city set.
2026-04-28 11:10:12 +08:00
2569718930@qq.com d2699ce17a Represent market scan loading with RemoteData
Market scan state was still tracked as separate nullable payload and status strings. This moves the hook internals to RemoteData<MarketScan> so loading and error paths can preserve previous data while keeping the existing marketScan and marketStatus return values for current card consumers.

Constraint: Preserve the existing useCityMarketScan public compatibility fields.

Rejected: Update all card UI to consume marketRemote immediately | keeping the compatibility bridge avoids a broad rendering diff while the request state model lands.

Confidence: high

Scope-risk: narrow

Reversibility: clean

Tested: npm run build

Not-tested: Forced live market-scan failure with stale previous quote.
2026-04-28 11:00:22 +08:00