Commit Graph

328 Commits

Author SHA1 Message Date
c998753eea feat(insta): 카드 탭 트렌딩 키워드 중복 제거 + 10개씩 페이지네이션
KeywordsPanel이 전체 목록을 세로로 길게 표시하던 것을, 동일 keyword
중복 제거(최고 score 유지)·score 내림차순 후 페이지당 10개만 렌더하고
이전(←)/다음(→) 페이저로 탐색하도록 변경. 카테고리 변경 시 첫 페이지 리셋.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-23 03:03:36 +09:00
a846ab89e6 feat(lotto): 헤더 카드를 자율 학습 시스템으로 업데이트
Why: v1(능동 시그널) + v2(자율 가중치 학습) + v2.1(활동 가시화)로
시스템이 진화한 것을 반영. 기존 '시뮬레이션 추천 시스템' 3 bullet
→ '자율 학습 시뮬레이션' 4 bullet (학습 루프·시그널·시뮬·AI 큐레이터).
2026-05-23 02:43:47 +09:00
ef392f02ed refactor(evolver): Lotto 탭으로 통합 + 다크 테마 + activity 스크롤
- EvolverTab.jsx 신규 생성: evolver 컴포넌트를 탭 body로 추출
- Evolver.jsx → Lotto 페이지 thin wrapper로 교체 (/lotto/evolver URL 유지)
- Lotto.jsx: useLocation으로 pathname 감지 → initialTab 결정
- Functions.jsx: 4번째 탭 '🧬 자율 학습' 추가 + initialTab prop 수용
- Evolver.css: light → dark 테마 전환 (rgba/slate 팔레트), activity-list max-height+scroll 적용

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-23 02:38:33 +09:00
2543dc335d feat(evolver): Evolver 페이지 + LottoActivityTimeline + EvolverActions + 라우터
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-23 02:19:07 +09:00
b99d720179 feat(evolver): TrialsGrid + BaseDiff + BaseHistory 3 컴포넌트
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-23 02:16:15 +09:00
734bc6532e feat(evolver): WinnerCard — Radar + 이전 base overlay + 메타 정보 2026-05-23 02:14:58 +09:00
5fd32030ab feat(evolver): useEvolverApi hook (4 fetch + activity merge sort) 2026-05-23 02:14:16 +09:00
e8d33906ba feat(evolver): api.js에 evolver + lotto activity fetch helpers (6개) 2026-05-23 02:13:35 +09:00
6533743100 fix(stock): 총 매입을 각 종목 매입가의 단순 합으로 표시
요약카드(백엔드 매입가×수량)와 증권사별(매입가 단순 합) 총 매입이 서로
달라 혼란. 박재오 정의대로 총 매입 = Σ매입가(수량 미곱산)로 통일.
getBrokerSummary를 stockUtils.computeBrokerSummary로 추출(테스트 5건),
usePortfolio가 portfolioSummary.total_buy를 프론트 단순 합으로 override해
요약카드·증권사별·AI 프롬프트가 동일 값 사용. 손익은 avg_price×수량 유지.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 11:15:58 +09:00
e42b643731 refactor(stock): 거래 데스크에서 AI 투자 탭 제거
TAB_AI 탭과 관련 컴포넌트(AiTradeTab)·훅(useAiBalance) 삭제. 헤더 카드는
aib 모의투자 요약 분기를 제거하고 항상 포트폴리오 요약을 표시.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 08:30:44 +09:00
ee5700dc95 feat(agent-office): 모바일 사이드패널 전체화면 토글 + music 에이전트 이미지 교체
모바일 바텀시트(Commands/Tasks)가 55vh로 작아 내용 확인이 불편 → 헤더에
전체화면 토글 버튼 추가(100dvh 확장, 데스크톱은 숨김). music 에이전트
이미지를 agent_music_2로 교체.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 08:30:38 +09:00
ec5fee8429 chore(agent-office): drop unused break state styling
Backend no longer emits the 'break' state (see web-backend
de8adae). Remove the matching entry from STATE_COLORS and the
.ao-card-dot.break CSS rule. Safe because AgentCard's unknown-state
fallback (DEFAULT_STATE_COLOR) handles any stray legacy value.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 08:44:58 +09:00
96cc5e7839 fix(agent-office): render TaskTab result_data when it's already an object
Old code assumed result_data was a JSON string and ran JSON.parse on it,
falling back to returning the value verbatim on parse error. When the
backend ships result_data as a dict (e.g. compose tasks return
{music_task_id, tracks}), JSON.parse threw, the catch returned the raw
object, and React threw error #31 'Objects are not valid as a React
child' the moment the user expanded the task row.

