Commit Graph

513 Commits

Author SHA1 Message Date
2b5009f864 fix(sqlite): WAL + busy_timeout 120s standardized across all labs
8개 lab의 _conn() 함수에 표준 동시성 패턴 통일:
- timeout=120.0 (connection 획득)
- PRAGMA journal_mode=WAL (reader/writer 분리)
- PRAGMA busy_timeout=120000 (트랜잭션 충돌 시 120초 대기)

stock-lab/screener/router.py 의 검증된 패턴(d9b6122) 을 lotto, stock-lab(메인),
music-lab, blog-lab, realestate-lab, agent-office, personal, travel-proxy 로 확산.
기존 'database is locked' 오류 윈도우를 흡수.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 22:12:01 +09:00
d9b612253a fix(stock-lab): snapshot flow 범위 100종목 + busy_timeout 2분 (writer 충돌 완화)
자동 잡 16:30 KST 실패 원인:
- agent-office httpx timeout 180s
- 그러나 snapshot/refresh의 flow 스크래핑(500종목 × 0.2-0.5s) = 100~250s
- 180s 초과 시 client timeout → 서버 background 처리 계속
- 곧 /run 호출 → snapshot의 long write transaction과 INSERT 충돌
- WAL은 reader/writer 분리만, writer 두 명은 직렬 → busy_timeout 30s 초과 lock

Fix:
- DEFAULT_FLOW_TOP_N 500 → 100 (시총 상위 100종목 × 0.2s = ~20s)
- busy_timeout 30s → 120s (snapshot write 시간보다 충분히 김)
- connect timeout 30s → 120s

외국인 매수 시그널은 대형주에서 의미 큼. 상위 100종목으로 충분.
더 많은 커버리지 필요 시 별도 cron으로 snapshot/refresh와 /run 시간 분리.
2026-05-13 19:56:30 +09:00
db4322006d fix(stock-lab): screener DB connection WAL 모드 + busy_timeout 30s
snapshot/refresh 직후 /run mode=auto가 'database is locked'으로 500
실패하던 증상 fix. SQLite 기본 rollback journal 모드 + busy_timeout=0
조합에서 long write transaction과 read가 겹치면 즉시 OperationalError.

PRAGMA journal_mode=WAL: reader가 writer를 block 안 함
PRAGMA busy_timeout=30000: 30초 대기 후 timeout (즉시 실패 X)
sqlite3.connect timeout=30: connection 획득 자체에도 대기 적용

agent-office 자동 잡 16:30 KST 흐름 안정화.
2026-05-13 16:50:25 +09:00
a05e6ba8ca feat(stock-lab): 텔레그램 노드 풀 라벨 + 원 단위 표기
- 아이콘(👤외/🆙고/...) 제거하고 풀 한글 라벨로 변경
  (외국인/거래량급증/20일모멘텀/52주신고가/RS레이팅/이평선정배열/VCP수축)
- 가격은 "103,917원" 형태로 원 단위 명시
- 활성 노드 없을 때 fallback 문구
- 테스트도 새 포맷으로 갱신 + 원 단위 검증 신규 케이스
2026-05-13 07:52:17 +09:00
4a333434ac Merge feature/stock-screener-board: Stock Screener Board MVP (backend + agent-office)
stock-lab:
- pykrx→FDR/네이버 데이터 전환 (KRX 인증 회피)
- 스키마 7테이블 + 디폴트 시드
- snapshot.py (FDR 마스터·일봉 + 네이버 외국인 수급, 시총 상위 500종목)
- ScreenContext, ScoreNode/GateNode 추상, percentile_rank
- 게이트 1 (HygieneGate) + 점수 노드 7 (ForeignBuy/VolumeSurge/Momentum20/
  High52WProximity/RsRating/MaAlignment/VcpLite)
- Screener 엔진 + combine + position_sizer (ATR Wilder) + telegram 빌더
- FastAPI 라우터: /nodes, /settings, /run (preview/manual_save/auto),
  /snapshot/refresh, /runs (리스트·상세), 공휴일·주말 skipped_holiday

agent-office:
- StockAgent.on_screener_schedule + run_screener 명령
- 평일 16:30 KST APScheduler cron (Asia/Seoul)
- service_proxy 헬퍼, send_raw parse_mode 확장 (MarkdownV2 지원)
- 5 신규 테스트, 38 회귀 통과
2026-05-13 07:23:43 +09:00
119ac88e1e feat(agent-office): stock screener 평일 16:30 KST 자동 잡 + 텔레그램 전송
- StockAgent.on_screener_schedule: snapshot/refresh → screener/run(mode=auto)
  → telegram_payload(MarkdownV2) 발송. skipped_holiday는 무발신,
  실패 시 운영자 HTML 알림.
