refactor: backend→lotto 서비스 리네이밍 + lotto.db 레거시 테이블 스키마 제거
- backend/ → lotto/ 디렉토리 이동 - docker-compose: lotto-backend→lotto, lotto-frontend→frontend - deploy scripts, nginx, agent-office config 네이밍 일괄 반영 - lotto/app/db.py에서 todos·blog_posts CREATE TABLE 제거 (personal로 이관 완료) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
12
CLAUDE.md
12
CLAUDE.md
@@ -31,7 +31,7 @@ Synology NAS 기반의 개인 웹 플랫폼 백엔드 모노레포.
|
|||||||
```
|
```
|
||||||
/volume1
|
/volume1
|
||||||
├── docker/webpage/ # 운영 런타임 (Docker Compose 실행 위치)
|
├── docker/webpage/ # 운영 런타임 (Docker Compose 실행 위치)
|
||||||
│ ├── backend/ # lotto-backend 소스 (rsync 동기화)
|
│ ├── lotto/ # lotto 소스 (rsync 동기화)
|
||||||
│ ├── stock-lab/ # stock-lab 소스 (rsync 동기화)
|
│ ├── stock-lab/ # stock-lab 소스 (rsync 동기화)
|
||||||
│ ├── travel-proxy/ # travel-proxy 소스 (rsync 동기화)
|
│ ├── travel-proxy/ # travel-proxy 소스 (rsync 동기화)
|
||||||
│ ├── deployer/ # deployer 소스 (rsync 동기화)
|
│ ├── deployer/ # deployer 소스 (rsync 동기화)
|
||||||
@@ -53,7 +53,7 @@ Synology NAS 기반의 개인 웹 플랫폼 백엔드 모노레포.
|
|||||||
|
|
||||||
| 컨테이너 | 포트 | 역할 |
|
| 컨테이너 | 포트 | 역할 |
|
||||||
|---------|------|------|
|
|---------|------|------|
|
||||||
| `lotto-backend` | 18000 | 로또 데이터 수집·분석·추천 API |
|
| `lotto` | 18000 | 로또 데이터 수집·분석·추천 API |
|
||||||
| `stock-lab` | 18500 | 주식 뉴스·AI 분석·KIS API 연동 |
|
| `stock-lab` | 18500 | 주식 뉴스·AI 분석·KIS API 연동 |
|
||||||
| `music-lab` | 18600 | AI 음악 생성·라이브러리 관리 API |
|
| `music-lab` | 18600 | AI 음악 생성·라이브러리 관리 API |
|
||||||
| `blog-lab` | 18700 | 블로그 마케팅 수익화 API |
|
| `blog-lab` | 18700 | 블로그 마케팅 수익화 API |
|
||||||
@@ -61,7 +61,7 @@ Synology NAS 기반의 개인 웹 플랫폼 백엔드 모노레포.
|
|||||||
| `agent-office` | 18900 | AI 에이전트 오피스 (실시간 WebSocket + 텔레그램 연동) |
|
| `agent-office` | 18900 | AI 에이전트 오피스 (실시간 WebSocket + 텔레그램 연동) |
|
||||||
| `personal` | 18850 | 개인 서비스 (포트폴리오·블로그·투두 통합) |
|
| `personal` | 18850 | 개인 서비스 (포트폴리오·블로그·투두 통합) |
|
||||||
| `travel-proxy` | 19000 | 여행 사진 API + 썸네일 생성 |
|
| `travel-proxy` | 19000 | 여행 사진 API + 썸네일 생성 |
|
||||||
| `lotto-frontend` (nginx) | 8080 | 정적 SPA 서빙 + API 리버스 프록시 |
|
| `frontend` (nginx) | 8080 | 정적 SPA 서빙 + API 리버스 프록시 |
|
||||||
| `webpage-deployer` | 19010 | Gitea Webhook 수신 → 자동 배포 |
|
| `webpage-deployer` | 19010 | Gitea Webhook 수신 → 자동 배포 |
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -70,7 +70,7 @@ Synology NAS 기반의 개인 웹 플랫폼 백엔드 모노레포.
|
|||||||
|
|
||||||
| 경로 | 프록시 대상 | 비고 |
|
| 경로 | 프록시 대상 | 비고 |
|
||||||
|------|------------|------|
|
|------|------------|------|
|
||||||
| `/api/` | `lotto-backend:8000` | lotto API (기본) |
|
| `/api/` | `lotto:8000` | lotto API (기본) |
|
||||||
| `/api/travel/` | `travel-proxy:8000` | travel API |
|
| `/api/travel/` | `travel-proxy:8000` | travel API |
|
||||||
| `/api/stock/` | `stock-lab:8000` | stock API |
|
| `/api/stock/` | `stock-lab:8000` | stock API |
|
||||||
| `/api/trade/` | `stock-lab:8000` | KIS 실계좌 API |
|
| `/api/trade/` | `stock-lab:8000` | KIS 실계좌 API |
|
||||||
@@ -139,7 +139,7 @@ docker compose up -d
|
|||||||
|
|
||||||
## 9. 서비스별 핵심 정보
|
## 9. 서비스별 핵심 정보
|
||||||
|
|
||||||
### lotto-lab (backend/)
|
### lotto-lab (lotto/)
|
||||||
- DB: `/app/data/lotto.db`
|
- DB: `/app/data/lotto.db`
|
||||||
- 데이터 소스: `smok95.github.io/lotto/results/`
|
- 데이터 소스: `smok95.github.io/lotto/results/`
|
||||||
- 파일 구조: `main.py`, `db.py`, `recommender.py`, `collector.py`, `checker.py`, `generator.py`, `analyzer.py`, `utils.py`, `purchase_manager.py`, `strategy_evolver.py`
|
- 파일 구조: `main.py`, `db.py`, `recommender.py`, `collector.py`, `checker.py`, `generator.py`, `analyzer.py`, `utils.py`, `purchase_manager.py`, `strategy_evolver.py`
|
||||||
@@ -454,7 +454,7 @@ docker compose up -d
|
|||||||
- `CONVERSATION_MODEL`: 대화 모델 (기본 `claude-haiku-4-5-20251001`)
|
- `CONVERSATION_MODEL`: 대화 모델 (기본 `claude-haiku-4-5-20251001`)
|
||||||
- `CONVERSATION_HISTORY_LIMIT`: 이력 주입 수 (기본 20)
|
- `CONVERSATION_HISTORY_LIMIT`: 이력 주입 수 (기본 20)
|
||||||
- `CONVERSATION_RATE_PER_MIN`: 채팅당 분당 최대 메시지 (기본 6)
|
- `CONVERSATION_RATE_PER_MIN`: 채팅당 분당 최대 메시지 (기본 6)
|
||||||
- `LOTTO_BACKEND_URL`: 기본 `http://lotto-backend:8000`
|
- `LOTTO_BACKEND_URL`: 기본 `http://lotto:8000`
|
||||||
- `LOTTO_CURATOR_MODEL`: 기본 `claude-sonnet-4-5`
|
- `LOTTO_CURATOR_MODEL`: 기본 `claude-sonnet-4-5`
|
||||||
|
|
||||||
**텔레그램 자연어 대화 (옵션 B)**
|
**텔레그램 자연어 대화 (옵션 B)**
|
||||||
|
|||||||
@@ -32,5 +32,5 @@ BREAK_DURATION_MIN = int(os.getenv("BREAK_DURATION_MIN", "60")) # 1 min
|
|||||||
BREAK_DURATION_MAX = int(os.getenv("BREAK_DURATION_MAX", "180")) # 3 min
|
BREAK_DURATION_MAX = int(os.getenv("BREAK_DURATION_MAX", "180")) # 3 min
|
||||||
|
|
||||||
# Lotto Curator
|
# Lotto Curator
|
||||||
LOTTO_BACKEND_URL = os.getenv("LOTTO_BACKEND_URL", "http://lotto-backend:8000")
|
LOTTO_BACKEND_URL = os.getenv("LOTTO_BACKEND_URL", "http://lotto:8000")
|
||||||
LOTTO_CURATOR_MODEL = os.getenv("LOTTO_CURATOR_MODEL", "claude-sonnet-4-5")
|
LOTTO_CURATOR_MODEL = os.getenv("LOTTO_CURATOR_MODEL", "claude-sonnet-4-5")
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
name: webpage
|
name: webpage
|
||||||
|
|
||||||
services:
|
services:
|
||||||
backend:
|
lotto:
|
||||||
build:
|
build:
|
||||||
context: ./backend
|
context: ./lotto
|
||||||
args:
|
args:
|
||||||
APP_VERSION: ${APP_VERSION:-dev}
|
APP_VERSION: ${APP_VERSION:-dev}
|
||||||
container_name: lotto-backend
|
container_name: lotto
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
ports:
|
ports:
|
||||||
- "18000:8000"
|
- "18000:8000"
|
||||||
@@ -131,7 +131,7 @@ services:
|
|||||||
- TELEGRAM_WEBHOOK_URL=${TELEGRAM_WEBHOOK_URL:-}
|
- TELEGRAM_WEBHOOK_URL=${TELEGRAM_WEBHOOK_URL:-}
|
||||||
- TELEGRAM_WIFE_CHAT_ID=${TELEGRAM_WIFE_CHAT_ID:-}
|
- TELEGRAM_WIFE_CHAT_ID=${TELEGRAM_WIFE_CHAT_ID:-}
|
||||||
- ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY:-}
|
- ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY:-}
|
||||||
- LOTTO_BACKEND_URL=${LOTTO_BACKEND_URL:-http://lotto-backend:8000}
|
- LOTTO_BACKEND_URL=${LOTTO_BACKEND_URL:-http://lotto:8000}
|
||||||
- LOTTO_CURATOR_MODEL=${LOTTO_CURATOR_MODEL:-claude-sonnet-4-5}
|
- LOTTO_CURATOR_MODEL=${LOTTO_CURATOR_MODEL:-claude-sonnet-4-5}
|
||||||
- CONVERSATION_MODEL=${CONVERSATION_MODEL:-claude-haiku-4-5-20251001}
|
- CONVERSATION_MODEL=${CONVERSATION_MODEL:-claude-haiku-4-5-20251001}
|
||||||
- CONVERSATION_HISTORY_LIMIT=${CONVERSATION_HISTORY_LIMIT:-20}
|
- CONVERSATION_HISTORY_LIMIT=${CONVERSATION_HISTORY_LIMIT:-20}
|
||||||
@@ -193,7 +193,7 @@ services:
|
|||||||
|
|
||||||
frontend:
|
frontend:
|
||||||
image: nginx:alpine
|
image: nginx:alpine
|
||||||
container_name: lotto-frontend
|
container_name: frontend
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
depends_on:
|
depends_on:
|
||||||
- music-lab
|
- music-lab
|
||||||
|
|||||||
@@ -143,44 +143,6 @@ def init_db() -> None:
|
|||||||
"ON best_picks(is_active, score_total DESC);"
|
"ON best_picks(is_active, score_total DESC);"
|
||||||
)
|
)
|
||||||
|
|
||||||
# ── todos 테이블 ───────────────────────────────────────────────────────
|
|
||||||
conn.execute(
|
|
||||||
"""
|
|
||||||
CREATE TABLE IF NOT EXISTS todos (
|
|
||||||
id TEXT PRIMARY KEY
|
|
||||||
DEFAULT (lower(hex(randomblob(4))) || '-' || lower(hex(randomblob(2)))),
|
|
||||||
title TEXT NOT NULL,
|
|
||||||
description TEXT,
|
|
||||||
status TEXT NOT NULL DEFAULT 'todo'
|
|
||||||
CHECK(status IN ('todo','in_progress','done')),
|
|
||||||
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now')),
|
|
||||||
updated_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now'))
|
|
||||||
);
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
conn.execute(
|
|
||||||
"CREATE INDEX IF NOT EXISTS idx_todos_created ON todos(created_at DESC);"
|
|
||||||
)
|
|
||||||
|
|
||||||
# ── blog_posts 테이블 ──────────────────────────────────────────────────
|
|
||||||
conn.execute(
|
|
||||||
"""
|
|
||||||
CREATE TABLE IF NOT EXISTS blog_posts (
|
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
||||||
title TEXT NOT NULL,
|
|
||||||
body TEXT NOT NULL DEFAULT '',
|
|
||||||
excerpt TEXT NOT NULL DEFAULT '',
|
|
||||||
tags TEXT NOT NULL DEFAULT '[]',
|
|
||||||
date TEXT NOT NULL DEFAULT (date('now','localtime')),
|
|
||||||
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now')),
|
|
||||||
updated_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now'))
|
|
||||||
);
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
conn.execute(
|
|
||||||
"CREATE INDEX IF NOT EXISTS idx_blog_date ON blog_posts(date DESC);"
|
|
||||||
)
|
|
||||||
|
|
||||||
# ── purchase_history 테이블 ────────────────────────────────────────────
|
# ── purchase_history 테이블 ────────────────────────────────────────────
|
||||||
conn.execute(
|
conn.execute(
|
||||||
"""
|
"""
|
||||||
@@ -204,7 +204,7 @@ server {
|
|||||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
proxy_set_header X-Forwarded-Proto $scheme;
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
|
||||||
proxy_pass http://backend:8000;
|
proxy_pass http://lotto:8000;
|
||||||
}
|
}
|
||||||
|
|
||||||
# Fear & Greed Index (CNN 공개 API)
|
# Fear & Greed Index (CNN 공개 API)
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
# ── 서비스 목록 (한 곳에서만 관리) ──
|
# ── 서비스 목록 (한 곳에서만 관리) ──
|
||||||
SERVICES="backend travel-proxy deployer stock-lab music-lab blog-lab realestate-lab agent-office personal nginx scripts"
|
SERVICES="lotto travel-proxy deployer stock-lab music-lab blog-lab realestate-lab agent-office personal nginx scripts"
|
||||||
|
|
||||||
# 1. 자동 감지: Docker 컨테이너 내부인가?
|
# 1. 자동 감지: Docker 컨테이너 내부인가?
|
||||||
if [ -d "/repo" ] && [ -d "/runtime" ]; then
|
if [ -d "/repo" ] && [ -d "/runtime" ]; then
|
||||||
|
|||||||
@@ -7,11 +7,11 @@ flock -n 200 || { echo "Deploy already running, skipping"; exit 0; }
|
|||||||
|
|
||||||
# ── 서비스 목록 (한 곳에서만 관리) ──
|
# ── 서비스 목록 (한 곳에서만 관리) ──
|
||||||
# docker compose 서비스명 (deployer 제외 — 자기 자신을 재빌드하면 스크립트 중단)
|
# docker compose 서비스명 (deployer 제외 — 자기 자신을 재빌드하면 스크립트 중단)
|
||||||
BUILD_TARGETS="backend travel-proxy stock-lab music-lab blog-lab realestate-lab agent-office personal frontend"
|
BUILD_TARGETS="lotto travel-proxy stock-lab music-lab blog-lab realestate-lab agent-office personal frontend"
|
||||||
# 컨테이너 이름 (고아 정리용)
|
# 컨테이너 이름 (고아 정리용)
|
||||||
CONTAINER_NAMES="lotto-backend stock-lab music-lab blog-lab realestate-lab agent-office personal travel-proxy lotto-frontend"
|
CONTAINER_NAMES="lotto stock-lab music-lab blog-lab realestate-lab agent-office personal travel-proxy frontend"
|
||||||
# 헬스체크 대상
|
# 헬스체크 대상
|
||||||
HEALTH_ENDPOINTS="backend stock-lab travel-proxy music-lab blog-lab realestate-lab agent-office personal"
|
HEALTH_ENDPOINTS="lotto stock-lab travel-proxy music-lab blog-lab realestate-lab agent-office personal"
|
||||||
# data 디렉토리
|
# data 디렉토리
|
||||||
DATA_DIRS="music stock blog realestate agent-office personal"
|
DATA_DIRS="music stock blog realestate agent-office personal"
|
||||||
|
|
||||||
@@ -89,7 +89,7 @@ done
|
|||||||
|
|
||||||
# 3) 재빌드 및 시작
|
# 3) 재빌드 및 시작
|
||||||
docker compose up -d --build $BUILD_TARGETS
|
docker compose up -d --build $BUILD_TARGETS
|
||||||
docker exec lotto-frontend nginx -s reload 2>/dev/null || true
|
docker exec frontend nginx -s reload 2>/dev/null || true
|
||||||
|
|
||||||
# ── 배포 후 헬스체크 ──
|
# ── 배포 후 헬스체크 ──
|
||||||
echo "Waiting for services to start..."
|
echo "Waiting for services to start..."
|
||||||
|
|||||||
Reference in New Issue
Block a user