Files
web-page/CLAUDE.md
gahusb d1ecf13400 stock AI 어드바이저 추가 및 UX 개선
- Gemini Pro 기반 AI 어드바이저 탭 추가 (TAB_ADVISOR)
  - 보유 종목 현재가 + 뉴스 → 종목별 매도/매수/분할매도 지침
  - 5분 캐시, 강제 새로고침 버튼
  - 경량 마크다운 렌더러 (AdvisorMarkdown)
- 실현손익 수수료 → 수수료 & 세금으로 레이블 변경
- 총 자산 추이 그래프: 0 데이터 제외 (장 미개장일 필터)
- Todo 완료 패널 하단 이동 + 날짜 필터 추가

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-25 03:54:50 +09:00

11 KiB

web-ui — CLAUDE.md

개인 웹페이지 프론트엔드 프로젝트에 대한 컨텍스트 문서입니다.

프로젝트 개요

  • 스택: React 18 + Vite + react-router-dom v6
  • 목적: 개인 블로그, 로또 실험, 주식 뉴스/트레이딩, 여행 기록을 한 곳에 모은 개인 웹 UI
  • 배포 대상: Synology NAS (gahusb.synology.me) Docker 컨테이너 내 nginx

페이지 구조

경로 컴포넌트 설명
/ Home 메인 허브
/blog Blog 마크다운 기반 블로그
/lotto Lotto 로또 추천/통계
/stock Stock 주식 뉴스/지수
/stock/trade StockTrade 주식 트레이딩
/realestate Subscription 청약 자격·일정 관리
/realestate/property RealEstate 관심 단지 정보
/travel Travel 여행 사진 갤러리 (Dark Room 테마)
/lab EffectLab UI/UX 실험 허브
/lab/sword-stream SwordStream Three.js 파티클 인터랙션
/lab/day-calc DayCalc 날짜 계산기
/lab/music MusicStudio AI 음악 생성 스튜디오 (Sonic Forge)
/todo Todo 태스크 보드

라우트 정의: src/routes.jsx / 라우터 설정: src/Router.jsx


API 설정

핵심 원칙

  • 항상 상대 경로 사용: 프로덕션에서 프론트와 백엔드는 nginx 리버스 프록시로 동일 도메인에서 서비스됨
  • 절대 URL 사용 금지: https:// 절대 URL을 fetch에 직접 사용하면 Mixed Content 오류 발생
  • VITE_API_BASE 환경변수는 사용하지 않음

API 헬퍼 (src/api.js)

// 모든 API 호출은 이 헬퍼를 통해 사용
import { apiGet, apiPost, apiPut, apiDelete } from './api';

// 예시
apiGet('/api/lotto/latest')
apiPost('/api/portfolio', { ... })

제공 함수: apiGet, apiPost, apiPut, apiDelete

개발 서버 프록시 (vite.config.js)