- service_proxy: refresh_screener_snapshot, run_stock_screener 추가
  (각각 180s timeout, STOCK_LAB_URL 기존 env 재사용).
- telegram.messaging.send_raw: parse_mode 파라미터 추가
  (기본 HTML 유지, MarkdownV2 페이로드 직접 전달용).
- scheduler: cron day_of_week=mon-fri hour=16 minute=30 id=stock_screener
  (Asia/Seoul TZ).
- on_command 'run_screener' 수동 트리거 추가.
- tests: 성공/휴일/스냅샷실패/run실패/이상status 5케이스.
2026-05-12 14:54:24 +09:00
c4cb18a25c feat(stock-lab): /run mode=auto 공휴일·주말 skipped_holiday 처리 2026-05-12 13:49:45 +09:00
50e811c5dd feat(stock-lab): /snapshot/refresh + /runs 리스트·상세 라우터 2026-05-12 13:47:16 +09:00
5ec7c2461b feat(stock-lab): /run 엔드포인트 — preview/manual_save/auto 모드 매트릭스 2026-05-12 13:44:21 +09:00
5f0fed7f13 feat(stock-lab): /nodes + /settings 라우터 + main.py include
- screener/router.py: APIRouter prefix=/api/stock/screener
  - GET /nodes: NODE_REGISTRY + GATE_REGISTRY 메타 노출 (7 score + 1 gate)
  - GET /settings: screener_settings 싱글톤 row 조회
  - PUT /settings: 가중치/노드/게이트 파라미터 round-trip
- main.py: screener_router include (FastAPI 생성 직후)
- db.py: STOCK_DB_PATH 환경변수 지원 (테스트 격리, 기본값 /app/data/stock.db 유지)
- test_screener_router.py: 3 tests (nodes list, settings GET, PUT round-trip)
2026-05-12 13:41:24 +09:00
070f2de3f1 feat(stock-lab): screener Pydantic 스키마 2026-05-12 13:37:23 +09:00
01ebd2e7d9 feat(stock-lab): telegram.py 메시지 빌더 (Top10 + 아이콘 + 페이지 링크) 2026-05-12 09:34:53 +09:00
7db9869722 feat(stock-lab): Screener 엔진 + combine + ScreenerResult + 노드 레지스트리
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 09:29:10 +09:00
97cb38ca7f feat(stock-lab): position_sizer — ATR Wilder + entry/stop/target 2026-05-12 09:25:49 +09:00
90c408aa77 feat(stock-lab): VcpLite 노드 — 변동성 수축률 백분위 2026-05-12 09:07:59 +09:00
55f2fa9cff feat(stock-lab): MaAlignment 노드 — 이평선 정배열 5조건 룰 점수 2026-05-12 09:06:45 +09:00
3ded781059 feat(stock-lab): RsRating 노드 — IBD 가중 시장초과수익 백분위 2026-05-12 09:02:28 +09:00
4eaeea9833 feat(stock-lab): High52WProximity 노드 — 신고가 대비 근접도 룰 점수 2026-05-12 08:59:55 +09:00
9709e5b019 feat(stock-lab): Momentum20 노드 — N일 수익률 백분위 2026-05-12 08:58:43 +09:00
94d6a39ce8 feat(stock-lab): VolumeSurge 노드 — log(최근/평균) 거래량 급증 2026-05-12 08:54:47 +09:00
804fdcba26 feat(stock-lab): ForeignBuy 노드 — 외국인 N일 누적 순매수 강도 2026-05-12 08:19:44 +09:00
204cee67d6 fix(lotto): grade_weekly_review import용 httpx 의존성 추가
운영 사이트 nginx emerg 'host not found in upstream lotto'의 진짜
원인은 lotto 컨테이너 자체가 ModuleNotFoundError: httpx로 시작 실패한
것이었음. grade_weekly_review.py가 httpx를 import하는데 requirements
에서 누락. 재빌드 시 컨테이너 정상 부팅 가능.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 08:03:34 +09:00
779e78405e feat(stock-lab): HygieneGate — 위생 필터 (시총/거래대금/우선주/관리종목) 2026-05-12 07:59:32 +09:00
16a651f670 feat(stock-lab): ScoreNode/GateNode 추상 + percentile_rank 유틸 2026-05-12 07:52:01 +09:00
e508b7dc35 feat(stock-lab): ScreenContext.load/restrict + 합성 픽스쳐 2026-05-12 07:49:15 +09:00
6c5481971b feat(stock-lab): FDR 종목 마스터+일봉 + naver 외국인 수급 (snapshot) 2026-05-12 07:41:40 +09:00
d7e235c008 feat(stock-lab): screener 스키마 7테이블 + 디폴트 설정 시드 2026-05-12 04:10:36 +09:00
8707d322e4 chore(stock-lab): FDR/네이버 데이터 의존성 + screener 패키지 골격 2026-05-12 04:07:52 +09:00
b4dd21e67a feat(packs-lab): chunked resumable upload (offset-based) 추가
기존 single-shot POST /upload는 그대로 유지하고, 5GB+ 안정성을 위한
chunk upload 5-endpoint를 추가했다.

