Commit Graph
41 Commits
Author SHA1 Message Date
shangfangjian 1a37c75907 fix(a11y): ink-400 对比度达标,接入 Noto Serif SC webfont,补纸张噪点与入场编排
- ink-400 #9C9587(2.90:1)→ #756F61(paper-50 4.87:1 / paper-100 4.55:1),正文级小字全部达标
- serif 栈插入 Noto Serif SC(fontsource 子集加载),Windows 不再跌进 SimSun
- 首页加 feTurbulence 纸张噪点层(.grain);报头/赛程行/预测版 rise-in 错峰入场(60ms 步进)
- reduce 动效用户:隐藏态与动画同在 no-preference 块,不会白屏
- Switch 提到模块顶层(修 render 重建丢焦点);a→Link(SPA 内链);h3→h2/h4→h3 修标题层级
- 按钮/输入热区抬高(btn 40px / btn-sm 32px / field py-2);index.css 硬编码色值改 :root 令牌
2026-09-18 11:04:46 +08:00
shangfangjian cf0751d1ff feat: 管理界面报刊风统一改造 — 移除独立暗色主题,预测/回测/监控/配置页增强 2026-09-18 10:42:14 +08:00
shangfangjian 91e406f5ee feat: 管理界面优化 — 移动端自适应 + 数据源 + LLM 配置
移动端自适应:
- AdminLayout: 汉堡菜单 + 可折叠侧边栏 + 遮罩层 + ESC 关闭
- 所有页面响应式布局 (grid-cols-1 sm:grid-cols-2 lg:grid-cols-4)
- 触摸友好按钮 (min-h-[44px])
- 表格移动端卡片视图

新增页面:
- DataSources: 数据源状态 + API Key 脱敏 + 测试连接
- LLMConfig: LLM 配置 + 测试连接 + 使用统计 + 最近预测

增强功能:
- Config: 配置列表 + 修改指南 + 快捷导航
- types: 新增 DataSourceStatus, LLMUsageStats 等类型
- dal: 新增 testDataSource, fetchDataSourceStatuses, testLLMConnection 等
2026-09-17 02:43:44 +08:00
shangfangjian 6680da7d61 fix: 修复 Admin 后台多个 bug
- api.ts: 修复 URL 拼接 bug(缺少 API_BASE) 和 204 判断逻辑
- dal.ts: 修复 fetchDashboard 类型错乱,修正 API 端点
- types.ts: 对齐后端 Pydantic 模型
- 所有页面: Badge variant→status, CardHeader children→action
- 移除不存在的后端端点调用
2026-09-17 02:11:50 +08:00
shangfangjian d3284c48c3 feat: 后台管理 Admin 仪表盘
新增完整的后台管理系统 (/admin):
- Dashboard: 系统概览、最近采集状态、预测统计
- Collection: 数据采集触发(bzzoiro/understat/injuries)
- Predictions: 预测历史查看、触发新预测
- Backtest: 回测配置与结果查看
- Monitoring: 系统健康、错误日志、死色队列
- Config: API Key 与数据源配置

