업로드 시 어떤 행이 왜 제외되는가. 제외는 두 층으로 나뉩니다 — 화면에 보여주는 "미리보기 4기준"과, DB에 실제 반영되는 "파이프라인 dedup 3기준". 둘은 같지 않습니다.
화면의 "제외"는 고지(미리보기)이고, 실제 반영은 별도 파이프라인이 결정합니다.
① 미리보기 화면4 모달
exclusion-preview.service.ts
POST /api/v1/exclusion-preview
② 파이프라인 실제 반영
smart-import.service.ts
deduplicateRecords()
import_jobs.unresolvedData로 보존(복구 가능)모두 워크스페이스 범위. 업로드 값(이메일/회사명)을 기존 DB와 대조.
| 사유 (코드) | 판정 로직 | 토글 |
|---|---|---|
| active_sequence 활성 시퀀스 등록됨 |
업로드 이메일 = 활성/일시정지 시퀀스에 활성/일시정지 enrollment로 등록된 리드의 이메일
sequences.status ∈ {active, paused}
AND enrollment.status ∈ {active, paused}
AND lead_contacts.email = 업로드이메일 |
강제 ON 못 끔 |
| past_sent 과거 발송 이력 |
업로드 이메일 = emails 테이블에 발송 이력 있는 수신주소
emails.status ∈ {sent, delivered,
opened, clicked, replied}
AND emails.to_email = 업로드이메일 |
ON/OFF |
| duplicate_email 이메일 중복 |
업로드 이메일 = 워크스페이스 lead_contacts(type=email)에 이미 존재
lead_contacts.contact_type = 'email'
AND lead_contacts.contact_value = 업로드이메일 |
ON/OFF |
| duplicate_company 회사명 중복 |
업로드 회사명(lower) = 워크스페이스 leads.company_name(lower)에 이미 존재
lower(leads.company_name)
= lower(업로드회사명) |
ON/OFF |
NFC + trim + lowercase (단순).anyText (대소문자 무시 IN 조회), 5,000건 청크.willImport ≤ 0이면 비활성.500,000행이면 미리보기 모달 skip → 바로 import.한 행이 여러 사유에 걸려도 가장 높은 사유 하나만 표시(가장 actionable한 이유).
import 시 DB에 무엇이 들어갈지 실제로 결정. deduplicateRecords.
// 행별 순차, 매칭되면 duplicates 로 빼고 continue 1 email normalizeEmail (NFC+trim+lower+형식검증) → DB lead_contacts 매칭 OR 파일내 중복 2 url host normalizeUrlHost (호스트만, www 제거) ← 미리보기엔 없는 축 → DB leads.website_url 매칭 OR 파일내 중복 3 회사명 normalizeCompanyName (악센트·접미사·부호 제거) ← 미리보기보다 공격적 → DB leads.company_name 매칭 OR 파일내 중복 매칭분 → import_jobs.unresolvedData (수동 복구 가능)
| 기준 | 미리보기에 있나 | 비고 |
|---|---|---|
| ○ (duplicate_email) | 거의 동일 | |
| url host | ✕ 없음 | 파이프라인 전용 |
| 회사명 | △ (정규화 다름) | 접미사 제거로 더 많이 묶임 |
| active_sequence / past_sent | ○ (미리보기 전용) | 파이프라인은 안 봄 |
| # | 불일치 | 결과 |
|---|---|---|
| 1 | 회사명 정규화 차이 — 미리보기=단순 lower / 파이프라인=접미사·악센트 제거 | 미리보기엔 "안 빠짐"인데 import에서 빠질 수 있음 (Gap Inc. vs Gap) |
| 2 | 미리보기 전용 기준 — active_sequence·past_sent | 새 이메일이면 활성 시퀀스 멤버라도 import됨 (파이프라인은 email로만 간접 차단) |
| 3 | 파이프라인 전용 축 — url host | 미리보기엔 URL 중복 개념 없음 |
| 4 | 토글은 시뮬레이션 — 모달 ON/OFF는 카운트만 바꿈 | "회사명 중복 끄기" 해도 실제 import는 항상 dedup (주석: false 는 시뮬레이션 전용) |
| 값 | ① 미리보기 | ② 파이프라인 |
|---|---|---|
| 이메일 | NFC + trim + lower | NFC + trim + lower + 형식검증 |
| 회사명 | NFC + trim + lower (여기까지) | + 악센트 제거 + 접미사(Inc/Ltd/LLC…) 제거 + 부호 제거 |
| URL | — | host만(www 제거, path/query 버림) |
| 코드 | exclusion-preview.service.ts:26,32 | utils/dedup-normalize.ts |