- POST /upload/init — mint-token jti consume + 세션 디렉토리 생성
- PUT /upload/{sid}/chunk?offset=N — offset 매칭 후 .part 파일 append
  · 불일치 시 409 + X-Current-Offset 헤더로 재개 지점 통보
- GET /upload/{sid}/status — 현재 written / expected_size 조회
- POST /upload/{sid}/complete — atomic rename + Supabase INSERT
- DELETE /upload/{sid} — 세션 중단 + 부분파일 정리

auth.py: verify_upload_token_no_consume() 추가 — chunk/complete/abort/status
는 동일 mint-token을 재사용해야 하므로 jti consume 없이 시그니처+만료만 검증.

models.py: InitUploadResponse, ChunkUploadResponse 추가.

세션 state: PACK_BASE_DIR/.uploads/{jti}/meta.json + data.part (파일시스템
영속, 단일 컨테이너 가정).

chunk 크기 상한: PACK_CHUNK_MAX_SIZE env (기본 64MB).

tests: chunk upload 시나리오 8종 — full-flow / offset mismatch / status /
abort / wrong token / incomplete complete / filename collision / host path
저장. 전체 37 테스트 pass.

CLAUDE.md: packs-lab API 표에 chunk 5-endpoint + 사용 패턴 보강.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 02:36:20 +09:00
448dbd5f48 feat(packs-lab): DSM 호출 retry/backoff + 업로드 cleanup 보강
- dsm_client.py: _request_with_retry()로 5xx·transport·timeout만 지수백오프
  재시도 (DSM_MAX_RETRIES, DSM_BACKOFF_SEC env). DSM error code 응답 본문 로깅.
- routes.py: upload 핸들러를 try/finally로 감싸 부분파일 정리 보장, Supabase
  INSERT 호출 자체에 try/except 추가해 네트워크 예외도 cleanup.
- test_dsm_client.py: retry 시나리오 4종 추가 (5xx→성공/소진/transport
  error/4xx no-retry). 전체 29 테스트 pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 02:31:39 +09:00
a826e00399 feat(stock): NXT 시간외 거래가를 정규장 마감 후 자동 연결
네이버 모바일 주식 API의 overMarketPriceInfo를 인식해 NXT 프리/애프터마켓
운영 중이면 overPrice를 current_price로 자동 전환. 포트폴리오 응답에
price_session(REGULAR/NXT_PRE/NXT_AFTER/CLOSED)과 price_as_of 메타 동봉.

이전엔 closePrice만 사용해 15:30 이후 NXT 거래가 진행 중이어도 평가금액이
동결됐음. 이제 가격이 자연스럽게 이어짐. _select_price_from_response는
순수 함수로 분리, unittest 8케이스로 회귀 방지.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 19:32:10 +09:00
134e628e5e Merge feature/lotto-curator-evolution: Lotto Curator Evolution
16 commits across Phase A-E + H:
- weekly_review 테이블 + grade_weekly_review 잡 (일 03:00 KST)
- review/bulk/briefing 4계층 라우터
- 큐레이터 4계층 스키마 + retrospective + N=30
- 텔레그램 큐레이션·당첨 알림 + lotto_agent 월 09:00 KST
- 1주차 운영 점검 체크리스트