技术栈: React Router + Tailwind 暗色主题 + TypeScript
文件: 11 个新文件, +21KB JS / +5KB CSS
2026-09-17 02:00:14 +08:00
shangfangjian 1219b4fd18 fix: alembic version_num 长度修复 + 前端部署配置
- env.py: 自动创建 alembic_version 表时使用 VARCHAR(255) 避免截断
- docker-compose: 添加 frontend nginx 服务 + alembic 挂载
- nginx.conf: SPA 路由 + API 代理
2026-09-17 01:26:58 +08:00
shangfangjian 312778d995 feat: 数据管线架构优化 + 前端部署配置
- Bronze 层 RawEvent 表(原始事件存档)
- IngestFailure 死信表(失败持久化+重试)
- DataQualityCheck 数据质量监控
- DataLineage 血缘追踪
- MatchStats xG 追踪字段
- Nginx 前端服务配置
2026-09-17 01:15:51 +08:00
shangfangjian e89ab1a0c9 Merge pull request 'fix: 数据库与数据管线审查问题修复 (6 P1 + 5 P2)' (#3) from fix/db-pipeline-review-issues into main
Reviewed-on: #3
2026-09-16 03:14:37 +08:00
shangfangjian ff0045ad93 fix: 数据库与数据管线 6 个 P1 + 5 个 P2 审查问题修复
P1-1 [context_builder] build_context 共享 session,切片函数传 db 参数,
        回测 20 场并发连接需求从 100+ 降至每场 1 个
P1-2 [bzzoiro] 预加载改为按 raw_events 日期范围 ±30 天按需加载
P1-3 [understat] 批量查询球队 + 比赛,从 1140 次往返降到 3 次
P1-4 [injuries] 批量幂等检查 + 分批 flush,IntegrityError 逐条回退
P1-5 [predict] 删除 threading.Lock,dict 操作原子无需同步锁
P1-6 [models] 添加 (match_id, provider, model) 唯一约束 + 迁移

P2-1 [unit_of_work] get_uow 返回类型改为 AsyncIterator[AsyncSession]
P2-2 [normalize] _parse_date 失败时记录 warning 避免静默丢数据
P2-3 [repositories] find_by_teams_and_date 改用 match_date_date 等值匹配
P2-4 [migration] 幽灵列 cutoff_at 已在 0006 迁移删除(已有)
P2-5 [migration] injuries 约束命名对齐 ORM,UniqueConstraint → 唯一索引
2026-09-16 03:09:39 +08:00
shangfangjian 983b620659 refactor: fix P0/P1/P2 security and performance issues
P0 fixes:
- CORS: replace wildcard methods/headers with configurable lists
- deps.py: remove unsafe global _warned_unset variable

P1 fixes:
- http_client: read default timeout from Settings
- bzzoiro: replace sync urllib with async httpx
- bzzoiro: normalize validation failures use warning level only
- db pool: read pool config from Settings (default 5+10)
- backtest: add asyncio.Semaphore(8) for concurrent execution
- predict/context_builder: add backtest parameter for cutoff buffer

P2 improvements:
- injuries: enforce int conversion for player_id/fixture_id
- injuries: use system temp dir for cache
- utils.py: extract shared actual_1x2/is_correct_1x2
- validation: downgrade 1x2 mismatch log to debug
- docker-compose: use env vars for all credentials
- .env.example: add POSTGRES_USER/PASSWORD/PORT, API_PORT
2026-09-16 02:38:25 +08:00
shangfangjian fa69795d69 fix: 应用代码审查三项发现
- frontend: .tab 补 position:relative,修复激活 tab 下划线定位缺失定位上下文
- core/retry.py: 删除全项目零调用的重试模块(避免"看似生效实际未接入"的误判)
- llm/validation.py: KNOWN_AGENT_NAMES 改为从 orchestrator.SPECIALIST_SPECS 派生,单一权威源
2026-09-15 20:12:47 +08:00
shangfangjian c5f92c9a54 Merge pull request 'refactor(ui): 前端重做为报刊赛程版视觉' (#2) from frontend-beautify into main
Reviewed-on: #2
2026-09-15 20:00:05 +08:00
shangfangjian 7df46544b8 Merge branch 'main' into frontend-beautify 2026-09-15 19:59:13 +08:00
WorkBuddy d847f4f3f4 refactor(ui): 去 AI 味,重做为报刊赛程版视觉
- 色板收敛为纸白/暖墨/印报红三色,移除默认 Tailwind 蓝
- 队名彩色哈希块、shimmer/ping/fade-up 动效、圆角卡片阵全部移除
- 报头改为双线+居中宋体刊名+报眉日期行
- 赛程列表表格化:细线分行,联赛改为文字版面切换
- 预测版:方正墨线框,大号宋体比分,胜平负改文字行,专家意见改汉字编号折叠行,终裁改红竖线引文
- 修复:桌面状态列 sm:contents 错位;移动端对阵未同行
2026-09-15 19:56:23 +08:00
shangfangjian 29e718962f Merge pull request 'feat(ui): 清爽专业风设计系统重构,并修复 Tailwind 从未生效的配置缺陷' (#1) from frontend-beautify into main
Reviewed-on: #1
2026-09-15 19:01:22 +08:00
WorkBuddy e3cacc35e4 chore: 忽略本地审查/预览脚手架
.tools/ 与 .preview/ 为本机校验脚本与截图产物,不参与构建,不入库。
2026-09-15 17:45:21 +08:00
WorkBuddy 77d01450b1 feat(ui): 清爽专业风设计系统与界面重构
设计令牌(tailwind.config.js):
- brand 11 档蓝色阶、ink 11 档冷灰色阶、win/draw/loss 语义色
- 中文字体栈、tabular-nums 数字等宽、2xs 字号
- borderRadius card/pill、boxShadow card/raise/focus、fade-up/shimmer 动画

组件层(index.css):
- @layer base: 全局背景/字色/抗锯齿、统一焦点环、自定义滚动条,
  尊重 prefers-reduced-motion
- @layer components: .card .btn .field .pill .skeleton .segment

界面:
- App.tsx: SVG 队徽替代 emoji、sticky 毛玻璃头部、服务状态指示、页脚免责声明
- Matches.tsx: 比赛列表卡片化;新增 TeamMark(队名哈希色相队标)、
  EdgeBar(home_edge 双向可视化)、OutcomeCard、AgentCard(状态徽章+证据
  列表+无数据说明)、骨架屏;SVG Spinner 替代 emoji 转圈

可用性修复:
- 预测面板拆为独立的胜平负/置信度/模式/耗时卡片,胜平负与比分各有
  独立可视化条
- 移动端横向溢出:比赛行改为 flex-col -> sm:flex-row,元信息与操作按钮重排
- 无数据专家卡片补充说明文案,不再空白

保留原有契约:loadSeq/predictSeq 竞态防护、游标分页、全部类型定义。

验证:tsc --noEmit(strict)0 错误;vite build 成功;
360/390/414/768/1280px 五档实测 scrollWidth === viewport,零横向溢出。
2026-09-15 17:45:16 +08:00
WorkBuddy acea7e699d fix(frontend): 修复 postcss 配置误写导致 Tailwind 从未生效
postcss.config.js 中写入的是 Tailwind 的配置对象(content/theme/plugins),
缺少 PostCSS 插件注册所需的 plugins 字段,导致 PostCSS 从未加载 tailwindcss。
所有 className 上的 Tailwind 工具类一直是无效字符串,页面仅使用浏览器默认样式。

修复为标准写法 plugins: { tailwindcss: {}, autoprefixer: {} }。

验证:构建产物 CSS 由 1.81 kB 增至 24.66 kB,且不再残留未编译的
@tailwind / @apply / @layer 指令。
2026-09-15 17:45:10 +08:00
WorkBuddy f965650c10 test+docs: P0 回归测试与文档同步
回归测试(P0 三项,不依赖 DB 的静态断言):
- tests/test_regressions.py:
  · context_builder 三个查询函数 + backtest 必须 eager-load 关系
  · Match.{stats,home_team,away_team,league} 必须 lazy="selectin"
  · bzzoiro normalized_matches 必须携带并解包 (nm, raw) 配对
  这些是「集成方式」缺陷,原先的单元测试(全 mock slice_fn/provider)
  照不出来,故此专项静态锁定。

文档同步(修正与实际不符的表述):
- docs/01-architecture.md: app.py 标注改为「lifespan 仅验证连接,不建表」;
  补 deps.py / repositories.py / unit_of_work.py / validation.py /
  backtest.py / sources.py / http_client.py / retry.py;迁移范围改 0001~0006
- docs/07-development.md: 目录树修正 leagues.py→matches.py,补齐
  backtest.py / deps.py 及 0003~0006 迁移文件

附带: src/core/retry.py 加 NOTE 说明其当前无调用点(P3),
避免「看似有重试实则未生效」的误判。
2026-09-15 16:55:54 +08:00
WorkBuddy c89bfe2af7 fix(P2): no_data 结构化、权重校验、鉴权与前端竞态
P2-1 no_data 门控依赖文案子串(脆弱):
- context_builder 新增 SliceResult(text/has_data/n_records),
  5 个切片函数改为显式声明 has_data
- base._slice_has_data() 优先取结构化结果,str 返回仍走文案回退
  (兼容既有测试 mock 与自定义切片)
- build_context 的 has_stats/has_injuries 直接取切片声明

P2-2 agent_weights 无校验即落库:
- validation 新增 AgentWeightsSchema / validate_agent_weights:
  未知专家名丢弃、越界值钳制、总和非 1 时归一化
- orchestrator 落库前对 agent_weights 做校验

P2-3 1x2 与比分不一致被静默修正:
- 仍以比分修正,但补 logger.warning 暴露 LLM 自相矛盾

P2-5/P2-6 prompt 缓存不可刷新 + 缓存键不含模板内容:
- 新增 clear_prompt_cache() 供改模板后显式失效
- 缓存键纳入模板内容 hash,模板一改缓存自动失效

P2-7 ingest/backtest/settle 接口无鉴权:
- 新增 require_admin_key 依赖(X-API-Key),
  ADMIN_API_KEY 未设置时放行并告警(不破坏本地开发)
- 挂到 3 个 ingest 接口 + backtest + eval/settle

P2-8 前端请求竞态 + 未使用游标分页:
- Matches.tsx 用递增 seq 丢弃过期响应,避免旧筛选结果覆盖新筛选
- 接入后端已有的 cursor 分页 + 「加载更多」按钮

附带: .env.example 补齐 LLM_TIMEOUT / 分档模型 / ADMIN_API_KEY;
tests 新增 10 个用例覆盖 P2-1/2/3。
2026-09-15 16:54:05 +08:00
WorkBuddy 71bf723a10 fix(P1): 消除迁移漂移、回测缓存污染与历史数据越界风险
P1-1 schema/ORM 漂移:
- 新增 0006 迁移: 回填后 drop 幽灵列 predictions.cutoff_at,
  并幂等重建 ix_match_stats_available_at / ix_predictions_cutoff_at
- models.py 为 MatchStats / Prediction 声明上述两个索引,
  使 autogenerate 不再误建议删除

P1-2 迁移对历史越界数据不安全:
- 0004 在建 CHECK 约束前先 op.execute 清洗越界行
  (负数进球/置信度越界/非法 1x2/mode),避免 ALTER 中途失败
  导致迁移卡在半完成状态

P1-3 回测缓存污染:
- predict_match / _predict_single 新增 use_cache 参数,
  use_cache=False 时既不读也不写进程内缓存
- run_backtest 显式传 use_cache=False,避免 settle 到旧记录

P1-5 understat 关系属性访问:
- MatchRepository.find_by_teams_and_date 加 selectinload(Match.stats)

P1-6 日期键构造不统一:
- bzzoiro 抽取 _to_date()/_match_key() 统一去重键构造,
  消除 str(date) 与 isoformat() 的隐式格式依赖
2026-09-15 16:48:03 +08:00
WorkBuddy 235fb0de97 fix(P0): 修复三处静默失效的阻断缺陷
P0-1 backtest 会话生命周期:
- _get_historical_matches 加 selectinload(league/home_team/away_team),
  并在 session 内物化为 BacktestCandidate 纯数据快照,避免 session
  关闭后访问惰性关系抛 MissingGreenlet
- except 收窄并改用 logger.exception 保留堆栈
- 移除未使用的 and_ / League 导入

P0-2 切片函数关系属性 MissingGreenlet:
- models.py 为 Match.league/home_team/away_team/stats 声明 lazy=selectin
- context_builder 的 _get_form/_get_h2h/_get_home_away 显式 selectinload
  (修复 form_slice/h2h_slice 恒定失败,被 fail-open 掩盖的问题)
- repositories.find_by_teams_and_date 加 selectinload(Match.stats)

P0-3 bzzoiro raw 变量泄漏导致血缘错乱:
- normalized_matches 改为携带 (nm, raw) 元组,内层循环解包
- source_event_id / source_record_id 现在取到正确 event id
- 已有比赛补建 stats 时补齐 source/source_event_id/retrieved_at/available_at
- 抽取 _match_key()/_to_date() 统一日期键构造 (P1-6)
2026-09-15 16:45:09 +08:00
shangfangjian 60e4b89822 docs: 统一文档与代码一致性
- 修复所有 confidence → subjective_confidence 残留(03-api, 04-agents, 05-data, 07-development)
- 修复 5 张表 → 6 张表残留(06-deployment)
- 同步 API schema 示例与实际模型一致
- 更新 predictions 表结构文档(新增 status/cutoff/input_hash 字段)

code: 修复 API 异常处理(eval/predict)和 context_builder stats 时间过滤
2026-09-15 02:27:48 +08:00
shangfangjian 0980c2242a feat: P0-02/P0-03/P0-05 数据库时间语义与约束
P0-02: MatchStats 增加 source/source_record_id/retrieved_at/available_at
        context_builder 过滤统计数据时检查 available_at <= cutoff
P0-03: Prediction 增加 match_kickoff_at/prediction_created_at/prediction_cutoff_at
        明确区分比赛时间/预测创建时间/数据截止时间
P0-05: Prediction 增加 status 字段(success/failed/degraded)
        数据库 CHECK 约束

Alembic: 0005_prediction_status_and_stats_provenance

P1-02: injuries as_of 不再截断为 date,保持 datetime 精度
2026-09-15 02:04:25 +08:00
shangfangjian c657e04679 docs: 同步文档与实现一致性
- 5 张表 → 6 张表(添加 injuries)
- 同步所有 docs 和 models.py docstring
2026-09-15 01:44:49 +08:00
shangfangjian 98e3d07cf5 fix: 补充 Alembic 迁移 + bzzoiro 批量优化 + validation 兼容层
- 新增 0004_snapshot_and_constraints.py: 重命名 confidence → subjective_confidence,
  新增 cutoff_at/input_hash, 添加 CHECK 约束
- bzzoiro.py: 预加载完整 Match 对象到内存,更新路径不再重复查询
- validation.py: 旧字段 confidence 兼容并打 deprecation 日志
2026-09-15 01:42:52 +08:00
shangfangjian 2c205c68b1 fix: 修复剩余审查问题
- ingest.py: 异常不再暴露客户端,改为通用错误消息+日志记录
- bzzoiro.py: 修复 normalize 重复调用,改为一次遍历缓存结果
- understat.py: 使用 Repository 替代原始 SQL
2026-09-15 01:26:15 +08:00
shangfangjian 53e602b4f6 fix: 代码审查问题修复
- unit_of_work.py: 简化为纯 session 上下文管理器,消除 double-close 风险
- validation.py: 移除未使用的 import,简化 _score_to_1x2 逻辑
- repositories.py: 将 func 导入移到模块顶层
- 更新所有 get_uow() 调用点使用新接口(yield session 而非 uow 对象)
2026-09-15 01:18:35 +08:00
shangfangjian 74586aa5b7 docs: 更新 README 反映当前架构
- 更新架构图(添加分层架构、backtest 端点)
- 更新项目结构(添加 unit_of_work.py、repositories.py、backtest.py)
- 更新核心模块表
- 添加数据正确性保障章节
- 修正表数量(6 张表)
- confidence → subjective_confidence
2026-09-15 00:48:43 +08:00
shangfangjian 483cb956ba refactor: Sprint 3 - 引入 UnitOfWork + Repository 架构
新增:
- src/db/unit_of_work.py: UnitOfWork 事务封装
- src/db/repositories.py: Match/Team/League/Prediction Repository

重构:
- 删除 src/data/match_lookup.py(由 Repository 替代)
- 数据源(bzzoiro/understat/injuries)不再自行 commit
- API 路由(ingest)改用 UnitOfWork
- LLM 服务(predict/orchestrator/eval/backtest)改用 UnitOfWork

事务边界统一由调用方控制,数据层不再自行决定 commit。
2026-09-15 00:42:05 +08:00
shangfangjian cb36dc3ef9 feat: Sprint 2 - 概率语义 + 轻量快照 + 数据库约束
P0-05: confidence → subjective_confidence 改名(15 文件)
       LLM 主观置信度与概率分离
P0-02: predictions 增加 cutoff_at + input_hash(轻量快照)
       MatchContext 暴露 match_dt
       单/多 Agent 路径均记录快照元数据
P2-05: 数据库 CHECK 约束
       - pred_home_goals >= 0
       - pred_away_goals >= 0
       - subjective_confidence 0~1
       - pred_1x2 IN (1,X,2)
       - mode IN (single,multi)
P2-06: limit 分页约束(ge=1, le=200)
P2-01: 新增 /health/ready 就绪检查
2026-09-15 00:14:24 +08:00
shangfangjian f3160e3062 feat: Sprint 1 - 数据正确性整改
P2-01: 移除 lifespan create_all,改为仅验证连接
       新增 /health/ready 就绪检查
P0-04: LLM 输出严格 Pydantic 校验
       - Agent 输出越界/非法 → parse_error
       - 预测输出自动修正 1X2 与比分一致性
P0-01: injuries cutoff 修复
       - get_injuries_for_match 增加 as_of 参数
       - injuries_slice 使用 as_of 过滤 retrieved_at
       - 防止回测时未来采集数据泄漏
P1-12: 批量入库优化
       - 预加载 teams 到内存 dict
       - 预加载 existing matches 到内存 set
       - 消灭 N+1 查询
2026-09-14 23:36:35 +08:00
shangfangjian 9b44905192 chore: gitignore AI 助手上下文文件 2026-09-14 22:09:45 +08:00
shangfangjian c2b8a37bdd Revert "docs: 建立多 Agent 协同架构"
This reverts commit f50784f9dc.
2026-09-14 22:09:28 +08:00
shangfangjian f50784f9dc docs: 建立多 Agent 协同架构
4 个专业 Agent 协同:
- DBA: 数据库 schema、迁移、模型
- FE: 前端 React 界面
- BE: 后端 API、LLM 预测、数据采集
- Ops: 部署、Docker、配置

详见 docs/AGENTS.md 和各 Agent 上下文文件
2026-09-14 21:59:45 +08:00
shangfangjian 3071ffd533 feat: 前端 Error Boundary + 体验改进
- 新增 ErrorBoundary 组件: 捕获组件崩溃,显示友好错误页+重试按钮
- App: 用 ErrorBoundary 包裹,标题改为「先知 Profeto」
- Matches 页面:
  - 预测模式切换 (单次/多 Agent)
  - 加载中动画指示
  - 预测中状态提示
  - 错误提示可关闭
2026-09-09 21:58:57 +08:00
shangfangjian 494751bbb0 feat: 数据采集健壮性改进
- 新增 src/core/retry.py: 指数退避 + 抖动的重试装饰器
- bzzoiro: 改进重试逻辑
  - 429/5xx/网络错误均触发指数退避重试
  - 4xx 直接抛(不重试)
- understat: 新增重试(原无重试)
- injuries: 新增重试 + 文件缓存 7 天过期
- sources.py: 延迟导入修复循环导入
2026-09-09 21:47:56 +08:00
shangfangjian 1166a157ec feat: 添加回测框架
- 新增 src/llm/backtest.py: 回测核心逻辑
  - 查询历史已完赛比赛
  - 逐场预测(自动防未来信息泄漏)
  - 实际比分回填 + 统计
  - 1X2 准确率 / 比分 RMSE / 置信度校准
- 新增 POST /api/v1/backtest 路由
- 支持按联赛/日期范围/模式/模型筛选
2026-09-09 21:39:56 +08:00
shangfangjian 9c24b5f744 docs: 移除 MatchPro 对比,加入项目中文名「先知」 2026-09-09 02:23:02 +08:00
shangfangjian d9b1c3aeb5 docs: 完善 README 文档 2026-09-09 02:17:47 +08:00
shangfangjian 0a27b18c27 feat: 足球 LLM 预测服务初始提交
Profeto — 给 LLM 提供数据,让 LLM 预测足球比分。

核心模块:
- FastAPI 后端 + PostgreSQL (SQLAlchemy async)
- 多 Agent LLM 预测 (5 专家 + 终裁)
- 数据采集 (bzzoiro / understat / injuries)
- React 前端 (Vite + Tailwind)

包含:
- 数据源抽象 (DataSource 协议 + 注册表)
- Alembic 数据库迁移
- Prompt 模板 (单/多 Agent)
- 核心路径单元测试
2026-09-09 02:10:47 +08:00