Extract formatResultData helper: object → JSON.stringify, JSON string
→ parse then pretty-print, plain string → as-is.

Regression tests cover all three input shapes.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 08:38:06 +09:00
e6742e06ba fix(agent-office): unwrap {tasks}/{logs} response objects before .map
Backend returns {"tasks": [...]} and {"logs": [...]} but TaskTab and
LogTab stored the raw object and called .map on it, throwing
'l.map is not a function' the moment a user opened the Tasks or
Logs tab. Unwrap via Array.isArray check (also covers theoretical
bare-array responses).

Regression test for TaskTab covers all three response shapes:
wrapped object, bare array, and empty.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 08:34:08 +09:00
b713f00bf9 feat(agent-office): WS reconnect exponential backoff + status detail
- Replace fixed 3s reconnect with exponential backoff
  (1s/2s/4s/8s/16s/30s, capped). Reduces console noise when
  upstream WebSocket is blocked (e.g. DSM reverse proxy without
  WS upgrade headers).
- ws.onerror swallowed (onclose still schedules reconnect) so the
  browser stops printing an unhandled-error pair per attempt.
- Expose reconnectAttempt in hook; TopBar shows 'Connecting…'
  pre-first-attempt and 'Disconnected · 재연결 시도 #N' after.

Root cause of WS failure is upstream (curl proves the endpoint
itself is fine — see DSM reverse proxy WebSocket headers).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 08:25:18 +09:00
0dce449124 chore(agent-office): convert agent PNGs to WebP (~93% smaller)
ffmpeg libwebp quality=85 compression_level=6.
Total: 11.8MB → 875KB (~11MB saved). Visually indistinguishable on
the card grid at the 9:16 image aspect.

PNG removals were already staged in the previous CommandTab commit;
this commit adds the 6 .webp replacements and points constants.js
imports at .webp.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 07:58:12 +09:00
2c32659f6a fix(agent-office): useAgentManager reconnect via ref to satisfy lint
Previously connect's onclose handler referenced connect itself before
the useCallback declaration, triggering react-hooks/immutability. Hold
the latest connect in a ref (updated in useEffect) and call through it
on reconnect. Same runtime behavior, lint-clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 07:58:04 +09:00
add2d8044c style(agent-office): neutral color for sidepanel state line
Was hardcoded #22c55e (green) regardless of actual state, making
error/break states look healthy. Switch to muted #94a3b8.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 07:57:57 +09:00
2e9b0daec6 fix(agent-office): CommandTab approval state + blog→insta agent
- Approval card gated on 'waiting_approval' (was 'waiting'), matching
  the state useAgentManager emits — previously the approval UI was
  silently suppressed and pendingTask buttons unreachable
- QUICK_ACTIONS/PARAM_ACTIONS: drop blog (agent removed),
  add insta (extract / collect_trends / render)
- Regression test covers the three approval-card branches

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 07:57:41 +09:00
46589c05b1 feat(insta): 슬레이트 캐러셀 + 반응형 레이아웃 전면 개선
문제:
- 페이지 1~10 미리보기가 가로 overflow인데 시각 affordance 없어서 page 2~10 못 봄
- 슬레이트 목록(.ic-slates-grid)이 모바일에서 어색 + 카드 자체가 viewport 밖으로 밀림

수정:
- PagesStrip 컴포넌트 신설: 좌/우 chevron + page 인디케이터(3/10) + 양옆 fade gradient
  + 키보드 ←/→ + scroll-snap + 클릭 페이지 이동 + 활성 카드 핑크 테두리/scale
