DOCS/journey/troubleshooting/260102_rb8001_계층_분리_리팩토링_Phase2_완료.md
2026-01-04 14:28:10 +09:00

3.9 KiB

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