Skip to content

Feature/dev - #1272

Closed
rex0104 wants to merge 93 commits into
ZhuLinsen:mainfrom
rex0104:feature/dev
Closed

Feature/dev#1272
rex0104 wants to merge 93 commits into
ZhuLinsen:mainfrom
rex0104:feature/dev

Conversation

@rex0104

@rex0104 rex0104 commented May 13, 2026

Copy link
Copy Markdown

PR Type

  • fix
  • feat
  • refactor
  • docs
  • chore
  • test

Background And Problem

请描述当前问题、影响范围与触发场景。
(EN) Describe the problem, its impact, and what triggers it.

Scope Of Change

请列出本 PR 修改的模块和文件范围。
(EN) List the modules and files changed in this PR.

Issue Link

必须填写以下之一 / Fill in one of:

  • Fixes #<issue_number>
  • Refs #<issue_number>
  • 无 Issue 时说明原因与验收标准 / If no issue, explain the motivation and acceptance criteria

Verification Commands And Results

请填写你实际执行过的命令和关键结果(不要只写"已测试")。
(EN) Paste the commands you actually ran and their key output (don't just write "tested"):

# example
./scripts/ci_gate.sh
python -m pytest -m "not network"

关键输出/结论 / Key output & conclusion:

Compatibility And Risk

请说明兼容性影响、潜在风险(如无请写 None)。
(EN) Describe compatibility impact and potential risks (write None if not applicable).

  • 若本 PR 修改第三方模型 / API 的兼容语义、请求参数、路由前缀或 provider fallback,请提供官方来源链接或公告,并说明这是长期约束、当前运行时约束还是临时兼容处理。
    (EN) If this PR changes third-party model/API compatibility, request parameters, routing prefixes, or provider fallback behavior, include an official source link or announcement and clarify whether the rule is permanent, runtime-specific, or a temporary compatibility workaround.)
  • 若本 PR 依赖特定运行时 / 锁定依赖窗口(例如 LiteLLM 版本范围、OpenAI-compatible 路由、YAML alias 行为),请写明当前验证过的兼容范围与覆盖路径。
    (EN) If this PR depends on a specific runtime or pinned dependency window (for example a LiteLLM version range, OpenAI-compatible routing, or YAML alias behavior), state the compatibility window you verified and which code paths were covered.)
  • 若本 PR 触及运行时配置保存、清理、迁移或回填逻辑,请明确说明旧配置是否会被自动改写、清空、迁移或保持不变,以及用户如何恢复原行为。
    (EN) If this PR touches runtime config save/cleanup/migration/backfill logic, explicitly describe whether existing config is rewritten, cleared, migrated, or left intact, and how users can restore the previous behavior.)

Rollback Plan

请至少写一句可执行的回滚方案(必填)。
(EN) Provide at least one actionable rollback step (required).

  • 如果是兼容性修复,默认应写出最小回滚方式(例如 revert this PR),并说明是否需要额外回滚配置或数据迁移。
    (EN) For compatibility fixes, include the minimal rollback path (for example revert this PR) and whether any additional config or data rollback is required.)

EXTRACT_PROMPT Change (if applicable)

若本 PR 修改了 src/services/image_stock_extractor.py 中的 EXTRACT_PROMPT,请在此处粘贴完整变更后的 prompt。
If this PR changes EXTRACT_PROMPT in src/services/image_stock_extractor.py, paste the full updated prompt here:

展开 / Expand: Full EXTRACT_PROMPT
(paste full prompt here)