- .ic-page-img width를 clamp(140px, 42vw, 220px)로 viewport 비례
- .ic-slates-grid 모바일 2칸 강제, 640px+ 부터 auto-fill
- .ic-detail에 min-width: 0 + max-width: 100% (자식이 부모 안 밀게)
- .ic-layout grid-template-columns에 minmax(0, 1fr) — 자식 overflow 시 부모 안정
- .ic 모바일 좌우 padding 12px (768px+ 16px)
2026-05-18 07:30:25 +09:00
2a9c8cb619 style(agent-office): match card image to 941x1672 aspect, fill grid width
- Card image aspect-ratio 1/1 → 941/1672 (real image ratio, no crop)
- object-fit cover → contain (defensive against rounding)
- Drop card aspect-ratio so it grows from natural image+name height
- Drop grid max-width 720px so grid fills the viewport width

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 00:00:30 +09:00
bcaf217b72 feat(agent-office): commit agent character images
6 PNGs for 5 active agents + 1 shared placeholder. Required by
constants.js imports; without these the build resolves them from
local disk but a clean clone or NAS deploy would 404.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 21:03:46 +09:00
18e309a14b feat(agent-office): replace canvas office with 3x3 agent grid
- AgentOffice renders TopBar + AgentGrid + dynamic right panel
- Right panel: SidePanel (active) / EmptyDetailPanel (initial or placeholder)
- TopBar simplified to connected status only (theme/zoom dropped)
- Wire AgentGrid through useAgentManager state
- Remove canvas/ (9 files), useOfficeCanvas, office-map.json
- New CSS for grid cards (state dot, notification badge, accent border)
- Mobile: 2-column grid + bottom-sheet panel

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 21:03:15 +09:00
80598cda93 refactor(agent-office): SidePanel uses central AGENT_META + image header
- emoji icon replaced with agent_{id}.png image
- AGENT_META imported from constants (single source of truth)
- blog removed, insta added (matches backend agent registry)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 20:59:25 +09:00
e49457ca46 feat(agent-office): EmptyDetailPanel for initial + placeholder views
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 20:58:06 +09:00
e04e2b010c feat(agent-office): AgentGrid renders 9 slots from GRID_SLOTS
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 20:57:20 +09:00
3fd923400f feat(agent-office): PlaceholderCard for unstaffed slots
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 20:56:02 +09:00
6d1f4914ca test(agent-office): cover pulse class for AgentCard state dot
Adds two tests verifying that working state adds the pulse class and
idle state does not. Pulse animation is part of the design spec §5
but was not covered by the original 8 tests.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 20:55:24 +09:00
1630109856 feat(agent-office): AgentCard component with state dot + badge
- state→color mapping via STATE_COLORS
- notification badge with 9+ overflow
- active prop for selected card border

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 20:52:34 +09:00
50d427e367 refactor(agent-office): derive ACTIVE_AGENT_IDS from GRID_SLOTS
Eliminates dual-write drift risk between ACTIVE_AGENT_IDS list
and GRID_SLOTS slot ordering. Single source of truth is now
GRID_SLOTS; ACTIVE_AGENT_IDS is computed from it.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 20:50:42 +09:00
07f1d34f4c feat(agent-office): centralize AGENT_META + grid slot layout
- 5 active agents (stock/music/insta/realestate/lotto) + 4 placeholders
- AGENT_META, GRID_SLOTS, STATE_COLORS in single constants module
- blog removed (replaced by insta)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 20:47:47 +09:00
d2838dfb7a docs(agent-office): implementation plan for 3x3 grid redesign
11 tasks covering AGENT_META centralization, AgentCard/PlaceholderCard/
AgentGrid/EmptyDetailPanel new components, SidePanel image header,
TopBar simplification, canvas removal, build + manual verification.

TDD for pure logic (constants, AgentCard); visual verification for layout.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 20:36:52 +09:00
ce09f804b6 docs(agent-office): 3x3 grid redesign design spec
Replace pixel-office canvas with 3x3 agent image grid.
- 5 active agents (stock/music/insta/realestate/lotto) + 4 placeholders
- Drop blog from AGENT_META, insta replaces it
- New assets dir: src/pages/agent-office/assets/agents/
- Remove canvas/ dir + useOfficeCanvas + office-map.json
- Keep useAgentManager (WebSocket) + 4-tab SidePanel

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 20:26:57 +09:00
534ded59e8 docs(signal-v2): amend spread formula to absolute (q90-q10) for Chronos-bolt zero-shot reality
Phase 0 spec §6.1 originally specified relative spread (q90-q10)/median < 0.6.
Phase 3b smoke (005930: median=-0.59%, q90-q10=15.3%) revealed Chronos-bolt
zero-shot median frequently sits near zero, causing relative spread to explode
(15.3/0.0059 ≈ 25) and reject every signal. Absolute spread (0.153 < 0.6)
preserves the threshold semantic and keeps Phase 7 IC validation tractable.

Phase 4 spec §4.2 + Phase 0 §6.1 both amended with cross-reference.
chronos_predictor.py conf calculation unchanged — monotonic mapping there
is independent of hard-gate semantics.
2026-05-17 13:10:50 +09:00
f4b78da176 docs(signal-v2): Phase 4 implementation plan — 4 tasks TDD
Task 1: foundation (config 6 env + state.signals)
Task 2: signal_generator + 9 unit tests (TDD)
Task 3: pull_worker + main.py integration + 1 test
Task 4: user manual (.env optional + smoke + push)

