# rb8001 계층 분리 리팩토링 Phase 2 완료

**날짜**: 2026-01-02
**작성자**: happybell80
**관련 파일**: 
- `rb8001/app/services/coldmail_filter.py`
- `rb8001/app/services/startup_valuation.py`
- `rb8001/app/services/intent_bayes.py`
- `rb8001/app/services/diary/aggregator.py`
- `rb8001/app/services/skills/dm_skill.py`
- `rb8001/app/services/naverworks_file_processor.py`
- `rb8001/app/state/repositories/`

---

## 문제 상황

계획 문서(`251123_rb8001_계층_분리_리팩토링_계획.md`)에서 Phase 2 미완료 위반 사항 6개:
1. router/feedback_handler.py:58 - SessionLocal() 직접 사용
2. router/intent_review_endpoint.py:21 - SessionLocal() 직접 사용
3. router/slack_handler.py:77,202,361 - SessionLocal() 직접 사용
4. services/startup_valuation.py:475 - asyncpg.connect() 직접 사용
5. services/intent_bayes.py:57,117,160 - psycopg2.connect() 직접 사용
6. services/coldmail_filter.py:182,208,255 - asyncpg.connect() 직접 사용

**원칙 위반**: `311_FastAPI_구조_원칙.md` 6장 - DB 접근은 state/repositories를 통해서만

---

## 해결 방안

### 1. state/repositories/ 폴더 생성
- `app/state/repositories/` 폴더 생성
- 기존 repository 파일들은 `state/`에 유지 (이미 올바른 위치)

### 2. Repository 패턴 구현 (TDD)
- **coldmail_classifier_repository.py**: coldmail_classifier 테이블 CRUD
  - `get_word_counts()`, `get_all_coldmail_counts()`, `get_vocabulary_size()`, `update_word_count()`, `initialize_seed_data()`
- **startup_valuation_repository.py**: startup_valuation 테이블 저장
  - `save_valuation()`
- **intent_classifier_repository.py**: intent_classifier 테이블 CRUD (동기)
  - `ensure_setup()`, `get_totals()`, `get_counts()`, `update_counts()`
- **user_repository.py**: user, user_preference 테이블 조회
  - `get_user_news_keywords()`, `get_user_uuid_by_slack_id()`, `get_user_team_id()`

### 3. Services 수정
- `coldmail_filter.py`: asyncpg.connect() 3곳 → repository 호출로 변경
- `startup_valuation.py`: asyncpg.connect() 1곳 → repository 호출로 변경
- `intent_bayes.py`: psycopg2.connect() 3곳 → repository 호출로 변경
- `diary/aggregator.py`: SessionLocal() 1곳 → conversation_repository 호출로 변경
- `skills/dm_skill.py`: SessionLocal() 1곳 → user_repository 호출로 변경
- `naverworks_file_processor.py`: SessionLocal() 2곳 → user_repository 호출로 변경

### 4. conversation_repository 확장
- `get_conversations_by_time_range()` 메서드 추가

---

## 구현 완료

**커밋**: 작업 완료
**수정 파일**:
- `app/state/repositories/coldmail_classifier_repository.py` (신규)
- `app/state/repositories/startup_valuation_repository.py` (신규)
- `app/state/repositories/intent_classifier_repository.py` (신규)
- `app/state/repositories/user_repository.py` (신규)
- `app/services/coldmail_filter.py`
- `app/services/startup_valuation.py`
- `app/services/intent_bayes.py`
- `app/services/diary/aggregator.py`
- `app/services/skills/dm_skill.py`
- `app/services/naverworks_file_processor.py`
- `app/state/conversation_repository.py`

---

## 교훈

### TDD 방식 적용
- 테스트 먼저 작성 (Red) → Repository 구현 (Green) → Services 수정 (Refactor)
- `test_coldmail_classifier_repository.py` 작성으로 기대 동작 명확화

### Repository 패턴 일관성
- asyncpg/psycopg2 직접 연결을 repository로 캡슐화
- 각 repository는 단일 테이블/도메인 전담
- 연결 관리(생성/종료)는 repository 내부에서 처리

### 계층 분리 원칙 준수
- services에서 DB 직접 연결 금지, state/repositories를 통해서만 접근
- router는 FastAPI 의존성 주입 패턴 사용 (`get_db()` 함수는 정상)

### 남은 작업
- `diary/aggregator.py`에 SessionLocal() 직접 사용 3곳 추가 수정 필요
- `router/slack_handler.py`의 SessionLocal() 사용 확인 필요 (의존성 주입 패턴일 수 있음)
- 나머지 asyncpg/psycopg2 직접 연결 10곳 추가 수정 필요