Checklist

  • 本 PR 有明确动机和业务价值 / This PR has a clear motivation and value
  • 已提供可复现的验证命令与结果 / Reproducible verification commands and results are included
  • 已评估兼容性与风险 / Compatibility and risk have been assessed
  • 已提供回滚方案 / A rollback plan is provided
  • 若涉及用户可见变更,已同步更新相关文档与 docs/CHANGELOG.mdREADME.md 仅在首页级信息变化时更新,细节优先写入 docs/*.md / If user-visible changes are included, relevant docs and docs/CHANGELOG.md are updated; README.md is updated only for homepage-level changes, with details kept in docs/*.md

rex0104 added 30 commits April 11, 2026 19:35
…l unreachable eastmoney, improve search provider selection

- Add litellm/LiteLLM to DEFAULT_QUIET_LOGGERS (reduced log from 748 to 218 lines)
- Pass pre-fetched realtime_quote into get_fundamental_context to avoid redundant network call
- DNS probe eastmoney hosts at EfinanceFetcher/AkshareFetcher init; skip chip/board APIs when unreachable
- Add prefer_provider for announcements (Anspire) and earnings (Tavily) dimensions to replace ineffective SerpAPI/SearXNG for Chinese content
- Add docs/deploy-webui.md: Web service deployment and startup manual
Add src/migration.py with ensure_schema_current() that tracks schema
versions in _schema_version table and applies v1 migration (user_id
columns on 5 tables). Hook into DatabaseManager.__init__ after create_all.
- Replace is_auth_enabled()/verify_session() with has_users()/verify_session_user()
- Add EXEMPT_PREFIXES for /api/v1/share/* public share links
- Add /api/v1/auth/register to exempt paths
- Extract user_id from session and store in request.state.user_id
- Add test_auth_middleware.py with 8 test cases covering all branches
- Update test_auth_api.py middleware tests to patch has_users/verify_session_user
rex0104 and others added 20 commits April 21, 2026 18:16
… quickstart

- main.py: catch ModuleNotFoundError on third-party imports and print a
  bilingual "pip install -r requirements.txt" message with exit code 1,
  instead of surfacing a raw Python traceback to first-time contributors.
- NotFoundPage: display the attempted path (pathname + search) so users
  can tell a typo from a dead link.
- README (zh / en / cht): add a "Minimum viable config" callout above the
  ~225-row secrets table, showing that STOCK_LIST + one AI key + one push
  channel is enough to get running. Everything else is optional.
- CHANGELOG: three [Unreleased] entries in the flat format.

Verification:
- python -m py_compile main.py: OK
- apps/dsa-web: npm run build OK (4.9s, 3211 modules). NotFoundPage lints
  clean. Two pre-existing lint errors in KLineChart.tsx and SidebarNav.tsx
  are unrelated to this change.
…ruth)

- Call normalize_stock_identity(stock_code) in POST /api/v1/watchlist;
  canonical (code, name) from STOCK_NAME_MAP/akshare replaces any user-submitted name.
- Return HTTP 400 with {"error": "stock.identity_not_found"} for unresolvable codes,
  using raise HTTPException with a dict detail — compatible with the existing
  global http_exception_handler that spreads dict details to the top level.
- Add http_client fixture + 2 HTTP-level tests to tests/test_watchlist.py.
Wire normalize_stock_identity into POST /analyze so every code is
resolved to a canonical (code, name) pair before task submission.
Unknown codes that pass format validation but cannot be resolved
(neither in STOCK_NAME_MAP nor akshare) now return 400 with
error=stock.identity_not_found.

Behavior change: stock_name passed to task queue is now the canonical
name from STOCK_NAME_MAP rather than request.stock_name. Existing tests
that asserted stock_name=None for resolvable codes (600519->贵州茅台,
HK00700->腾讯控股) are updated to assert the canonical name.

Tests that use codes outside STOCK_NAME_MAP (AAPL.US, 688783) now mock
normalize_stock_identity to avoid network dependency and keep the focus
on the routing/queue-submission semantics.

MAX_BATCH_SIZE check moved to precede normalization so DoS protection
triggers before any per-code identity lookups.
…ASE_PATH

- vite.config.ts: base reads from VITE_BASE_PATH env var, defaults to '/'
- App.tsx: Router basename uses import.meta.env.BASE_URL (vite-injected)
- Default build behavior unchanged (root path); sub-path deploys use:
    VITE_BASE_PATH=/your/path/ npm run build
The hardcoded '/stocks.index.json' broke autocomplete when the app is
deployed under a sub-path (e.g. /agents/daily-stock/) — the request hit
the host root and got back unrelated HTML, which JSON.parse silently
failed on, leaving the search index empty.

Prepend import.meta.env.BASE_URL so the URL resolves to:
  - '/stocks.index.json' for root deploys (default, unchanged)
  - '/agents/daily-stock/stocks.index.json' under sub-path
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@rex0104
rex0104 requested a review from ZhuLinsen as a code owner May 13, 2026 08:05
@github-actions github-actions Bot added configuration documentation Improvements or additions to documentation size/XL testing labels May 13, 2026
@rex0104 rex0104 closed this May 13, 2026
@github-actions

Copy link
Copy Markdown

🤖 自动审查报告

项目 结果
📊 变更文件 30 个
➕ 新增行数 1311 行
➖ 删除行数 439 行
🔍 静态检查 ✅ 通过
🧠 AI 审查 ✅ 已完成

📁 修改的文件

  • 📝 .env.example (+9/-4)
  • 📝 .gitignore (+3/-0)
  • 📝 AGENTS.md (+9/-0)
  • 📝 README.md (+12/-0)
  • 📝 api/deps.py (+18/-1)
  • 📝 api/middlewares/auth.py (+39/-25)
  • 📝 api/middlewares/error_handler.py (+13/-0)
  • 📝 api/v1/endpoints/agent.py (+11/-6)
  • 📝 api/v1/endpoints/analysis.py (+50/-18)
  • 📝 api/v1/endpoints/auth.py (+372/-317)
  • 📝 api/v1/endpoints/backtest.py (+5/-1)
  • 📝 api/v1/endpoints/history.py (+24/-13)
  • 🆕 api/v1/endpoints/onboarding.py (+72/-0)
  • 📝 api/v1/endpoints/portfolio.py (+7/-4)
  • 🆕 api/v1/endpoints/schedule.py (+42/-0)
  • 🆕 api/v1/endpoints/screener.py (+66/-0)
  • 🆕 api/v1/endpoints/share.py (+54/-0)
  • 📝 api/v1/endpoints/system_config.py (+7/-7)
  • 🆕 api/v1/endpoints/watchlist.py (+129/-0)
  • 📝 api/v1/router.py (+31/-1)

... 还有 10 个文件


🧠 AI 代码审查意见

结论: Not Ready

必要性: 基于 PR 描述无法确认。PR 描述中的 "Background And Problem" 为空。然而,从代码改动内容看,本次 PR 引入了多用户认证、用户数据隔离、用户配置管理等一系列核心系统功能,这是非常重要的特性。

关联性: 不通过。PR 描述中的 "Issue Link" 为空,且未说明无 Issue 的原因和验收标准。这是必填项。

类型: 建议为 feat (Feature)。当前 PR 描述中未勾选任何类型。

描述完整性: 不完整。缺失项包括:

  • Background And Problem
  • Scope Of Change
  • Issue Link
  • Verification Commands And Results
  • Compatibility And Risk
  • Rollback Plan
  • Checklist 未勾选。

关于验证充分性:

  • CI 检查状态显示 Python 语法检查 (py_compile) 和 Flake8 严重错误检查均 ✅ 通过
  • 但 PR 描述中的 "Verification Commands And Results" 为空,未提供功能测试命令和关键结果,也未说明 ./scripts/ci_gate.sh 的执行情况。考虑到这是一个核心功能变更,功能测试结果是评估其正确性的关键依据。

风险级别: 高。
本次 PR 引入了全新的多用户认证系统、用户数据隔离机制以及用户配置管理。这涉及到对核心 auth 模块、数据库存储层、所有业务服务层(如 analysis_service, watchlist_service, scheduler, chat 等)的根本性改造。
关键风险:

  1. 数据隔离与安全性:若用户 ID 在各服务层面的传递和使用存在疏漏,可能导致用户数据泄露或交叉污染。
  2. 数据库迁移:引入多用户系统通常需要数据库模式变更(如新增用户表、为现有表添加 user_id 字段),src/migration.py 的修改证实了这一点。若迁移脚本不健壮或未提供兼容性方案,可能导致现有数据丢失或不可用。
  3. 兼容性影响:现有单用户部署升级到此版本后,是否需要特殊处理?旧数据如何关联到新用户体系?
  4. 性能AuthMiddleware 中的 has_users() 每次请求会查询数据库以判断是否需要认证,虽然可能开销不大,但值得留意。
  5. 认证流程与用户体验:新的注册、登录、找回密码流程需要充分测试,确保用户体验流畅且安全。

必改项 (阻断项):

  1. PR 描述信息不完整:
    • 必须详细填写 "Background And Problem"、"Scope Of Change"、"Compatibility And Risk" 这几项,以提供足够的上下文和评估依据。
    • 必须提供 "Issue Link" (Fixes #<issue_number> 或 Refs #<issue_number>)。如果没有关联 Issue,请说明原因和验收标准。
  2. 验证命令和结果缺失: 请提供实际执行过的功能测试命令(如 python -m pytest)及其关键结果。如果执行了 ./scripts/ci_gate.sh,也请提供其结果或说明跳过原因。这些对于验证多用户系统的正确性和数据隔离至关重要。
  3. 兼容性与风险评估缺失: 必须详细说明此 PR 对现有部署的兼容性影响、数据迁移方案、以及可能存在的潜在风险。例如,旧配置是否会被自动改写/迁移,用户如何从单用户模式过渡到多用户模式。
  4. 回滚方案缺失: 必须提供至少一句可执行的回滚方案,例如 revert this PR,并说明是否需要额外回滚配置或数据迁移。
  5. Checklist 未勾选: 请仔细阅读 Checklist 并勾选已完成的项目。

建议项:

  1. 明确 PR Type: 请在 PR 描述中勾选 feat 类型,以准确反映本次变更的性质。
  2. graphify 文档位置: AGENTS.md 中新增的 graphify 相关说明似乎是针对开发者的内部工具,建议将其移动到更适合开发者文档的位置,例如 docs/developer_guide.mdCONTRIBUTING.md,以保持 AGENTS.md 内容的聚焦性。
  3. AuthMiddlewarehas_users() 的性能考虑: has_users() 函数在每次请求时都会查询数据库以判断系统是否有注册用户。虽然在无用户状态下它可能只执行几次,但在有用户后,它会在每次未认证请求(或豁免路径之外的请求)时执行,可以考虑是否能在应用启动时缓存这个状态,或者在用户注册/删除时更新一个全局标志位,以避免不必要的 DB 查询。
  4. api/deps.py_SessionLocal 的直接访问: 在 get_user_config_service 中直接访问 db._SessionLocal 略显底层,虽然在当前设计下可能难以完全避免。可以考虑在 DatabaseManager 中提供一个更高级别的接口来获取用户会话所需的 Session 工厂。
  5. 前端变更细节: 由于前端 apps/dsa-web 有大量文件改动,建议在 "Scope Of Change" 或 "Background And Problem" 中简要说明前端的主要 UI 变化点,例如新增了哪些页面、组件用于支持多用户认证、用户配置、或数据隔离的展示等,以便于理解整体功能。

💡 提示: 请确保代码已通过本地测试,并遵循项目代码规范。

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 34d7eb386a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread api/middlewares/auth.py
Comment on lines +56 to +57
except Exception:
return False

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Fail closed when user lookup errors in auth middleware

If the has_users() database query throws (e.g. transient DB outage, migration mismatch), this returns False, and dispatch() then skips authentication for every /api/v1/* route. That turns backend failures into an authorization bypass, exposing protected APIs exactly when infrastructure is unstable. The middleware should deny by default (or return 503) when user existence cannot be determined.

Useful? React with 👍 / 👎.

Comment on lines +129 to +136
_saved_env: Dict[str, Optional[str]] = {}


def _inject_user_settings(settings: Dict[str, str]) -> None:
"""Temporarily inject user settings into os.environ."""
global _saved_env
_saved_env = {}
for k, v in settings.items():

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Remove shared env snapshot across concurrent user runs

The scheduled per-user analysis path runs in parallel threads (src/scheduler.py dispatches one thread per due user), but _inject_user_settings() stores original env values in a single module-global _saved_env. Concurrent executions overwrite each other’s snapshot, so one user's restore step can corrupt another user's runtime config, causing cross-user model/API credentials and analysis settings to leak into the wrong job.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

configuration documentation Improvements or additions to documentation size/XL testing

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant