docs: Coldmail Slack Lists 컬럼 매핑 및 IR 대표 이름 추출 스펙 문서 추가

- 251122_coldmail_slack_lists_column_mapping_spec.md: 컬럼 매핑 스펙 및 검증 시나리오
- 251122_ir_representative_name_extraction_spec.md: IR 문서 대표 이름 추출 설계
This commit is contained in:
Claude-51124 2025-11-22 22:57:15 +09:00
parent b33691964e
commit 5f28de18fa
2 changed files with 217 additions and 0 deletions

View File

@ -0,0 +1,131 @@
# Coldmail Slack Lists 컬럼 매핑 스펙
**날짜**: 2025-11-22
**작성자**: Claude
**관련 파일**:
- `rb8001/app/services/coldmail_processor.py`
- `rb8001/app/services/ir_analyzer.py`
---
## Slack Lists 실제 컬럼 구조
**확인 방법**: Slack Lists UI에서 확인 (이미지 참조)
| 컬럼 이름 | 타입 | 용도 | 현재 코드 매핑 |
|-----------|------|------|----------------|
| 회사설명 | rich_text | 회사명 저장 | ❌ business_area 저장 중 |
| 날짜 | date | 이메일 수신일 | ✅ 정상 |
| 대표 | rich_text | 대표 이름 저장 | ❌ From 헤더 발신자 이름 |
| 이메일 | email | 이메일 주소 | ✅ 정상 |
| IR Deck | attachment | PDF 파일 첨부 | ✅ 정상 (attach_id) |
| 확인 | checkbox | 체크박스 | ❌ deck_id에 혼재 |
---
## 요구사항 (테스트 기준)
### 1. "회사설명" 컬럼
- **저장 값**: `company_name` (IR 문서 또는 휴리스틱으로 추론한 회사명)
- **현재**: `business_area` 또는 제목 저장 (수정 필요)
- **검증**: Slack Lists에서 "회사설명" 컬럼에 회사명이 표시되어야 함
### 2. "대표" 컬럼
- **저장 값**: 대표 이름 (`representative_name`)
- **우선순위**:
1. IR 문서에서 추출한 대표 이름
2. From 헤더에서 파싱한 발신자 이름 (fallback)
3. 없으면 "없음" (현재 정책 유지)
- **검증**: IR 문서에 대표 이름이 있으면 IR 우선, 없으면 From 헤더 사용
### 3. "IR Deck" 컬럼
- **저장 값**: PDF 파일 (attachment 타입)
- **매핑**: `attach_id` 사용 (현재 정상)
- **컬럼 이름 매칭**: "ir deck", "irdeck", "ir 덱" 등
- **검증**: IR PDF 파일이 "IR Deck" 컬럼에 첨부되어야 함
### 4. "확인" 컬럼
- **저장 값**: 체크박스 (기본 False)
- **매핑**: `check_id` 별도 컬럼
- **컬럼 이름 매칭**: "확인"만 (IR Deck과 분리)
- **검증**: "확인" 컬럼에 체크박스가 표시되어야 함 (IR Deck과 별도)
---
## IR 문서 추출 필드 스펙
### 현재 추출 필드 (ir_analyzer.py:257-265, 296-304)
- company_name
- business_area
- investment_stage
- revenue
- growth_rate
- team_size
- tech_advantage
### 추가 필요 필드
- **representative_name**: 대표이사/CEO 이름
- RAG 쿼리: "이 회사의 대표이사 또는 CEO 이름은 무엇인가?"
- LLM 프롬프트 키: `representative_name`
- 형식: "홍길동" (이름만)
---
## 우선순위 정책
### 회사명 (company_name)
1. IR 문서 `company_name` (유효하면 사용)
2. 휴리스틱 `_derive_company_name` (제목/발신 도메인)
3. `business_area` (fallback)
### 대표 이름 (representative_name)
1. IR 문서 `representative_name` (추출 시)
2. From 헤더 `contact_name` (발신자 이름)
3. "없음" (둘 다 없을 때)
---
## 검증 시나리오
### 시나리오 1: IR 문서에 대표 이름 있는 경우
- **IR 문서**: 대표이사 "김철수" 명시
- **From 헤더**: "홍길동 <hong@company.com>"
- **예상 결과**: "대표" 컬럼 = "김철수" (IR 우선)
### 시나리오 2: IR 문서에 대표 이름 없는 경우
- **IR 문서**: 대표 이름 정보 없음
- **From 헤더**: "홍길동 <hong@company.com>"
- **예상 결과**: "대표" 컬럼 = "홍길동" (From 헤더 fallback)
### 시나리오 3: 둘 다 없는 경우
- **IR 문서**: 대표 이름 정보 없음
- **From 헤더**: "hong@company.com" (이름 없음)
- **예상 결과**: "대표" 컬럼 = "없음"
### 시나리오 4: 회사설명 컬럼 검증
- **IR 문서**: company_name="(주)테크스타트업"
- **예상 결과**: "회사설명" 컬럼 = "(주)테크스타트업" (company_name)
---
## 구현 완료 조건
- [ ] IR analyzer에서 `representative_name` 추출 구현
- [ ] Coldmail processor에서 회사설명 컬럼에 `company_name` 저장
- [ ] 대표 컬럼에 IR 우선순위 적용
- [ ] IR Deck과 확인 컬럼 분리 매핑
- [ ] 검증 시나리오 1-4 모두 통과
---
## 교훈
### 문서화 부족
- Slack Lists 컬럼 구조가 코드에 휴리스틱으로만 존재
- 실제 컬럼 이름과 매핑 정책이 명시적으로 문서화되지 않음
- 교훈: UI와 코드 매핑은 항상 문서로 정리하고 동기화
### 필드 이름 일관성
- IR 추출 필드명 (`representative_name`)과 사용처 필드명 (`contact_name`) 혼재
- 교훈: 필드 이름은 추출 단계부터 사용 단계까지 일관성 유지