자세한 컨셉/계획: web-ui/docs/superpowers/{specs,plans}/2026-05-11-*.md
2026-05-11 09:38:31 +09:00
ce3a734e81 docs(lotto): 1주차 운영 점검 체크리스트 2026-05-11 09:08:05 +09:00
fb81c51dc8 feat(curator): 큐레이션 후 텔레그램 자동 푸시 + cron 09:00 변경 2026-05-11 08:55:12 +09:00
715e1598ce feat(agent-office): /api/agent-office/notify/lotto-prize 웹훅 2026-05-11 08:54:19 +09:00
57a4a72ff1 feat(curator): 텔레그램 큐레이션·당첨 알림 포맷터 2026-05-11 08:53:10 +09:00
e14278ec69 feat(curator): pipeline 4계층 직렬화 + retrospective 컨텍스트 + N=30 2026-05-11 08:51:07 +09:00
ff3134b838 feat(curator): build_retrospective + lotto review service proxy 2026-05-11 08:49:58 +09:00
95c5dc4217 feat(curator): SYSTEM_PROMPT 회고 + 4계층 규칙 2026-05-11 08:48:06 +09:00
9fb1c37eae feat(curator): 4계층 picks + tier_rationale + narrative.retrospective 스키마 2026-05-11 08:46:50 +09:00
3bd819b5e2 feat(lotto): briefing API 4계층 picks + tier_rationale 수용 2026-05-11 08:45:21 +09:00
b936233e7c feat(lotto): POST /api/lotto/purchase/bulk — 결정카드 원클릭 기록 2026-05-11 08:42:27 +09:00
4f85496fe5 feat(lotto): review 라우터 — latest/history/by-draw 2026-05-11 08:39:01 +09:00
2a2209a86c feat(lotto): 일 03:00 KST 채점 잡 APScheduler 등록 2026-05-11 08:37:08 +09:00
30bc627ae7 feat(lotto): grade_weekly_review 통합 잡 — 큐레이터 자기평가 + 패턴 갭 2026-05-11 08:33:51 +09:00
d972ea66c3 feat(lotto): 채점 보조 함수 — 일치 수·패턴 요약·델타 2026-05-11 08:29:46 +09:00
66165ebb88 feat(lotto): lotto_briefings.picks 4계층 객체로 마이그레이션 + tier_rationale 컬럼 2026-05-11 08:25:23 +09:00
5621cc7687 feat(lotto): weekly_review 테이블 + CRUD 헬퍼 2026-05-11 08:21:44 +09:00
fb54998def fix(deployer): deploy.sh 4 화이트리스트에 packs-lab 추가 + media/packs 자동 생성
deployer가 webhook 받을 때 packs-lab을 자동 rebuild·재시작·헬스체크 안 하던
근본 원인 — deploy.sh의 BUILD_TARGETS / CONTAINER_NAMES / HEALTH_ENDPOINTS
3개 화이트리스트에서 packs-lab 누락. SERVICES 화이트리스트(deploy-nas.sh)는
rsync 동기화용이라 별도이며 거기엔 이전에 추가했지만 빌드 트리거는 deploy.sh가
담당.

Fix:
- BUILD_TARGETS, CONTAINER_NAMES, HEALTH_ENDPOINTS에 packs-lab 추가
- media/packs 디렉토리 자동 mkdir + chown (admin이 수동 생성하던 절차 제거)
- DATA_DIRS는 path 다르니(data/X 아닌 media/packs) 제외

이번 push 자체는 옛 deploy.sh로 처리되지만 새 deploy.sh가 RUNTIME에 sync된 후
다음 push부터 packs-lab이 자동 빌드·헬스체크된다.
2026-05-11 04:07:02 +09:00
b792cdb8d5 docs(packs-lab): 운영 검증 결과 반영 — DSM API path 형식 + DSM_VERIFY_SSL 명시
5/11 운영 첫 호출 검증 중 발견된 사항을 spec/CLAUDE.md에 반영:

1. DSM API path 형식 차이: Synology DSM은 일반 사용자 권한일 때
   /<shared_folder>/... 형식만 인식, /volume1/... 거부 (error 408).
   PACK_HOST_DIR 운영 예시값 /docker/webpage/media/packs로 변경.

2. DSM_VERIFY_SSL env 명시: LAN IP + self-signed cert 환경에서 SSL 검증
   끄기 위한 환경변수. .env.example 7+3 path로 갱신.

3. DSM 사용자 권한 가이드: File Station + Sharing 둘 다 ON 필요.

4. NAS 디렉토리 준비 명령에서 호스트 OS path와 DSM API path 차이 명시.

운영 검증: HTTP 200 + DSM 공유 URL (gofile.me/...) 발급 확인.
2026-05-11 04:02:36 +09:00