Initial commit: Todo Project with dashboard, classification center, and upload functionality
- 📱 PWA 지원: 홈화면 추가 가능한 Progressive Web App - 🎨 M-Project 색상 스키마: 하늘색, 주황색, 회색, 흰색 일관된 디자인 - 📊 대시보드: 데스크톱 캘린더 뷰 + 모바일 일일 뷰 반응형 디자인 - 📥 분류 센터: Gmail 스타일 받은편지함으로 스마트 분류 시스템 - 🤖 AI 분류 제안: 키워드 기반 자동 분류 제안 및 일괄 처리 - 📷 업로드 모달: 데스크톱(파일 선택) + 모바일(카메라/갤러리) 최적화 - 🏷️ 3가지 분류: Todo(시작일), 캘린더(마감일), 체크리스트(무기한) - 📋 체크리스트: 진행률 표시 및 완료 토글 기능 - 🔄 시놀로지 연동 준비: 메일플러스 연동을 위한 구조 설계 - 📱 반응형 UI: 모든 페이지 모바일 최적화 완료
This commit is contained in:
469
docs/DEPLOYMENT.md
Normal file
469
docs/DEPLOYMENT.md
Normal file
@@ -0,0 +1,469 @@
|
||||
# 배포 가이드 (DEPLOYMENT.md)
|
||||
|
||||
## 🚀 배포 개요
|
||||
|
||||
Todo-Project는 Docker를 사용한 컨테이너 기반 배포를 지원하며, 개인용 환경에 최적화되어 있습니다.
|
||||
|
||||
## 📋 사전 요구사항
|
||||
|
||||
### 시스템 요구사항
|
||||
- **OS**: Linux, macOS, Windows (Docker 지원)
|
||||
- **RAM**: 최소 2GB, 권장 4GB
|
||||
- **Storage**: 최소 10GB 여유 공간
|
||||
- **Network**: 인터넷 연결 (시놀로지 연동 시)
|
||||
|
||||
### 필수 소프트웨어
|
||||
- Docker 20.10+
|
||||
- Docker Compose 2.0+
|
||||
- Git (소스 코드 다운로드용)
|
||||
|
||||
## 🐳 Docker 배포
|
||||
|
||||
### 1. 소스 코드 다운로드
|
||||
```bash
|
||||
git clone https://github.com/your-username/Todo-Project.git
|
||||
cd Todo-Project
|
||||
```
|
||||
|
||||
### 2. 환경 설정
|
||||
```bash
|
||||
# 환경 변수 파일 생성
|
||||
cp .env.example .env
|
||||
|
||||
# 환경 변수 편집
|
||||
nano .env
|
||||
```
|
||||
|
||||
#### 기본 환경 변수 설정
|
||||
```bash
|
||||
# 데이터베이스 설정
|
||||
DATABASE_URL=postgresql://todo_user:todo_password@database:5432/todo_db
|
||||
POSTGRES_USER=todo_user
|
||||
POSTGRES_PASSWORD=your_secure_password_here
|
||||
POSTGRES_DB=todo_db
|
||||
|
||||
# JWT 설정 (반드시 변경!)
|
||||
SECRET_KEY=your-very-long-and-random-secret-key-here-change-this-in-production
|
||||
ALGORITHM=HS256
|
||||
ACCESS_TOKEN_EXPIRE_MINUTES=30
|
||||
|
||||
# 애플리케이션 설정
|
||||
DEBUG=false
|
||||
CORS_ORIGINS=["http://localhost:4000", "http://your-domain.com:4000"]
|
||||
|
||||
# 서버 설정
|
||||
HOST=0.0.0.0
|
||||
PORT=9000
|
||||
|
||||
# 시놀로지 연동 (선택사항)
|
||||
SYNOLOGY_DSM_URL=https://your-nas.synology.me:5001
|
||||
SYNOLOGY_USERNAME=todo_user
|
||||
SYNOLOGY_PASSWORD=your_synology_password
|
||||
ENABLE_SYNOLOGY_INTEGRATION=true
|
||||
```
|
||||
|
||||
### 3. Docker Compose 실행
|
||||
```bash
|
||||
# 백그라운드에서 실행
|
||||
docker-compose up -d
|
||||
|
||||
# 로그 확인
|
||||
docker-compose logs -f
|
||||
```
|
||||
|
||||
### 4. 서비스 확인
|
||||
```bash
|
||||
# 컨테이너 상태 확인
|
||||
docker-compose ps
|
||||
|
||||
# 헬스 체크
|
||||
curl http://localhost:9000/api/health
|
||||
|
||||
# 프론트엔드 접속
|
||||
open http://localhost:4000
|
||||
```
|
||||
|
||||
## 🔧 Docker Compose 구성
|
||||
|
||||
### docker-compose.yml
|
||||
```yaml
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
frontend:
|
||||
build:
|
||||
context: ./frontend
|
||||
dockerfile: Dockerfile
|
||||
ports:
|
||||
- "4000:80"
|
||||
depends_on:
|
||||
- backend
|
||||
environment:
|
||||
- API_BASE_URL=http://localhost:9000/api
|
||||
volumes:
|
||||
- ./frontend/static:/usr/share/nginx/html/static
|
||||
restart: unless-stopped
|
||||
|
||||
backend:
|
||||
build:
|
||||
context: ./backend
|
||||
dockerfile: Dockerfile
|
||||
ports:
|
||||
- "9000:9000"
|
||||
depends_on:
|
||||
- database
|
||||
environment:
|
||||
- DATABASE_URL=postgresql://todo_user:${POSTGRES_PASSWORD}@database:5432/todo_db
|
||||
- SECRET_KEY=${SECRET_KEY}
|
||||
- DEBUG=${DEBUG:-false}
|
||||
volumes:
|
||||
- ./backend/uploads:/app/uploads
|
||||
restart: unless-stopped
|
||||
|
||||
database:
|
||||
image: postgres:15-alpine
|
||||
ports:
|
||||
- "5434:5432"
|
||||
environment:
|
||||
- POSTGRES_USER=${POSTGRES_USER}
|
||||
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
|
||||
- POSTGRES_DB=${POSTGRES_DB}
|
||||
volumes:
|
||||
- postgres_data:/var/lib/postgresql/data
|
||||
- ./database/init:/docker-entrypoint-initdb.d
|
||||
restart: unless-stopped
|
||||
|
||||
volumes:
|
||||
postgres_data:
|
||||
```
|
||||
|
||||
### 프로덕션용 docker-compose.prod.yml
|
||||
```yaml
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
frontend:
|
||||
build:
|
||||
context: ./frontend
|
||||
dockerfile: Dockerfile.prod
|
||||
ports:
|
||||
- "80:80"
|
||||
- "443:443"
|
||||
volumes:
|
||||
- ./ssl:/etc/nginx/ssl
|
||||
- ./nginx/nginx.prod.conf:/etc/nginx/nginx.conf
|
||||
restart: always
|
||||
|
||||
backend:
|
||||
build:
|
||||
context: ./backend
|
||||
dockerfile: Dockerfile.prod
|
||||
expose:
|
||||
- "9000"
|
||||
environment:
|
||||
- DEBUG=false
|
||||
- DATABASE_URL=postgresql://todo_user:${POSTGRES_PASSWORD}@database:5432/todo_db
|
||||
restart: always
|
||||
|
||||
database:
|
||||
image: postgres:15-alpine
|
||||
expose:
|
||||
- "5432"
|
||||
environment:
|
||||
- POSTGRES_USER=${POSTGRES_USER}
|
||||
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
|
||||
- POSTGRES_DB=${POSTGRES_DB}
|
||||
volumes:
|
||||
- postgres_data:/var/lib/postgresql/data
|
||||
- ./backups:/backups
|
||||
restart: always
|
||||
|
||||
volumes:
|
||||
postgres_data:
|
||||
```
|
||||
|
||||
## 🌐 프로덕션 배포
|
||||
|
||||
### 1. SSL 인증서 설정
|
||||
```bash
|
||||
# Let's Encrypt 인증서 생성 (Certbot 사용)
|
||||
sudo certbot certonly --standalone -d your-domain.com
|
||||
|
||||
# 인증서 파일 복사
|
||||
sudo cp /etc/letsencrypt/live/your-domain.com/fullchain.pem ./ssl/
|
||||
sudo cp /etc/letsencrypt/live/your-domain.com/privkey.pem ./ssl/
|
||||
```
|
||||
|
||||
### 2. Nginx 설정 (프로덕션)
|
||||
```nginx
|
||||
# nginx/nginx.prod.conf
|
||||
server {
|
||||
listen 80;
|
||||
server_name your-domain.com;
|
||||
return 301 https://$server_name$request_uri;
|
||||
}
|
||||
|
||||
server {
|
||||
listen 443 ssl http2;
|
||||
server_name your-domain.com;
|
||||
|
||||
ssl_certificate /etc/nginx/ssl/fullchain.pem;
|
||||
ssl_certificate_key /etc/nginx/ssl/privkey.pem;
|
||||
|
||||
# Frontend
|
||||
location / {
|
||||
root /usr/share/nginx/html;
|
||||
index index.html;
|
||||
try_files $uri $uri/ /index.html;
|
||||
}
|
||||
|
||||
# Backend API
|
||||
location /api/ {
|
||||
proxy_pass http://backend:9000/api/;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
|
||||
# 보안 헤더
|
||||
add_header X-Frame-Options "SAMEORIGIN" always;
|
||||
add_header X-XSS-Protection "1; mode=block" always;
|
||||
add_header X-Content-Type-Options "nosniff" always;
|
||||
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 프로덕션 배포 실행
|
||||
```bash
|
||||
# 프로덕션 환경으로 배포
|
||||
docker-compose -f docker-compose.prod.yml up -d
|
||||
|
||||
# 로그 모니터링
|
||||
docker-compose -f docker-compose.prod.yml logs -f
|
||||
```
|
||||
|
||||
## 🔄 업데이트 및 유지보수
|
||||
|
||||
### 애플리케이션 업데이트
|
||||
```bash
|
||||
# 소스 코드 업데이트
|
||||
git pull origin main
|
||||
|
||||
# 컨테이너 재빌드 및 재시작
|
||||
docker-compose down
|
||||
docker-compose build --no-cache
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
### 데이터베이스 백업
|
||||
```bash
|
||||
# 백업 스크립트 생성
|
||||
cat > backup.sh << 'EOF'
|
||||
#!/bin/bash
|
||||
DATE=$(date +%Y%m%d_%H%M%S)
|
||||
BACKUP_FILE="todo_backup_${DATE}.sql"
|
||||
|
||||
docker-compose exec database pg_dump -U todo_user todo_db > ./backups/${BACKUP_FILE}
|
||||
echo "백업 완료: ${BACKUP_FILE}"
|
||||
|
||||
# 7일 이상 된 백업 파일 삭제
|
||||
find ./backups -name "todo_backup_*.sql" -mtime +7 -delete
|
||||
EOF
|
||||
|
||||
chmod +x backup.sh
|
||||
|
||||
# 백업 실행
|
||||
./backup.sh
|
||||
```
|
||||
|
||||
### 데이터베이스 복원
|
||||
```bash
|
||||
# 백업에서 복원
|
||||
docker-compose exec database psql -U todo_user -d todo_db < ./backups/todo_backup_20240115_120000.sql
|
||||
```
|
||||
|
||||
### 로그 관리
|
||||
```bash
|
||||
# 로그 확인
|
||||
docker-compose logs backend
|
||||
docker-compose logs frontend
|
||||
docker-compose logs database
|
||||
|
||||
# 로그 로테이션 설정
|
||||
cat > /etc/logrotate.d/docker-compose << 'EOF'
|
||||
/var/lib/docker/containers/*/*.log {
|
||||
rotate 7
|
||||
daily
|
||||
compress
|
||||
size=1M
|
||||
missingok
|
||||
delaycompress
|
||||
copytruncate
|
||||
}
|
||||
EOF
|
||||
```
|
||||
|
||||
## 📊 모니터링
|
||||
|
||||
### 헬스 체크 스크립트
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# health_check.sh
|
||||
|
||||
API_URL="http://localhost:9000/api/health"
|
||||
FRONTEND_URL="http://localhost:4000"
|
||||
|
||||
# API 헬스 체크
|
||||
if curl -f -s $API_URL > /dev/null; then
|
||||
echo "✅ API 서버 정상"
|
||||
else
|
||||
echo "❌ API 서버 오류"
|
||||
# 알림 발송 (예: 이메일, Slack 등)
|
||||
fi
|
||||
|
||||
# 프론트엔드 체크
|
||||
if curl -f -s $FRONTEND_URL > /dev/null; then
|
||||
echo "✅ 프론트엔드 정상"
|
||||
else
|
||||
echo "❌ 프론트엔드 오류"
|
||||
fi
|
||||
|
||||
# 데이터베이스 체크
|
||||
if docker-compose exec database pg_isready -U todo_user > /dev/null; then
|
||||
echo "✅ 데이터베이스 정상"
|
||||
else
|
||||
echo "❌ 데이터베이스 오류"
|
||||
fi
|
||||
```
|
||||
|
||||
### 시스템 리소스 모니터링
|
||||
```bash
|
||||
# 컨테이너 리소스 사용량 확인
|
||||
docker stats
|
||||
|
||||
# 디스크 사용량 확인
|
||||
df -h
|
||||
|
||||
# 메모리 사용량 확인
|
||||
free -h
|
||||
```
|
||||
|
||||
## 🔐 보안 설정
|
||||
|
||||
### 방화벽 설정 (Ubuntu/CentOS)
|
||||
```bash
|
||||
# UFW (Ubuntu)
|
||||
sudo ufw allow 22/tcp # SSH
|
||||
sudo ufw allow 80/tcp # HTTP
|
||||
sudo ufw allow 443/tcp # HTTPS
|
||||
sudo ufw enable
|
||||
|
||||
# firewalld (CentOS)
|
||||
sudo firewall-cmd --permanent --add-service=ssh
|
||||
sudo firewall-cmd --permanent --add-service=http
|
||||
sudo firewall-cmd --permanent --add-service=https
|
||||
sudo firewall-cmd --reload
|
||||
```
|
||||
|
||||
### 자동 보안 업데이트
|
||||
```bash
|
||||
# Ubuntu
|
||||
sudo apt install unattended-upgrades
|
||||
sudo dpkg-reconfigure -plow unattended-upgrades
|
||||
|
||||
# CentOS
|
||||
sudo yum install yum-cron
|
||||
sudo systemctl enable yum-cron
|
||||
sudo systemctl start yum-cron
|
||||
```
|
||||
|
||||
## 🚨 문제 해결
|
||||
|
||||
### 일반적인 문제들
|
||||
|
||||
#### 1. 컨테이너 시작 실패
|
||||
```bash
|
||||
# 로그 확인
|
||||
docker-compose logs backend
|
||||
|
||||
# 포트 충돌 확인
|
||||
netstat -tulpn | grep :9000
|
||||
|
||||
# 권한 문제 확인
|
||||
ls -la ./backend/uploads
|
||||
```
|
||||
|
||||
#### 2. 데이터베이스 연결 실패
|
||||
```bash
|
||||
# 데이터베이스 컨테이너 상태 확인
|
||||
docker-compose exec database pg_isready -U todo_user
|
||||
|
||||
# 연결 테스트
|
||||
docker-compose exec database psql -U todo_user -d todo_db -c "SELECT 1;"
|
||||
```
|
||||
|
||||
#### 3. 시놀로지 연동 문제
|
||||
```bash
|
||||
# 네트워크 연결 테스트
|
||||
curl -k https://your-nas.synology.me:5001/webapi/auth.cgi
|
||||
|
||||
# DNS 해결 확인
|
||||
nslookup your-nas.synology.me
|
||||
```
|
||||
|
||||
### 성능 최적화
|
||||
|
||||
#### 1. 데이터베이스 최적화
|
||||
```sql
|
||||
-- 인덱스 확인
|
||||
SELECT schemaname, tablename, attname, n_distinct, correlation
|
||||
FROM pg_stats
|
||||
WHERE tablename = 'todo_items';
|
||||
|
||||
-- 쿼리 성능 분석
|
||||
EXPLAIN ANALYZE SELECT * FROM todo_items WHERE user_id = 'uuid';
|
||||
```
|
||||
|
||||
#### 2. 캐싱 설정
|
||||
```bash
|
||||
# Redis 추가 (선택사항)
|
||||
docker run -d --name redis -p 6379:6379 redis:alpine
|
||||
```
|
||||
|
||||
## 📱 모바일 PWA 배포
|
||||
|
||||
### PWA 설정 확인
|
||||
```javascript
|
||||
// manifest.json 검증
|
||||
{
|
||||
"name": "Todo Project",
|
||||
"short_name": "Todo",
|
||||
"start_url": "/",
|
||||
"display": "standalone",
|
||||
"background_color": "#6366f1",
|
||||
"theme_color": "#6366f1",
|
||||
"icons": [
|
||||
{
|
||||
"src": "/icons/icon-192.png",
|
||||
"sizes": "192x192",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "/icons/icon-512.png",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Service Worker 등록
|
||||
```javascript
|
||||
// sw.js 등록 확인
|
||||
if ('serviceWorker' in navigator) {
|
||||
navigator.serviceWorker.register('/sw.js');
|
||||
}
|
||||
```
|
||||
|
||||
이 배포 가이드를 통해 안정적이고 확장 가능한 Todo-Project를 배포할 수 있습니다!
|
||||
Reference in New Issue
Block a user