- Flask Blueprint 아키텍처로 전환 (dashboard, upload, backup, status) - app.py 681줄 95줄로 축소 (86% 감소) - HTML 템플릿 모듈화 (base.html + 기능별 templates) - CSS/JS 파일 분리 (common + 기능별 파일) - 대시보드 기능 추가 (통계, 주간 예보, 방문객 추이) - 파일 업로드 웹 인터페이스 구현 - 백업/복구 관리 UI 구현 - Docker 배포 환경 개선 - .gitignore 업데이트 (uploads, backups, cache 등)
421 lines
8.4 KiB
Markdown
421 lines
8.4 KiB
Markdown
# 개발자 가이드 (Developer Guide)
|
|
|
|
이 문서는 First Garden Static Analysis Service에 기여하거나 개발하고자 하는 개발자를 위한 가이드입니다.
|
|
|
|
## 개발 환경 설정
|
|
|
|
### 1. 저장소 클론
|
|
```bash
|
|
git clone https://git.siane.kr/firstgarden/static.git
|
|
cd static
|
|
```
|
|
|
|
### 2. Python 가상환경 생성
|
|
```bash
|
|
# Python 3.11 이상 필수
|
|
python3.11 -m venv venv
|
|
|
|
# 가상환경 활성화
|
|
# Linux/macOS
|
|
source venv/bin/activate
|
|
|
|
# Windows
|
|
.\venv\Scripts\activate
|
|
```
|
|
|
|
### 3. 의존성 설치
|
|
```bash
|
|
pip install --upgrade pip setuptools wheel
|
|
pip install -r requirements.txt
|
|
|
|
# 개발 도구 추가 설치
|
|
pip install pytest pytest-cov black flake8 mypy
|
|
```
|
|
|
|
### 4. 환경 변수 설정
|
|
```bash
|
|
cp .env.example .env
|
|
# .env 파일을 편집하여 로컬 DB 정보 입력
|
|
```
|
|
|
|
### 5. 로컬 데이터베이스 설정
|
|
```bash
|
|
# Docker로 MariaDB 실행 (기존 DB가 없는 경우)
|
|
docker run --name fg-static-db \
|
|
-e MYSQL_ROOT_PASSWORD=rootpassword \
|
|
-e MYSQL_DATABASE=firstgarden \
|
|
-e MYSQL_USER=firstgarden \
|
|
-e MYSQL_PASSWORD=Fg9576861! \
|
|
-p 3306:3306 \
|
|
mariadb:11.2-jammy
|
|
```
|
|
|
|
---
|
|
|
|
## 코드 스타일
|
|
|
|
### PEP 8 준수
|
|
```bash
|
|
# 코드 포매팅
|
|
black lib/ conf/ daily_run.py
|
|
|
|
# 린트 검사
|
|
flake8 lib/ conf/ daily_run.py --max-line-length=100
|
|
|
|
# 타입 검사
|
|
mypy lib/ conf/ --ignore-missing-imports
|
|
```
|
|
|
|
### 명명 규칙
|
|
- 함수/변수: `snake_case`
|
|
- 클래스: `PascalCase`
|
|
- 상수: `UPPER_CASE`
|
|
- 비공개 함수: `_leading_underscore`
|
|
|
|
### 문서화
|
|
모든 함수에 docstring 작성:
|
|
```python
|
|
def fetch_data(start_date, end_date, **kwargs):
|
|
"""
|
|
데이터 조회 함수
|
|
|
|
Args:
|
|
start_date (datetime.date): 시작 날짜
|
|
end_date (datetime.date): 종료 날짜
|
|
**kwargs: 추가 매개변수
|
|
|
|
Returns:
|
|
pd.DataFrame: 조회된 데이터
|
|
|
|
Raises:
|
|
ValueError: 유효하지 않은 날짜 범위
|
|
DatabaseError: DB 연결 실패
|
|
"""
|
|
...
|
|
```
|
|
|
|
---
|
|
|
|
## 로깅 사용법
|
|
|
|
```python
|
|
from lib.common import setup_logging
|
|
|
|
# 로거 생성
|
|
logger = setup_logging('module_name', 'INFO')
|
|
|
|
# 로그 출력
|
|
logger.info('정보 메시지')
|
|
logger.warning('경고 메시지')
|
|
logger.error('에러 메시지', exc_info=True) # 스택 트레이스 포함
|
|
logger.debug('디버그 메시지')
|
|
```
|
|
|
|
---
|
|
|
|
## 데이터베이스 작업
|
|
|
|
### 세션 관리
|
|
```python
|
|
from conf.db import DBSession
|
|
|
|
# 권장: 컨텍스트 매니저 사용
|
|
with DBSession() as session:
|
|
result = session.execute(select(some_table))
|
|
# 자동으로 커밋 또는 롤백
|
|
|
|
# 또는 기존 방식
|
|
session = db.get_session()
|
|
try:
|
|
result = session.execute(select(some_table))
|
|
session.commit()
|
|
finally:
|
|
session.close()
|
|
```
|
|
|
|
### 쿼리 작성
|
|
```python
|
|
from sqlalchemy import select, and_, func
|
|
from conf import db_schema
|
|
|
|
# 데이터 조회
|
|
session = db.get_session()
|
|
stmt = select(
|
|
db_schema.weather.c.date,
|
|
db_schema.weather.c.maxTa
|
|
).where(
|
|
and_(
|
|
db_schema.weather.c.date >= '2025-01-01',
|
|
db_schema.weather.c.stnId == 99
|
|
)
|
|
)
|
|
result = session.execute(stmt).fetchall()
|
|
```
|
|
|
|
---
|
|
|
|
## API 데이터 수집
|
|
|
|
### 기본 패턴
|
|
```python
|
|
import requests
|
|
from lib.common import setup_logging, retry_on_exception
|
|
|
|
logger = setup_logging(__name__, 'INFO')
|
|
|
|
@retry_on_exception(max_retries=3, delay=1.0, backoff=2.0)
|
|
def fetch_api_data(url, params):
|
|
"""API 데이터 수집"""
|
|
try:
|
|
response = requests.get(url, params=params, timeout=20)
|
|
response.raise_for_status()
|
|
data = response.json()
|
|
logger.info(f"API 데이터 수집 완료: {len(data)} 건")
|
|
return data
|
|
except requests.exceptions.RequestException as e:
|
|
logger.error(f"API 요청 실패: {e}")
|
|
raise
|
|
```
|
|
|
|
---
|
|
|
|
## 테스트 작성
|
|
|
|
### 단위 테스트
|
|
```bash
|
|
# 테스트 디렉토리 생성
|
|
mkdir tests
|
|
|
|
# 테스트 파일 작성
|
|
cat > tests/test_common.py << 'EOF'
|
|
import pytest
|
|
from lib.common import load_config
|
|
|
|
def test_load_config():
|
|
config = load_config()
|
|
assert config is not None
|
|
assert 'database' in config
|
|
assert 'DATA_API' in config
|
|
|
|
def test_load_config_invalid_path():
|
|
with pytest.raises(FileNotFoundError):
|
|
load_config('/invalid/path.yaml')
|
|
EOF
|
|
|
|
# 테스트 실행
|
|
pytest tests/ -v
|
|
pytest tests/ --cov=lib --cov=conf
|
|
```
|
|
|
|
### 통합 테스트
|
|
```python
|
|
# tests/test_integration.py
|
|
import pytest
|
|
from conf.db import DBSession
|
|
from lib.weekly_visitor_forecast_prophet import load_data
|
|
|
|
def test_load_data_integration():
|
|
"""DB에서 데이터 로드 테스트"""
|
|
with DBSession() as session:
|
|
from datetime import date, timedelta
|
|
start_date = date.today() - timedelta(days=30)
|
|
end_date = date.today()
|
|
|
|
df = load_data(session, start_date, end_date)
|
|
assert len(df) > 0
|
|
assert 'pos_qty' in df.columns
|
|
```
|
|
|
|
---
|
|
|
|
## 모듈 개발 체크리스트
|
|
|
|
새로운 모듈을 추가할 때 다음을 확인하세요:
|
|
|
|
- [ ] 모든 함수에 docstring 작성
|
|
- [ ] PEP 8 코드 스타일 준수
|
|
- [ ] 로깅 추가 (info, warning, error)
|
|
- [ ] 에러 처리 구현
|
|
- [ ] 단위 테스트 작성
|
|
- [ ] `requirements.txt` 업데이트
|
|
- [ ] README.md 업데이트
|
|
- [ ] CHANGELOG.md 업데이트
|
|
|
|
---
|
|
|
|
## Git 워크플로우
|
|
|
|
### 기본 브랜치
|
|
- `main`: 배포 준비 브랜치
|
|
- `develop`: 개발 메인 브랜치
|
|
- `feature/*`: 기능 개발
|
|
- `bugfix/*`: 버그 수정
|
|
|
|
### 커밋 메시지 포맷
|
|
```
|
|
[타입] 간단한 설명
|
|
|
|
더 자세한 설명 (선택사항)
|
|
|
|
연관 이슈: #123
|
|
```
|
|
|
|
**타입:**
|
|
- `feat`: 새로운 기능
|
|
- `fix`: 버그 수정
|
|
- `docs`: 문서화
|
|
- `refactor`: 코드 리팩토링
|
|
- `test`: 테스트 추가
|
|
- `chore`: 설정 변경
|
|
|
|
### 브랜치 생성 및 병합
|
|
```bash
|
|
# 브랜치 생성
|
|
git checkout develop
|
|
git pull origin develop
|
|
git checkout -b feature/새로운기능
|
|
|
|
# 커밋
|
|
git add .
|
|
git commit -m "[feat] 새로운 기능 추가"
|
|
|
|
# 푸시
|
|
git push origin feature/새로운기능
|
|
|
|
# Merge Request/Pull Request 생성 후 코드 리뷰
|
|
```
|
|
|
|
---
|
|
|
|
## CI/CD 파이프라인
|
|
|
|
### GitHub Actions (예상 설정)
|
|
```yaml
|
|
# .github/workflows/test.yml
|
|
name: Test
|
|
|
|
on: [push, pull_request]
|
|
|
|
jobs:
|
|
test:
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@v2
|
|
- uses: actions/setup-python@v2
|
|
with:
|
|
python-version: '3.11'
|
|
- run: pip install -r requirements.txt
|
|
- run: pytest tests/ --cov=lib --cov=conf
|
|
```
|
|
|
|
---
|
|
|
|
## 문제 해결
|
|
|
|
### 일반적인 개발 문제
|
|
|
|
**Q: DB 연결 실패**
|
|
```bash
|
|
# DB 상태 확인
|
|
docker ps | grep mariadb
|
|
|
|
# DB 접속 확인
|
|
mysql -h localhost -u firstgarden -p firstgarden
|
|
|
|
# conf/config.yaml에서 DB 정보 확인
|
|
```
|
|
|
|
**Q: 패키지 설치 오류**
|
|
```bash
|
|
# 캐시 초기화
|
|
pip cache purge
|
|
|
|
# 의존성 재설치
|
|
pip install -r requirements.txt --force-reinstall
|
|
```
|
|
|
|
**Q: 포트 이미 사용 중**
|
|
```bash
|
|
# 기존 컨테이너 제거
|
|
docker-compose down -v
|
|
|
|
# 포트 사용 프로세스 확인
|
|
lsof -i :3306
|
|
```
|
|
|
|
---
|
|
|
|
## 성능 프로파일링
|
|
|
|
### 실행 시간 측정
|
|
```python
|
|
import time
|
|
from lib.common import setup_logging
|
|
|
|
logger = setup_logging(__name__)
|
|
|
|
start = time.time()
|
|
# 코드 실행
|
|
elapsed = time.time() - start
|
|
logger.info(f"실행 시간: {elapsed:.2f}초")
|
|
```
|
|
|
|
### 메모리 프로파일링
|
|
```bash
|
|
# memory_profiler 설치
|
|
pip install memory-profiler
|
|
|
|
# 스크립트 실행
|
|
python -m memory_profiler script.py
|
|
```
|
|
|
|
---
|
|
|
|
## 배포 준비
|
|
|
|
### 프로덕션 체크리스트
|
|
- [ ] 모든 테스트 통과
|
|
- [ ] 코드 리뷰 완료
|
|
- [ ] 버전 번호 업데이트 (CHANGELOG.md)
|
|
- [ ] 환경 변수 검증
|
|
- [ ] 데이터베이스 마이그레이션 확인
|
|
- [ ] Docker 이미지 빌드 및 테스트
|
|
- [ ] 보안 취약점 검사
|
|
- [ ] 성능 벤치마크
|
|
|
|
---
|
|
|
|
## 유용한 명령어
|
|
|
|
```bash
|
|
# 개발 모드로 실행
|
|
PYTHONUNBUFFERED=1 python daily_run.py
|
|
|
|
# 로그 모니터링
|
|
tail -f logs/daily_run.log
|
|
|
|
# Docker 컨테이너 로그
|
|
docker-compose logs -f fg-static
|
|
|
|
# 데이터베이스 접속
|
|
docker-compose exec mariadb mysql -u firstgarden -p firstgarden
|
|
|
|
# 파이썬 인터랙티브 셸
|
|
python -c "import sys; sys.path.insert(0, '.'); from conf import db; print(db.load_config())"
|
|
```
|
|
|
|
---
|
|
|
|
## 참고 자료
|
|
|
|
- [Python 공식 가이드](https://docs.python.org/)
|
|
- [SQLAlchemy 문서](https://docs.sqlalchemy.org/)
|
|
- [Prophet 가이드](https://facebook.github.io/prophet/docs/installation.html)
|
|
- [Docker 문서](https://docs.docker.com/)
|
|
- [Git 가이드](https://git-scm.com/doc)
|
|
|
|
---
|
|
|
|
**작성일**: 2025-12-26
|
|
**마지막 업데이트**: 2025-12-26
|