README.md 수정
This commit is contained in:
576
README.md
576
README.md
@@ -1,262 +1,334 @@
|
||||
# 🏠 Home NAS Web Platform (webpage)
|
||||
# web-backend
|
||||
|
||||
Synology NAS 기반의 개인 웹 플랫폼으로, 로또 분석/추천 서비스와 여행 사진 지도 서비스를 포함합니다.
|
||||
Frontend, Backend, Travel Proxy, Auto Deployer를 Docker Compose로 통합하여 운영합니다.
|
||||
Synology NAS 기반 개인 웹 플랫폼 백엔드 모노레포.
|
||||
로또 분석, 주식 포트폴리오, 여행 앨범, 블로그, 투두리스트를 하나의 서비스로 운영한다.
|
||||
|
||||
---
|
||||
|
||||
## 🖥️ NAS 환경 정보
|
||||
## 서비스 구성
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ lotto-frontend (Nginx:8080) │
|
||||
│ ├── 정적 SPA 서빙 (React + Vite) │
|
||||
│ └── API 리버스 프록시 │
|
||||
│ ├── /api/ → lotto-backend:8000 │
|
||||
│ ├── /api/stock/ → stock-lab:8000 │
|
||||
│ ├── /api/trade/ → stock-lab:8000 │
|
||||
│ ├── /api/portfolio → stock-lab:8000 │
|
||||
│ ├── /api/travel/ → travel-proxy:8000 │
|
||||
│ └── /webhook → deployer:9000 │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
| 컨테이너 | 포트 | 역할 |
|
||||
|---------|------|------|
|
||||
| `lotto-backend` | 18000 | 로또·블로그·투두 API |
|
||||
| `stock-lab` | 18500 | 주식 뉴스·포트폴리오·자산 추적 |
|
||||
| `travel-proxy` | 19000 | 여행 사진 API + 썸네일 생성 |
|
||||
| `lotto-frontend` | 8080 | SPA 서빙 + 리버스 프록시 |
|
||||
| `webpage-deployer` | 19010 | Gitea Webhook → 자동 배포 |
|
||||
|
||||
---
|
||||
|
||||
## 디렉토리 구조
|
||||
|
||||
```
|
||||
web-backend/
|
||||
├── backend/ # lotto-backend 서비스 (Python/FastAPI)
|
||||
│ ├── app/
|
||||
│ │ ├── main.py # 라우터, 스케줄러
|
||||
│ │ ├── db.py # SQLite CRUD (7개 테이블)
|
||||
│ │ ├── generator.py # 몬테카를로 시뮬레이션 엔진
|
||||
│ │ ├── analyzer.py # 5가지 통계 분석
|
||||
│ │ ├── checker.py # 당첨 결과 채점
|
||||
│ │ ├── collector.py # 로또 데이터 수집
|
||||
│ │ ├── recommender.py # 추천 알고리즘
|
||||
│ │ └── utils.py # 메트릭 계산
|
||||
│ └── Dockerfile
|
||||
│
|
||||
├── stock-lab/ # stock-lab 서비스 (Python/FastAPI)
|
||||
│ ├── app/
|
||||
│ │ ├── main.py # 라우터, 스케줄러
|
||||
│ │ ├── db.py # SQLite CRUD (4개 테이블)
|
||||
│ │ ├── scraper.py # 네이버 금융 뉴스 크롤링
|
||||
│ │ ├── price_fetcher.py # 현재가 조회 (3분 캐시)
|
||||
│ │ └── holidays.json # 한국 주식시장 휴장일
|
||||
│ └── Dockerfile
|
||||
│
|
||||
├── travel-proxy/ # travel-proxy 서비스 (Python/FastAPI)
|
||||
│ ├── app/
|
||||
│ │ └── main.py # 사진 API, 썸네일 생성 (Pillow)
|
||||
│ └── Dockerfile
|
||||
│
|
||||
├── deployer/ # Gitea Webhook 수신 → 자동 배포
|
||||
│ ├── app.py # HMAC SHA256 검증 + 배포 트리거
|
||||
│ └── Dockerfile
|
||||
│
|
||||
├── nginx/
|
||||
│ └── default.conf # 리버스 프록시 + SPA + 캐시
|
||||
│
|
||||
├── scripts/
|
||||
│ ├── deploy.sh # 운영 배포 (git pull → rsync → compose up)
|
||||
│ ├── deploy-nas.sh # rsync 전용 스크립트
|
||||
│ └── healthcheck.sh # 전체 서비스 헬스 체크
|
||||
│
|
||||
├── docker-compose.yml
|
||||
├── .env.example
|
||||
└── CLAUDE.md
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 빠른 시작 (로컬 개발)
|
||||
|
||||
```bash
|
||||
# 1. 환경변수 설정
|
||||
cp .env.example .env
|
||||
|
||||
# 2. 컨테이너 실행 (.env 기본값으로 즉시 실행 가능)
|
||||
docker compose up -d
|
||||
|
||||
# 3. 확인
|
||||
curl http://localhost:18000/health
|
||||
curl http://localhost:18500/health
|
||||
```
|
||||
|
||||
| 서비스 | 로컬 URL |
|
||||
|--------|----------|
|
||||
| Frontend + API | http://localhost:8080 |
|
||||
| lotto-backend | http://localhost:18000 |
|
||||
| stock-lab | http://localhost:18500 |
|
||||
| travel-proxy | http://localhost:19000 |
|
||||
|
||||
---
|
||||
|
||||
## 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)
|
||||
|
||||
```
|
||||
역대 당첨번호 분석 → 번호별 가중치 산출
|
||||
→ 가중 확률 샘플링으로 후보 20,000개 생성
|
||||
→ 5가지 기법으로 각 조합 점수화
|
||||
→ 상위 100개 DB 저장 → best_picks 20개 교체
|
||||
```
|
||||
|
||||
**5가지 채점 기법:**
|
||||
|
||||
| 기법 | 가중치 | 내용 |
|
||||
|------|--------|------|
|
||||
| 빈도 Z-score | 25% | 번호 출현 빈도의 표준편차 |
|
||||
| 조합 지문 | 30% | 합계 정규분포 + 홀짝 비율 + 구간분포 |
|
||||
| 갭 분석 | 20% | 마지막 출현 이후 경과 회차 |
|
||||
| 공동 출현 | 15% | 번호 쌍 동시 출현 빈도 |
|
||||
| 다양성 | 10% | 연속번호·범위·구간 커버리지 |
|
||||
|
||||
**스케줄:** 매일 0, 4, 8, 12, 16, 20시 (하루 6회, 각 5분)
|
||||
|
||||
### 총 자산 스냅샷 (stock-lab)
|
||||
|
||||
```
|
||||
평일 15:40 자동 실행 → holidays.json으로 공휴일 스킵
|
||||
→ 포트폴리오 현재가 조회 → total_eval
|
||||
→ 예수금 합계 → total_cash
|
||||
→ asset_snapshots upsert (date UNIQUE, 같은 날 중복 시 덮어씀)
|
||||
```
|
||||
|
||||
### 현재가 조회 (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
|
||||
|
||||
---
|
||||
|
||||
## 자동 배포
|
||||
|
||||
```
|
||||
git push → Gitea → X-Gitea-Signature (HMAC SHA256)
|
||||
→ deployer:9000/webhook (서명 검증, compare_digest 사용)
|
||||
→ BackgroundTask: scripts/deploy.sh (10분 타임아웃)
|
||||
1. git pull
|
||||
2. .releases/{timestamp}/ 백업
|
||||
3. rsync (repo → runtime)
|
||||
4. docker compose up -d --build
|
||||
5. chown PUID:PGID
|
||||
```
|
||||
|
||||
> 프론트엔드는 **자동 배포 안 됨** — 로컬 빌드 후 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) |
|
||||
|
||||
---
|
||||
|
||||
## 환경변수
|
||||
|
||||
```env
|
||||
# 경로 설정
|
||||
RUNTIME_PATH=.
|
||||
REPO_PATH=.
|
||||
FRONTEND_PATH=./frontend/dist
|
||||
PHOTO_PATH=./mock_data/photos
|
||||
|
||||
# NAS 파일 권한
|
||||
PUID=1000
|
||||
PGID=1000
|
||||
|
||||
# 외부 서비스
|
||||
WINDOWS_AI_SERVER_URL=http://192.168.45.59:8000
|
||||
WEBHOOK_SECRET=your_secret_here
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 인프라
|
||||
|
||||
| 항목 | 값 |
|
||||
| --------------- | ------------------------------------- |
|
||||
| **NAS** | Synology NAS |
|
||||
| **OS** | Synology DSM |
|
||||
| **CPU** | Intel Celeron J4025 (2 Core, 2.0GHz) |
|
||||
| **메모리** | 18 GB |
|
||||
| **Docker** | Synology Container Manager |
|
||||
| **Reverse Proxy** | Nginx (컨테이너) |
|
||||
| **Git Server** | Gitea (self-hosted) |
|
||||
|------|----|
|
||||
| 장비 | 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 (볼륨 마운트로 영속 저장) |
|
||||
|
||||
---
|
||||
|
||||
## 📁 디렉토리 구조
|
||||
## 주의사항
|
||||
|
||||
```
|
||||
/volume1
|
||||
├── docker/
|
||||
│ └── webpage/ # 🚀 운영 런타임 (Docker Compose 기준점)
|
||||
│ ├── backend/ # lotto-backend
|
||||
│ ├── stock-lab/ # 🟪 stock-lab (Stock + AI)
|
||||
│ ├── travel-proxy/ # travel API + thumbnail generator
|
||||
│ ├── deployer/ # webhook 기반 자동 배포 컨테이너
|
||||
│ ├── frontend/ # 정적 파일 (Vite build 결과)
|
||||
│ ├── nginx/
|
||||
│ │ └── default.conf
|
||||
│ ├── scripts/
|
||||
│ │ └── deploy.sh # webhook이 호출하는 실행기
|
||||
│ ├── docker-compose.yml
|
||||
│ └── data/
|
||||
│ └── lotto.db
|
||||
│
|
||||
├── workspace/
|
||||
│ └── web-page-backend/ # 🧠 Git 레포 (backend + infra)
|
||||
│ ├── backend/
|
||||
│ ├── travel-proxy/
|
||||
│ ├── deployer/
|
||||
│ ├── nginx/
|
||||
│ ├── scripts/
|
||||
│ │ └── deploy-nas.sh # 실제 운영 반영 로직
|
||||
│ ├── docker-compose.yml
|
||||
│ ├── .env.example
|
||||
│ └── README.md
|
||||
│
|
||||
└── web/
|
||||
└── images/
|
||||
└── webPage/
|
||||
└── travel/ # 📷 원본 여행 사진 (RO)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🧩 서비스 구성 개요
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
User[User Browser] -->|HTTP| Nginx
|
||||
|
||||
subgraph NAS [Synology NAS]
|
||||
Nginx -->|/api/lotto| Lotto[Lotto Backend]
|
||||
Nginx -->|/api/travel| Travel[Travel Proxy]
|
||||
Nginx -->|/api/stock| Stock[Stock Lab]
|
||||
Stock -->|Trading/Balance| KIS[KIS API (Korea Inv.)]
|
||||
Stock -->|Market News| News[News Sites]
|
||||
end
|
||||
|
||||
subgraph Windows [High-Performance PC]
|
||||
Stock -->|Analyze Request| WinServer[Windows AI Server]
|
||||
WinServer -->|LLM Inference| Ollama[Ollama (Llama 3.1)]
|
||||
WinServer -->|GPU| GPU[NVIDIA 3070 Ti]
|
||||
end
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🛠️ 개발 환경 설정 (Local Development)
|
||||
|
||||
이 프로젝트는 **Windows/Mac 로컬 환경**과 **Synology NAS 운영 환경**을 모두 지원하도록 구성되었습니다.
|
||||
|
||||
### 1. 환경 변수 설정
|
||||
`docker-compose.yml`은 환경 변수에 의존합니다.
|
||||
1. `.env.example` 파일을 복사하여 `.env` 파일을 생성하세요.
|
||||
```bash
|
||||
cp .env.example .env
|
||||
```
|
||||
2. `.env` 파일의 경로(`RUNTIME_PATH`, `PHOTO_PATH` 등)를 로컬 환경에 맞게 수정하세요.
|
||||
- 기본값은 현재 디렉토리(`.`) 기준으로 설정되어 있어 바로 실행 가능합니다.
|
||||
|
||||
### 2. 로컬 실행
|
||||
```bash
|
||||
docker compose up -d
|
||||
```
|
||||
- Frontend: http://localhost:8080
|
||||
- Backend API: http://localhost:18000
|
||||
- Travel API: http://localhost:19000
|
||||
- Stock Lab API: http://localhost:18500
|
||||
|
||||
---
|
||||
|
||||
### 🟦 Frontend (lotto-frontend)
|
||||
|
||||
- **역할**: React + Vite 기반 SPA로, 로또 추천 및 여행 지도 UI를 제공합니다.
|
||||
- **특징**:
|
||||
- 정적 파일만 운영 서버에 배포합니다.
|
||||
- 장기 캐시(`assets/`)와 `index.html` 캐시 무효화 전략을 사용합니다.
|
||||
- Backend / Travel API는 Nginx에서 Reverse Proxy로 연결됩니다.
|
||||
- **배포 방식**:
|
||||
1. **로컬 개발**:
|
||||
- `.env` 파일 설정 후 `docker compose up`으로 전체 스택 실행 가능
|
||||
2. **운영 배포**:
|
||||
- Code를 Git에 Push
|
||||
- Webhook이 트리거되어 NAS가 자동 Pull & Deploy
|
||||
- (Frontend 빌드 산출물은 별도 업로드 혹은 CI 연동 필요)
|
||||
|
||||
---
|
||||
|
||||
### 🟩 Backend (lotto-backend)
|
||||
|
||||
- **역할**: 로또 데이터 수집, 분석, 추천 API를 제공하며 SQLite로 데이터를 관리합니다.
|
||||
- **주요 기능**:
|
||||
- 최신 및 특정 회차 조회
|
||||
- 추천 번호 생성 및 히스토리 관리 (중복 제거)
|
||||
- 즐겨찾기, 메모, 태그 관리
|
||||
- 배치 추천 기능
|
||||
- **기술 스택**: FastAPI, SQLite, APScheduler (정기 수집)
|
||||
- **주요 엔드포인트**:
|
||||
```http
|
||||
GET /api/lotto/latest
|
||||
GET /api/lotto/{drw_no}
|
||||
GET /api/lotto/recommend
|
||||
GET /api/lotto/recommend/batch
|
||||
GET /api/history
|
||||
PATCH /api/history/{id}
|
||||
DELETE /api/history/{id}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 🟪 Stock Lab (stock-lab)
|
||||
|
||||
- **역할**: 주식 시장 분석 및 AI 기반 투자 조언 제공. NAS의 편의성과 Windows PC의 고성능을 결합한 하이브리드 아키텍처입니다.
|
||||
- **주요 기능**:
|
||||
- **시장 뉴스 스크랩**: 네이버 증권, 해외 주요 뉴스 사이트 크롤링
|
||||
- **자산 관리**: 한국투자증권(KIS) Open API 연동 (잔고 조회, 매수/매도)
|
||||
- **AI 분석**: 고성능 PC의 로컬 LLM(Llama 3.1)을 활용하여 뉴스+포트폴리오 종합 분석
|
||||
- **기술 스택**: Python, FastAPI, Ollama (Lava/Llama3), Docker
|
||||
- **연동 구조**:
|
||||
```
|
||||
[NAS Stock-Lab] <--(HTTP)--> [Windows AI Server] <--(Localhost)--> [Ollama GPU]
|
||||
```
|
||||
- **주요 엔드포인트**:
|
||||
```http
|
||||
GET /api/stock/analyze # AI 시장 분석 요청
|
||||
GET /api/stock/news # 최신 뉴스 데이터
|
||||
GET /api/trade/balance # 계좌 잔고 조회
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 🟨 Travel Proxy (travel-proxy)
|
||||
|
||||
- **역할**: 여행 사진 API, 지역별 사진 매칭, 썸네일 자동 생성 및 캐시를 담당합니다.
|
||||
- **설계 포인트**:
|
||||
- 원본 사진은 읽기 전용(RO)으로 마운트합니다.
|
||||
- 썸네일은 쓰기/읽기(RW) 전용 캐시 디렉토리를 사용합니다.
|
||||
- 사진 메타데이터 변경 시 캐시가 자동으로 무효화됩니다.
|
||||
- **데이터 구조**:
|
||||
```
|
||||
/data/travel/ # 원본 사진 (RO)
|
||||
├── 24.09.jeju/
|
||||
├── 25.07.maldives/
|
||||
└── _meta/
|
||||
├── region_map.json
|
||||
└── regions.geojson
|
||||
|
||||
/data/thumbs/ # 썸네일 캐시 (RW)
|
||||
├── 24.09.jeju/
|
||||
└── 25.07.maldives/
|
||||
```
|
||||
- **주요 엔드포인트**:
|
||||
```http
|
||||
GET /api/travel/regions
|
||||
GET /api/travel/photos?region=jeju
|
||||
GET /media/travel/.thumb/{album}/{file}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 🟥 Deployer (webpage-deployer)
|
||||
|
||||
- **역할**: Gitea Webhook을 수신하여 Git pull 및 Docker 재기동을 자동화합니다.
|
||||
- **흐름**: `Gitea Push` → `Webhook` → `deployer` → `/scripts/deploy.sh` → `docker compose up -d --build`
|
||||
- **보안**: HMAC SHA256 서명(`X-Gitea-Signature`)을 `WEBHOOK_SECRET` 환경변수로 검증합니다.
|
||||
- **특징**:
|
||||
- Docker socket을 마운트하여 사용합니다.
|
||||
- 롤백을 위해 `.releases/` 디렉토리에 자동 백업을 수행합니다.
|
||||
|
||||
---
|
||||
|
||||
## 🔁 배포 플로우 요약
|
||||
|
||||
- **Backend / Travel / Infra 변경**: `git push`를 통해 Gitea로 푸시하면 Webhook이 트리거되어 자동으로 배포됩니다.
|
||||
- **Frontend 변경**: 로컬에서 빌드 후, 생성된 정적 파일만 NAS로 업로드합니다.
|
||||
|
||||
---
|
||||
|
||||
## 🧪 운영 체크 포인트
|
||||
|
||||
- `/health`: Backend 서비스 상태 확인
|
||||
- `/api/travel/photos`: 응답 속도 확인
|
||||
- `/media/travel/.thumb`: 썸네일 생성 여부 확인
|
||||
- `deployer` 컨테이너 로그 확인
|
||||
|
||||
---
|
||||
|
||||
## 📝 TODO
|
||||
|
||||
### 🔥 로또 서비스 고도화
|
||||
|
||||
- [ ] 추천 결과 통계 시각화 (분포, 합계, 홀짝)
|
||||
- [ ] 추천 히스토리 필터 및 검색 기능
|
||||
- [ ] 추천 결과 즐겨찾기 UI
|
||||
- [ ] 회차 대비 추천 성능 분석
|
||||
|
||||
### 🗺️ 여행 지도 UI
|
||||
|
||||
- [ ] 지도 영역 클릭 시 해당 지역 사진 로딩
|
||||
- [ ] 사진 지연 로딩 (Lazy Load)
|
||||
- [ ] 앨범 및 연도별 필터 기능
|
||||
- [ ] 모바일 UX 개선
|
||||
|
||||
### ⚙️ 운영/인프라
|
||||
|
||||
- [ ] Docker 이미지 버전 태깅 자동화
|
||||
- [ ] 배포 실패 시 자동 롤백 기능
|
||||
- [ ] Health check 기반 배포 성공 판단 로직
|
||||
- [ ] 로그 수집 및 관리 체계 개선
|
||||
|
||||
---
|
||||
|
||||
## ✨ 철학
|
||||
|
||||
> “NAS는 서버가 아니라 집이다.”
|
||||
>
|
||||
> 그래서 안전하고, 단순하며, 복구 가능한 구조를 최우선으로 합니다.
|
||||
|
||||
---
|
||||
|
||||
## Makefile 설정 사용 예시
|
||||
|
||||
- **배포**: `make deploy`
|
||||
- **백엔드 로그**: `make logs S=backend`
|
||||
- **전체 로그**: `make logs`
|
||||
- **상태**: `make status`
|
||||
- **`.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 고정 예약)
|
||||
|
||||
Reference in New Issue
Block a user