web-backend
Synology NAS 기반 개인 웹 플랫폼 백엔드 모노레포.
로또 분석, 주식 포트폴리오, 여행 앨범, 블로그, 투두리스트를 하나의 서비스로 운영한다.
서비스 구성
| 컨테이너 |
포트 |
역할 |
lotto-backend |
18000 |
로또·블로그·투두 API |
stock-lab |
18500 |
주식 뉴스·포트폴리오·자산 추적 |
travel-proxy |
19000 |
여행 사진 API + 썸네일 생성 |
lotto-frontend |
8080 |
SPA 서빙 + 리버스 프록시 |
webpage-deployer |
19010 |
Gitea Webhook → 자동 배포 |
디렉토리 구조
빠른 시작 (로컬 개발)
API 목록
lotto-backend (/api/)
로또
| 메서드 |
경로 |
설명 |
| GET |
/api/lotto/latest |
최신 당첨번호 |
| GET |
/api/lotto/{drw_no} |
특정 회차 |
| GET |
/api/lotto/stats |
번호 빈도 통계 |
| GET |
/api/lotto/analysis |
5가지 통계 분석 리포트 |
| GET |
/api/lotto/best |
시뮬레이션 최적 번호 (기본 20쌍) |
| GET |
/api/lotto/simulation |
시뮬레이션 상세 결과 |
| GET |
/api/lotto/recommend |
통계 기반 추천 |
| GET |
/api/lotto/recommend/heatmap |
히트맵 기반 추천 |
| GET |
/api/lotto/recommend/batch |
배치 추천 |
| POST |
/api/admin/simulate |
시뮬레이션 수동 실행 |
| POST |
/api/admin/sync_latest |
당첨번호 수동 동기화 |
추천 이력
| 메서드 |
경로 |
설명 |
| GET |
/api/history |
목록 (limit, offset, favorite, tag, sort) |
| PATCH |
/api/history/{id} |
즐겨찾기·메모·태그 수정 |
| DELETE |
/api/history/{id} |
삭제 |
투두리스트
| 메서드 |
경로 |
설명 |
| GET |
/api/todos |
전체 목록 |
| POST |
/api/todos |
생성 (status: todo|in_progress|done) |
| PUT |
/api/todos/{id} |
수정 |
| DELETE |
/api/todos/done |
완료 항목 일괄 삭제 |
| DELETE |
/api/todos/{id} |
개별 삭제 |
⚠️ /done 라우트는 반드시 /{id} 보다 먼저 등록해야 함
블로그
| 메서드 |
경로 |
설명 |
| GET |
/api/blog/posts |
글 목록 ({"posts": [...]}, date DESC) |
| POST |
/api/blog/posts |
글 생성 (date 미입력 시 오늘 날짜) |
| PUT |
/api/blog/posts/{id} |
글 수정 |
| DELETE |
/api/blog/posts/{id} |
글 삭제 |
블로그 포스트 구조: { id, title, tags[], body, date, excerpt, created_at, updated_at }
stock-lab (/api/stock/, /api/trade/, /api/portfolio)
뉴스 & 지표
| 메서드 |
경로 |
설명 |
| GET |
/api/stock/news |
뉴스 목록 (limit, category) |
| GET |
/api/stock/indices |
주요 지표 (KOSPI 등) |
| POST |
/api/stock/scrap |
뉴스 수동 스크랩 |
실계좌 (Windows AI 서버 프록시)
| 메서드 |
경로 |
설명 |
| GET |
/api/trade/balance |
실계좌 잔고 조회 |
| POST |
/api/trade/order |
주문 (BUY|SELL, price=0이면 시장가) |
포트폴리오
| 메서드 |
경로 |
설명 |
| GET |
/api/portfolio |
전체 조회 (현재가·손익·예수금 포함) |
| POST |
/api/portfolio |
종목 추가 |
| PUT |
/api/portfolio/{id} |
종목 수정 |
| DELETE |
/api/portfolio/{id} |
종목 삭제 |
| GET |
/api/portfolio/cash |
예수금 전체 조회 |
| PUT |
/api/portfolio/cash |
예수금 upsert |
| DELETE |
/api/portfolio/cash/{broker} |
예수금 삭제 |
| POST |
/api/portfolio/snapshot |
총 자산 스냅샷 수동 저장 |
| GET |
/api/portfolio/snapshot/history |
자산 변화 이력 (days=0: 전체) |
travel-proxy (/api/travel/)
| 메서드 |
경로 |
설명 |
| GET |
/api/travel/regions |
지역 GeoJSON |
| GET |
/api/travel/photos |
사진 목록 (region, page, size) |
| POST |
/api/travel/reload |
캐시 초기화 |
- 썸네일:
/media/travel/.thumb/{album}/{file} (nginx 직접 서빙, 30일 캐시)
- 원본:
/media/travel/{album}/{file} (nginx 직접 서빙, 7일 캐시)
핵심 로직
몬테카를로 시뮬레이션 (lotto-backend)
5가지 채점 기법:
| 기법 |
가중치 |
내용 |
| 빈도 Z-score |
25% |
번호 출현 빈도의 표준편차 |
| 조합 지문 |
30% |
합계 정규분포 + 홀짝 비율 + 구간분포 |
| 갭 분석 |
20% |
마지막 출현 이후 경과 회차 |
| 공동 출현 |
15% |
번호 쌍 동시 출현 빈도 |
| 다양성 |
10% |
연속번호·범위·구간 커버리지 |
스케줄: 매일 0, 4, 8, 12, 16, 20시 (하루 6회, 각 5분)
총 자산 스냅샷 (stock-lab)
현재가 조회 (stock-lab)
- 네이버 모바일 API 우선 (
m.stock.naver.com/api/stock/{ticker}/basic)
- 실패 시 네이버 금융 HTML 파싱 폴백
- 3분 TTL 메모리 캐시
여행 사진 썸네일 (travel-proxy)
- 480×480 리사이징 (Pillow), 확장자 유지 (JPEG/PNG/WEBP)
- 온디맨드 생성 후
/data/thumbs/ 영구 캐시
- 원자성 보장: tmp 파일 작성 후 rename
자동 배포
프론트엔드는 자동 배포 안 됨 — 로컬 빌드 후 NAS에 수동 업로드
데이터베이스
lotto.db (/app/data/lotto.db)
| 테이블 |
설명 |
draws |
로또 당첨번호 |
recommendations |
추천 이력 (즐겨찾기·태그·채점 포함) |
simulation_runs |
시뮬레이션 실행 기록 |
simulation_candidates |
시뮬레이션 후보 (점수 5종) |
best_picks |
현재 활성 최적 번호 20개 (is_active 플래그) |
todos |
투두리스트 (UUID PK) |
blog_posts |
블로그 글 (tags: JSON 배열) |
stock.db (/app/data/stock.db)
| 테이블 |
설명 |
articles |
뉴스 기사 (hash UNIQUE, category: domestic|overseas) |
portfolio |
보유 종목 (broker, ticker, quantity, avg_price) |
broker_cash |
증권사별 예수금 (broker UNIQUE) |
asset_snapshots |
일별 총 자산 스냅샷 (date UNIQUE) |
환경변수
인프라
| 항목 |
값 |
| 장비 |
Synology NAS (Intel Celeron J4025, 18GB RAM) |
| Docker |
Synology Container Manager |
| Git 서버 |
Gitea (NAS 내부 self-hosted) |
| AI 서버 |
Windows PC (192.168.45.59:8000) — RTX 3070 Ti + Ollama |
| Python |
3.12 (slim / alpine 기반 이미지) |
| DB |
SQLite (볼륨 마운트로 영속 저장) |
주의사항
.env 파일 — 절대 커밋 금지. .env.example만 레포에 포함
- Nginx trailing slash —
/api/portfolio는 두 location 블록으로 처리 (trailing slash 유무 모두 매칭)
- 라우트 순서 —
/api/todos/done은 /api/todos/{id} 보다 먼저 등록 필수
- 캐시 전략 —
index.html: no-store / assets/: 1년 immutable
- PUID/PGID — travel-proxy는 NAS 파일 권한을 위해 환경변수 주입 필수
- 공휴일 목록 —
stock-lab/app/holidays.json 매년 수동 갱신 필요 (KRX 기준)
- Windows AI 서버 — IP 192.168.45.59 (공유기 DHCP 고정 예약)