# 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곳 추가 수정 필요