View File

@ -0,0 +1,86 @@
# IR 문서 대표 이름 추출 스펙
**날짜**: 2025-11-22
**작성자**: Claude
**관련 파일**:
- `rb8001/app/services/ir_analyzer.py`
---
## 요구사항
IR 문서에서 대표이사/CEO 이름을 추출하여 coldmail processor에서 "대표" 컬럼에 저장.
---
## 현재 상태
### 추출 필드 목록 (ir_analyzer.py:257-265)
- company_name
- business_area
- investment_stage
- revenue
- growth_rate
- team_size
- tech_advantage
**대표 이름 필드 없음**
### LLM 프롬프트 (ir_analyzer.py:296-304)
- `exact keys` 목록에 `representative_name` 없음
---
## 설계
### 1. RAG 쿼리 추가
**위치**: `ir_analyzer.py:257-265` queries 딕셔너리
**추가 쿼리**:
```python
"representative_name": "이 회사의 대표이사 또는 CEO 이름은 무엇인가? (예: 홍길동, 김철수)"
```
### 2. LLM 프롬프트 키 추가
**위치**: `ir_analyzer.py:296-304` prompt의 `exact keys` 목록
**추가 키**:
```python
- representative_name: 대표이사 또는 CEO 이름 (예: "홍길동", "김철수")
```
### 3. 반환 형식
**타입**: `str`
**형식**: 이름만 (예: "홍길동", "김철수")
**없을 때**: "N/A"
---
## 우선순위 정책
**coldmail_processor.py에서 사용**:
1. IR 문서 `representative_name` (유효하면)
2. From 헤더 `contact_name` (fallback)
3. "없음" (둘 다 없을 때)
---
## 검증 기준
### 성공 케이스
- IR 문서에 "대표이사: 홍길동" 명시 → `representative_name = "홍길동"`
- IR 문서에 "CEO: 김철수" 명시 → `representative_name = "김철수"`
### 실패 케이스
- IR 문서에 대표 이름 정보 없음 → `representative_name = "N/A"`
- IR 문서 파싱 실패 → `representative_name = "N/A"`
---
## 구현 완료 조건
- [ ] RAG 쿼리에 `representative_name` 추가
- [ ] LLM 프롬프트에 `representative_name` 키 추가
- [ ] 실제 IR 문서로 테스트 (대표 이름 있는 경우/없는 경우)
- [ ] coldmail processor에서 IR `representative_name` 우선 사용