proxy: {
  '/api':   { target: 'https://gahusb.synology.me', changeOrigin: true, secure: true },
  '/media': { target: 'https://gahusb.synology.me', changeOrigin: true, secure: true },
  // /ext/* — Yahoo Finance, CNN Fear&Greed 등 외부 API 프록시
}
  • /api/* → NAS 백엔드
  • /media/* → NAS 미디어 파일 (여행 사진 /media/travel/, 음악 /media/music/)
  • 개발 서버 포트: 3007

API 엔드포인트 목록

분류 메서드 경로
로또 기본 GET /api/lotto/latest, /api/lotto/stats, /api/lotto/recommend
로또 기본 GET /api/lotto/best, /api/lotto/analysis
로또 기본 POST /api/admin/simulate
로또 고도화 GET /api/lotto/stats/performance
로또 고도화 GET /api/lotto/report/latest, /api/lotto/report/:drw_no, /api/lotto/report/history?limit=N
로또 고도화 GET /api/lotto/analysis/personal
로또 구매 GET /api/lotto/purchase?draw_no=N&days=N, /api/lotto/purchase/stats
로또 구매 POST/PUT/DELETE /api/lotto/purchase, /api/lotto/purchase/:id
히스토리 GET /api/history
히스토리 DELETE /api/history/:id
주식 GET /api/stock/news, /api/stock/indices
트레이딩 GET /api/trade/balance
트레이딩 POST /api/trade/order
포트폴리오 GET/POST /api/portfolio
포트폴리오 PUT/DELETE /api/portfolio/:id
예수금 PUT /api/portfolio/cash — body: { broker, cash }
예수금 DELETE /api/portfolio/cash/:broker
자산 스냅샷 POST /api/portfolio/snapshot — body: { total_assets } 또는 body 없이 서버 계산
자산 스냅샷 GET /api/portfolio/snapshot/history?days=N — response: { history: [{date, total_assets}] }
실현손익 GET /api/portfolio/sell-history?broker=X&days=N — response: { records: [...] }
실현손익 POST/PUT /api/portfolio/sell-history, /api/portfolio/sell-history/:id
실현손익 DELETE /api/portfolio/sell-history/:id
TODO GET/POST /api/todos
TODO PUT/DELETE /api/todos/:id, /api/todos/done
블로그 GET/POST /api/blog/posts
블로그 PUT/DELETE /api/blog/posts/:id
AI 음악 POST /api/music/generate — body: { title, genre, moods, instruments, duration_sec, bpm, key, scale, prompt }{ task_id }
AI 음악 GET /api/music/status/:task_id{ status, progress, message, audio_url?, error?, track? }
AI 음악 라이브러리 GET/POST /api/music/library — response: { tracks: [...] }
AI 음악 라이브러리 DELETE /api/music/library/:id

NAS 배포 설정

배포 경로

환경 경로
Windows Z:\docker\webpage\frontend\ (NAS 네트워크 드라이브 마운트)
macOS (SMB) /Volumes/gahusb.synology.me/docker/webpage/frontend/
macOS (SSH) /volume1/docker/webpage/frontend/

배포 명령어

# 빌드 + 배포 (권장)
npm run release:nas

# 빌드만
npm run build

# 배포만 (dist 폴더가 이미 있을 때)
npm run deploy:nas

Windows 배포

NAS가 Z: 드라이브로 마운트되어 있어야 함. robocopy/MIR 동기화하며 로그는 robocopy.log에 저장됨.

macOS 배포 — SSH 방식 (권장)

# 환경변수 설정 후 배포
NAS_SSH_TARGET=user@gahusb.synology.me NAS_SSH_PORT=22 npm run release:nas

NAS_SSH_TARGET이 설정되면 rsync로 SSH 배포. SMB 마운트 방식보다 안정적.

macOS 배포 — SMB 마운트 방식

SMB 마운트 후 ditto로 복사. NAS_CLEAN=1 설정 시 배포 전 기존 파일 전체 삭제.

NAS_CLEAN=1 npm run release:nas

배포 스크립트 파일

scripts/deploy-nas.cjs — Node.js CJS 모듈, 플랫폼 자동 감지


개발 환경

npm install
npm run dev        # localhost:3007 에서 개발 서버 실행
npm run build      # dist/ 로 프로덕션 빌드
npm run lint       # ESLint 검사
npm run preview    # 빌드 결과물 미리보기

주요 파일 위치

파일 역할
src/api.js API 헬퍼 함수 모음
src/routes.jsx 라우트 및 네비게이션 링크 정의
src/Router.jsx BrowserRouter 설정
vite.config.js 개발 서버 및 프록시 설정
scripts/deploy-nas.cjs NAS 배포 스크립트
src/content/blog/ 블로그 마크다운 파일
public/ 정적 파일 (로고, API 스펙 등)

Sonic Forge — AI 음악 생성 스튜디오 (/lab/music)

파일 구조

파일 역할
src/pages/music/MusicStudio.jsx 메인 컴포넌트
src/pages/music/MusicStudio.css 스타일 (Bebas Neue · Syne · Courier Prime)

주요 컴포넌트

  • SonicRadar — 헤더 우측 비주얼. SVG 링·크로스헤어·스윕 라인 + 48개 CSS 방사형 바. isGenerating / accentColor prop으로 상태 전환
  • WaveformCanvas — 스테이지 우측 캔버스 오실로스코프 (헤더와 별도)
  • AudioPlayer — 실제 <audio> 엘리먼트 기반. audio_url 없으면 타이머 폴백
  • Library — 저장된 트랙 카드 그리드 + 삭제/재생
  • GenerationProgress — 진행률 바 + 단계 메시지

생성 플로우

handleGenerate()
  → POST /api/music/generate (payload에 title 포함)
  → task_id 반환 시: setInterval 3초 폴링 (getMusicStatus)
      succeeded → setTrack(status.track 우선, 없으면 로컬 조립) + loadLibrary()
      failed    → genError 표시
  → API 실패 시: 6단계 시뮬레이션 폴백 (오프라인 모드)

백엔드 연동 규칙

  • audio_url은 반드시 상대경로 /media/music/{task_id}.mp3 형식 (절대 URL 금지)
  • status 응답 shape: { status, progress, message, audio_url?, error?, track? }
  • track 객체: { id, title, genre, moods[], instruments[], duration_sec, bpm, key, scale, audio_url, created_at }
  • 백엔드가 succeeded 시 library 자동 등록 → 프론트는 "Save" 버튼 없음, loadLibrary() 자동 호출
  • generate payload에 title 포함 → 백엔드에서 payload title 우선 사용 권장

CSS 설계 특이사항

  • 설명 토글: .ms-desc-wrap + grid-template-rows: 0fr → 1fr 트랜지션으로 높이 애니메이션
  • 완전히 닫힐 때 노출 방지: .ms-desc-wrap { overflow: hidden } + .ms-desc-wrap > * { min-height: 0 }
  • 장르 선택 시 --ms-accent / --radar-accent / --g-color CSS 변수로 전체 컬러 테마 동기화

Lotto 고도화 (/lotto)

src/pages/lotto/Functions.jsx에 4개 신규 섹션 추가:

섹션 API 설명
PerformanceBanner /api/lotto/stats/performance 수익률·당첨 통계 상단 띠
ReportPanel /api/lotto/report/* 주간 리포트 + 전략 카드 + ConfidenceRing
PersonalAnalysisPanel /api/lotto/analysis/personal 개인 번호 성향 분석
PurchasePanel /api/lotto/purchase/* 구매 내역 CRUD

Travel 갤러리 (/travel)

  • 테마: "Dark Room" (배경 #0f0c09, 서체 Cormorant Garamond + Space Mono)
  • 사진 URL: /media/travel/... 형식 → vite.config.js /media 프록시로 처리
  • 프로덕션 nginx에도 location /media/ 프록시 블록 필요

Windows AI 서버 (C:\Users\jaeoh\Desktop\workspace\music_ai)

NAS의 music-lab 컨테이너 대신 Windows PC(RTX 5070 Ti)에서 MusicGen을 로컬 추론하는 별도 서버.

구성 파일

파일 역할
server.py FastAPI 서버 (generate/status/audio 엔드포인트)
model.py MusicGen 래퍼 + 프롬프트 빌더 (genre/mood/instruments→텍스트)
.env MODEL_NAME, OUTPUT_DIR, SERVER_PORT 등
setup.bat venv 생성 + PyTorch CUDA 12.4 + audiocraft 설치
start.bat 서버 시작

엔드포인트

메서드 경로 설명
GET /health 서버·GPU 상태 확인
POST /generate 음악 생성 → task_id 즉시 반환
GET /status/{task_id} 생성 진행 폴링
GET /audio/{task_id}.mp3 완성 오디오 파일

모델

  • 기본: facebook/musicgen-stereo-large (16GB VRAM, 스테레오 고품질)
  • RTX 5070 Ti(16GB)로 실행 가능

NAS 연동 흐름

web-ui → POST /api/music/generate (NAS music-lab)
  → music-lab이 Windows PC :8765/generate 호출
  → Windows PC가 MusicGen 추론 → WAV → MP3 변환
  → music-lab이 /status 폴링 → audio_url 다운로드
  → /media/music/{task_id}.mp3 저장 → DB 등록
  → 프론트 폴링 성공 → Library 자동 갱신

Windows 방화벽에서 포트 8765 인바운드 허용 필요.