* feat: add reliable home watchlist workspace
* fix(review-feedback-1984): Don't trust stale stock-bar rows after refresh failures
* fix(review-feedback-1984): apps/dsa-web/src/stores/stockPoolStore.ts 的 refreshStockBar
* fix(review-feedback-1984): Clear loading when refresh supersedes initial stock-bar load
* fix(review-feedback-1984): Type stock-bar test fixtures as StockBarItem and 跟进结论 - 结论 :不接受;最新
* fix(review-feedback-1984): tying the Today fetch to the same refresh path while this tab is
* feat(issue-1580): feat:-完善大盘复盘历史聚合、查看与删除能力
* fix(review-feedback-1598): resetting the paged window or deduping the merged list before storing it
* fix(review-feedback-1598): 补齐 AGENTS.md 要求的用户可见能力文档同步
* feat: add stock bar sidebar and watchlist management
- Replace history list sidebar with stock bar that deduplicates stocks
and places market review at top, ordered by latest analysis time
- Add GET /api/v1/history/stocks endpoint for distinct stock list
- Add code normalization to merge code variants (e.g. 002460 / 002460.SZ)
- Add GET/POST /api/v1/stocks/watchlist CRUD endpoints
- Add watchlist card to report detail right sidebar
- Add watchlist buttons to chat/ask page with auto stock code detection
- Add useWatchlist hook for shared watchlist state management
- Update CHANGELOG with [Unreleased] flat entries
Refs #1530
* fix: use canonical normalize_stock_code for stock code dedup
Replace ad-hoc suffix stripping with the existing normalize_stock_code
in data_provider/base.py, which handles all supported variants:
SH600519 / 600519.SH / HK00700 / 00700.HK / BJ920748 / 920748.BJ.
Addresses Codex P2 suggestion on PR #1540.
* fix: address PR review feedback on #1540
1. Fix extractStockCodeFromMessage to reject exchange prefixes
(SH/SZ/BJ/HK/US/SS) as standalone tickers; add explicit patterns
for SH600519/SZ000001/BJ920748 prefix formats.
Move function to utils/chatStockCode.ts to satisfy react-refresh.
2. Add stock code validation and normalization in watchlist API
(add/remove endpoints now validate format and use
normalize_stock_code before persisting to STOCK_LIST).
3. Over-fetch distinct stocks (limit*3) before normalization dedup
to avoid losing results when code variants shrink after grouping.
4. Update HomePage tests: remove batch-delete test scenario (sidebar
replaced by StockBar), add getStockBarList/getWatchlist mocks,
adjust assertions to match StockBarItem accessible names.
Refs #1540
* fix: normalize watchlist codes on read/write and strengthen validation
1. _read_watchlist_codes now normalizes and deduplicates all existing
STOCK_LIST entries via normalize_stock_code, so hk00700/HK00700/00700.HK
are treated as one canonical entry.
2. _write_watchlist_codes deduplicates before persisting.
3. _validate_and_normalize_stock_code uses regex matching against
all supported stock code formats (aligned with frontend validateStockCode).
4. Restore accidentally deleted CHANGELOG entry for same-stock history trend.
5. Fix CHANGELOG/PR description API paths to match actual routes.
Refs #1540
* fix: normalize stock codes in frontend watchlist comparison
Add normalizeStockCode utility mirroring backend normalize_stock_code,
and use it in isInWatchlist so SH600519/600519.SH/HK00700/00700.HK
variants are all recognized as the same stock. Add 10 regression tests.
Refs #1540
* fix: normalize stock code variants in watchlist comparison and extraction
1. ChatPage.tsx: stockInWatchlist now normalizes input via normalizeStockCode
before comparing against watchlistCodes, so SH600519/600519.SH variants
are correctly recognized as already being in the watchlist.
2. chatStockCode.ts: add \d{1,5}\.HK suffix pattern (e.g. 00700.HK → HK00700),
and return normalizeStockCode(normalized) for all extracted codes.
3. stocks.py: add bare 5-digit HK code (\d{5}) to _STOCK_CODE_RE regex.
4. ChatPage tests: add mockGetWatchlist/AddToWatchlist/RemoveFromWatchlist mocks,
add 2 regression tests for watchlist button with code variants
(600519.SH → 600519 and 1810.HK → HK01810).
Refs #1540
* fix: keep STOCK_LIST as-is, normalize only for comparison
Revert read/write normalization in _read_watchlist_codes and
_write_watchlist_codes. STOCK_LIST is now stored exactly as the user
input, without auto-normalization. Add/remove endpoints normalize
only for duplicate/matching comparison, preserving raw codes.
Refs #1540
* feat: restore batch delete in StockBar and add delete-by-code API
1. Add DELETE /api/v1/history/by-code/{stock_code} endpoint to delete
all history records for a given stock code in one call.
2. Add deleteByCode function to frontend historyApi.
3. StockBar: restore select-all checkbox and batch delete button,
matching the original HistoryList UX.
4. StockBarItem: add per-item delete button (trash icon, visible on hover).
5. HomePage: wire handleDeleteStock to StockBar, refresh stock bar and
history after deletion.
6. Update CHANGELOG to reflect restored batch delete capability.
Refs #1540
* fix: preserve change_pct in history detail (#1084)
- Replace truthy 'or' chains with explicit 'is None' checks so a 0.0 daily
change (flat) is no longer dropped from the response meta.
- Drop incorrect change_60d fallback (60-day cumulative) for the daily
change_pct field.
- When enhanced_context.realtime has price but no change_pct, fall back to
realtime_quote_raw.change_pct / pct_chg unconditionally, matching the
fix already applied to api/v1/endpoints/analysis.py.
Adds two regression tests covering the zero-value preservation and the
realtime_quote_raw fallback path.
* feat: add configurable report language
* Fix review follow-ups for history and fallback localization
* fix: prefer .env report language at startup
* fix: address report language review feedback
* fix: address latest report language review feedback
* feat: implement batch deletion of analysis history with UI/UX improvements
- Backend: Added DELETE /api/v1/history endpoint for bulk deletion by IDs.
- Storage: Implemented DatabaseManager.delete_analysis_history_records with cascade cleanup of BacktestResult to prevent foreign key constraints.
- Frontend:
- Added checkbox-based multi-selection to HistoryList component.
- Implemented batch delete logic in HomePage with automatic selection fallback.
- Extracted and standardized ConfirmDialog component for consistent design across the app.
- Updated ChatPage to use the new standardized ConfirmDialog.
- Tests: Added unit tests for database cascade deletion and API endpoint functionality.
* docs: update README and CHANGELOG for batch history deletion
* feat: Implement the main HomePage for stock analysis and history management, supported by a new history service.
---------
Co-authored-by: mumu <42829555+ZhuLinsen@users.noreply.github.com>
* feat: mark model used in reports and notifications (#528)
* refactor: centralize model_used normalization and raw_result parsing (#528)
---------
Co-authored-by: mumu <42829555+ZhuLinsen@users.noreply.github.com>
- Guard against None/empty response.choices in LLMToolAdapter._call_api()
before accessing choices[0]; raise descriptive ValueError instead of
cryptic TypeError (Fixes#390)
- Change history detail/news endpoint record_id type from int to str;
add _resolve_record() that tries integer PK first then falls back to
query_id lookup; add get_latest_analysis_by_query_id() in storage layer
(Fixes#432)
- Enhance _extract_sniper_points() with multi-level dashboard traversal
(standard path → dashboard dict → raw_response); add _find_sniper_in_dashboard()
recursive search; improve _parse_sniper_value() edge case handling for zero
values, full-width commas, and placeholder strings (Fixes#436)
#patch
* resolve empty analysis result list problem by endDate + 1
* fix bug 322 by using record id for db query
* address comments
* address potential issue and error