10 new tests, total 55 signal_v2 tests. ~3-5 days.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 12:52:13 +09:00
aeeab6704f fix(insta): SlateDetail JSON 객체 렌더 오류 + 카드 생성 시 자동 스크롤
(1) React error #31 fix: cover_copy/cta_copy는 객체({headline,body,accent_color}),
    body_copies는 배열 — 직접 {slate.cover_copy}로 렌더하면 에러. 필드별로
    분해 렌더하고, 10페이지 전체 카피(커버 1 + 본문 8 + CTA 1)를 detail에
    노출하도록 SlateDetail 확장.

(2) UX: handleCreateSlate 시작 시 window.scrollTo(0, 0)로 상단 progress 배너
    노출 보장. KeywordsPanel의 🎴 버튼도 부모 handleCreateSlate 위임으로
    통합 — Trends/Cards 양쪽 어디서 눌러도 동일 흐름(배너 + 자동 미리보기).

(3) KeywordsPanel의 자체 slatePoll 제거 — 상단 ic-slate-progress 배너로
    일원화하여 중복 진행 표시 회피.
2026-05-17 12:51:26 +09:00
6222b56716 feat(insta): trends 카드 생성 시 progress 배너 + 자동 미리보기 전환
Trends 탭의 🎴 버튼 클릭이 silent로 끝나 사용자에게 무동작처럼 보이던
이슈 fix. handleCreateSlate를 3초 간격 폴링으로 확장 (최대 8분):

- 시작/진행/성공/실패 상단 배너로 시각화
- 카드 생성 완료 시 자동으로 Cards 탭 전환 + 새 슬레이트 자동 선택
  → SlateDetail이 카피·이미지 미리보기 즉시 표시
- 실패 시 에러 메시지 + 클릭으로 dismiss
- "Claude 카피 추론 + Playwright 카드 10장 생성 중 (3~7분)" 안내 문구
2026-05-17 12:41:04 +09:00
9e9eed2162 docs(signal-v2): Phase 4 signal generator spec
매수/매도 룰 (Phase 0 spec §6.1-§6.3) + confidence_webai 공식
(chronos*0.5 + minute*0.3 + screener*0.2) + SignalDedup 24h. 6 env
외부화 (STOP_LOSS/TAKE_PROFIT/SPREAD/BID_RATIO/CONFIDENCE/MIN_MOMENTUM).
state.signals = Phase 0 spec §5.2 schema. 10 new tests.

brainstorming 6 decisions: scope=A(생성만) / trigger=A(매 cycle) /
minute_score=A(linear 5-level) / thresholds=A+(6 env) / state=A(spec §5.2) /
test=A(9 unit + 1 integration).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 12:40:24 +09:00
06affd9614 feat(insta): swap google_trends source for youtube_trending (Google Trends API 폐기 대응) 2026-05-17 11:54:10 +09:00
b0eda14982 feat(insta): Trends tab — account focus + external trends + impact preview
- api.js: add getInstaTrends, instaCollectTrends, getInstaPreferences, putInstaPreferences helpers
- InstaCards.jsx: add Cards/Trends tab bar with URL sync (?tab=trends); add AccountFocusPanel (category weight sliders + save), ExternalTrendsPanel (Naver+Google trend rows + manual collect), PreferenceImpactPanel (next extract preview); existing 5-panel Cards tab preserved intact
- InstaCards.css: add ic-tabbar, ic-tab, ic-trends-grid, ic-panel base, ic-focus/ic-trend/ic-impact component styles

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-16 18:04:47 +09:00
1f55d24ce6 docs(signal-v2): Phase 3b implementation plan — 7 tasks TDD
Task 1: foundation (config + state + requirements)
Task 2: kis_client.get_daily_ohlcv + 1 test
Task 3: momentum_classifier (pure functions) + 6 tests
Task 4: chronos_predictor + 4 tests (mock pipeline)
Task 5: pull_worker post-close cycle + scheduler trigger + 1 test
Task 6: main.py lifespan ChronosPredictor
Task 7: user manual (pip install + .env + smoke + push)

12 new tests, total 45 signal_v2 tests. ~1 week.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-16 17:42:17 +09:00
6eb4ab1204 docs(signal-v2): Phase 3b Chronos-2 + minute momentum spec
KIS daily OHLCV fetch (kis_client.get_daily_ohlcv, FHKST03010100) +
ChronosPredictor (HuggingFace amazon/chronos-2 zero-shot, env-configurable
model, always-loaded) + minute momentum classifier (5-level rule:
strong_up/weak_up/neutral/weak_down/strong_down) + post-close cycle
trigger (16:00 KST). 12 new tests (33 → 45 total).

brainstorming 7 decisions: daily=B(KIS REST) / freq=A(post-close 1x) /
model=A(env CHRONOS_MODEL) / momentum=A(5-level rule) / state=B(median+
q10+q90+conf+as_of) / test=A(mock+pure) / scope=integrated.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-16 17:37:17 +09:00
78b77e2691 docs(signal-v2): Phase 3a implementation plan — 7 tasks TDD
Task 1: config + state + websockets dep
Task 2: scheduler NXT windows + 3 tests
Task 3: kis_client REST + 4 tests
Task 4: kis_websocket + 4 tests (most heavy)
Task 5: pull_worker minute cycle + 2 tests
Task 6: main.py KIS lifespan + 1 test
Task 7: user manual .env + smoke + push

13 new tests, total 32 signal_v2 tests. ~1 week.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-16 05:00:43 +09:00
1813db761f docs(signal-v2): Phase 3a KIS data collection spec
KIS REST client (minute OHLCV + asking price polling, V1 token
read-only share) + KIS WebSocket client (approval_key + portfolio
asking_price realtime subscribe) + PollState extension + scheduler
NXT windows (20:00-23:30 / 04:30-07:00). 13 new tests.

brainstorming 6 decisions: scope=B(3a/3b split) / data=B(REST minute +
WS asking) / auth=A(V1 token share) / subscribe=A(portfolio WS +
screener REST) / NXT=C(scheduler extend) / test=A(respx + WS mock).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-16 04:50:16 +09:00
01d9b2f872 docs(signal-v2): Phase 2 implementation plan — 6 tasks TDD
Task 1: foundation (config + state + gitignore + requirements)
Task 2: stock_client + 6 tests (httpx retry + cache)
Task 3: scheduler + 5 tests (market windows + holidays)
Task 4: rate_limit + 3 tests (SQLite WAL dedup)
Task 5: pull_worker + FastAPI app + 2 tests (lifespan + /health)
Task 6: holidays sync + start.bat + user .env + manual smoke

Total 16 tests. ~1 week.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-16 03:31:31 +09:00
b9dabd07e0 docs(signal-v2): Phase 2 web-ai pull worker spec
stock pull worker + asyncio scheduler + rate limit SQLite + FastAPI
app (:8001). 16 tests planned. brainstorming 6 decisions:
batch=A(separate FastAPI :8001) / scope=A(3 items) / scheduler=B(asyncio
cron) / http=B(httpx + custom retry + memory cache) / rate-limit=A(SQLite
WAL) / test=B(pytest-asyncio + httpx mock).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-16 03:14:45 +09:00
a8e411ec22 feat(insta): replace Blog Lab page with Insta cards UI
/blog-lab → /insta route. New InstaCards page consumes insta-lab API
(news/keywords/slates + 10-page card preview + prompt template editor).
25개 blog-marketing API helper 제거, 13개 insta helper 추가.
2026-05-16 02:47:19 +09:00
f261a80d52 docs(signal-v1): web-ai V1 rename plan — 13 step atomic refactor
Single big task (Task 1) for atomic mv + load_dotenv update +
new CLAUDE.md/start.bat + verification. Task 2 = user manual
push + 30-min runtime verification.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-16 00:23:38 +09:00
42e9c8df27 docs(signal-v1): web-ai V1 → signal_v1/ rename spec
atomic refactor (single commit) of web-ai root V1 assets into
signal_v1/ subdirectory. V2 (signal_v2/) Phase 2 will be added
alongside in subsequent slice. Pattern mirrors stock-lab → stock
graduation.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-16 00:19:00 +09:00
c84c6b5bac docs(signal-v2): Phase 1 implementation plan — 7 tasks TDD
7 tasks: auth.py + verify_webai_key (Task 1) → portfolio + pnl_pct
(Task 2) → news-sentiment (Task 3) → common edge cases (Task 4) →
docker-compose env (Task 5) → nginx config (Task 6) → deploy +
manual smoke (Task 7). 16 tests total (4 unit + 12 integration).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 08:30:53 +09:00