CRM, 청구, 지원을 위한 단일 고객 프로필 스키마
CRM, 청구, 지원 전반에서 일관된 단일 고객 프로필 스키마를 구축하세요. 시스템 오브 레코드 규칙, 중복 제거, 시스템 간 매핑으로 업데이트가 일관되게 이동하도록 합니다.

고객 데이터가 도구들에 나뉘는 이유(그리고 왜 문제가 되는가)
한 고객이 항상 한 레코드로만 존재하는 경우는 드뭅니다. CRM에서는 사람(리드나 연락처)이 회사(계정)에 연결됩니다. 청구에서는 법적 이름, 세금 정보, 송장이 붙는 결제 주체입니다. 지원에서는 티켓을 연 사람과 그 사람이 속한 회사가 기록됩니다.
각 도구는 자기 역할을 하므로 서로 다른 순간에 다른 세부 정보를 캡처합니다. 영업은 명함에서 연락처를 생성하고, 재무는 송장 요청으로 청구 고객을 만들며, 지원은 이메일로 요청자를 생성합니다. 이건 모두 정상입니다. 문제는 이로 인해 비슷해 보이지만 하나의 고객처럼 동작하지 않는 별개의 레코드가 생긴다는 점입니다.
중복 레코드는 데이터베이스를 어지럽히는 것을 넘어 실질적인 실수를 야기합니다. 예를 들어 청구에 Acme Inc가 두 번 존재하면 결제가 한 레코드에 착지하고 송장은 다른 레코드로 갈 수 있습니다. VIP 고객이 지원에 두 번 존재하면 상담사는 과거의 에스컬레이션을 놓치고 고객이 이미 답한 질문을 반복하게 됩니다.
고객 데이터는 보통 다음과 같은 경우에 나뉩니다:
- 서로 다른 진입점(폼, 이메일, 가져오기)에서 레코드가 생성될 때
- 이름이 약간 다를 때(Acme, ACME, Acme Ltd)로 매칭 실패
- 사람들이 직장을 옮기거나 이메일, 전화번호가 바뀔 때
- 한 사람이 여러 팀이나 자회사를 대신해 구매할 때
- 한 시스템에서 병합했지만 다른 시스템에는 전파되지 않았을 때
시간이 지나면서 이런 불일치는 시스템들이 기본 사실(정확한 회사명, 주요 연락처, 계정 활성 여부 등)에 대해 조용히 다르게 말하는 드리프트로 발전합니다. 보통 환불, 갱신 누락, 잘못된 고객을 처리하는 지원 상황 등으로 뒤늦게 눈에 띕니다.
실용적인 단일 고객 프로필 스키마는 CRM, 청구, 지원을 하나의 데이터베이스로 대체하는 것을 의미하지 않습니다. 여러 시스템은 그대로 유지되지만, 사람과 회사(사람↔회사, 회사↔청구 주체)의 정체성과 관계에 대한 공유 뷰를 만들어 업데이트가 일관되게 이동하도록 하는 것이 목표입니다.
"단일 프로필"의 범위 정의
테이블을 설계하거나 동기 작업을 만들기 전에 조직에서 "단일"이 의미하는 바를 결정하세요. 단일 프로필은 모든 것을 담는 거대한 레코드가 아니라 다음에 대한 합의입니다:
- 어떤 시스템들을 범위에 둘 것인지
- 프로필이 답해야 할 질문들
- 각 데이터 조각의 신선도(업데이트 빈도)
우선 실제로 조정할 시스템들부터 시작하세요. 많은 팀은 CRM, 청구, 지원, 제품 사용자 데이터베이스, 그리고 이미 가지고 있는 통합 계층을 포함합니다.
그다음 통합 프로필이 평문으로 답해야 할 항목들을 정하세요:
- 이 사람은 누구고 어느 회사에 속해 있나?
- 무엇을 구매했고 현재 결제 상태는 어떤가?
- 어떤 이슈를 보고하고 있고 긴급하거나 반복되는 문제가 있는가?
- 어떻게 연락해야 하고 어떤 연락 수단을 선호하나?
- 제품에 접근할 권한이 있고 어떤 역할로 접근하나?
범위에서 제외할 항목을 엄격히 정하세요. 많은 단일 프로필 프로젝트가 조용히 분석이나 마케팅 재구성으로 변질되어 실패합니다. 마케팅 귀속, 광고 추적, 데이터 보강, 장기 행동 분석은 나중에 합치면 됩니다. 이들이 핵심 정체성 모델을 좌우하지 않도록 하세요.
업데이트 타이밍은 기술적 세부사항이 아니라 범위의 선택입니다. 실시간 동기화가 필요한 경우는 접근 권한 변경(정지, 역할 업데이트)이나 고터치 지원의 경우입니다. 송장 내역과 티켓 메타데이터에는 시간당 또는 일일 동기화로 충분한 경우가 많습니다. 이는 데이터 조각별로 결정하세요.
사전에 개인정보와 보존 정책을 문서화하세요. 어떤 개인 데이터를 얼마 동안 어디에 저장할 수 있는지 결정하세요. 지원 노트에는 민감한 내용이 포함될 수 있어 CRM으로 흐르면 안 될 수 있습니다. 청구 데이터는 법적 보관 요구사항이 있을 수 있습니다.
핵심 엔터티: 사람, 회사, 그리고 각 시스템에서 부르는 이름
실용적인 스키마는 두 가지 기본 엔터티에서 시작합니다: Company와 Person. 대부분의 팀이 이미 이를 갖고 있습니다. 문제는 각 도구가 다른 이름과 가정을 사용한다는 점이고, 이로 인해 불일치가 생깁니다.
거의 모든 스택에 매핑할 수 있고 나중에 확장 가능한 간단한 기본 모델은 다음과 같습니다:
- Account (Company): 판매 대상인 사업체. Company, Organization, Account 등으로 불립니다.
- Contact (Person): 개인. Person, User, Lead, Requester 등으로 불립니다.
- Billing Customer: 청구 도구에서의 결제 주체(종종 결제 수단과 세금 정보에 연결됨).
- Subscription / Invoice: 시간이 지나며 변하는 상업적 객체. 사람 레코드와 분리해서 유지하세요.
- Support Ticket: 대화 스레드로, requester(사람)과 선택적으로 organization(회사)를 참조합니다.
관계를 명시적으로 모델링하세요. 연락처는 보통 하나의 주요 계정에 속하지만 컨설턴트처럼 여러 고객과 관계가 필요한 경우 부가적 연관을 허용해야 합니다. 연락처에 여러 이메일과 전화번호를 허용하되, 하나를 주(primary)로 표시하고 나머지는 유형별 대체(work, personal, mobile)로 저장하세요.
청구에서는 "고객"이 사람처럼 보일 수 있지만, 결제 내역이 연락처의 역할 변경에 따라 깨지지 않도록 Billing Customer를 계정에 연결된 별도 엔터티로 취급하는 것이 안전합니다.
지원 도구는 종종 "Requester"와 "Organization"을 사용합니다. Requester는 Contact에, Organization은 Account에 매핑하되 모든 requester가 organization을 가지는 것은 아님을 전제로 하세요.
초기부터 엣지 케이스를 설계에 반영하세요:
- 공유 메일박스([email protected])로 인해 생성된 가짜 사람 레코드
- 고객으로 간주되지만 활성 고객으로 계산하면 안 되는 계약직(contractor)
- 지불 주체가 최종 사용자가 아닌 리셀러
- 별도의 계정이 필요하지만 상위 회사가 있는 자회사
필드 수준의 시스템 오브 레코드 결정
시스템 오브 레코드는 특정 필드를 변경할 권한이 있는 유일한 장소입니다. 다른 모든 도구는 그 값을 표시할 수는 있지만 덮어써서는 안 됩니다. 엄격하게 느껴지겠지만 CRM, 청구, 지원이 모두 서로 도우려다 조용히 드리프트를 일으키는 것을 방지합니다.
시스템 단위가 아니라 필드 단위로 소유권을 결정하세요. 대부분의 팀은 문서로 남기면 빠르게 합의합니다.
| Field | System of record | Other systems behavior | Conflict rule |
|---|---|---|---|
| Primary email | CRM | Read-only in billing/support | CRM의 이메일이 검증되지 않았고 청구에서 검증된 경우를 제외하고 CRM 우선 |
| Billing address | Billing | Read-only in CRM/support | Billing 우선; 다음 송장/결제 이벤트 시 CRM 업데이트 |
| Plan / subscription status | Billing | Read-only elsewhere | Billing 우선; 취소 시 Support에는 태그만 업데이트, 플랜 자체는 변경 불가 |
| Support priority / SLA tier | Support | Read-only elsewhere | Support 우선; CRM은 표시만 가능 |
| Legal company name | Billing (if invoiced) or CRM (if lead) | Read-only elsewhere | 리드 단계에서는 CRM 우선; 첫 송장 후에는 Billing 우선 |
값이 다를 때는 "마지막 쓰기 승자(last write wins)"를 피하세요. 그 방식은 실수를 숨깁니다. 대신 명확한 규칙을 사용하세요: 검증 상태가 자유 텍스트보다 우선하고, 결제 상태가 영업 노트보다 우선이며, "첫 송장 이후" 규칙이 "구매 전" 규칙보다 우선합니다. 타이에 대한 결정을 내려야 하면 하나의 타임스탬프 소스(예: billing 이벤트 시간)를 선택해 고수하세요.
통합에서 읽기 전용 대 쓰기 가능한 동작을 실제로 구현하세요. 도움이 되는 기본 규칙은 각 시스템이 소유한 필드만 쓰고, 시스템별 내부 운영 메모(예: 지원 상담사의 내부 코멘트)처럼 절대 동기화하지 않을 소수 필드만 추가로 쓸 수 있게 하는 것입니다.
병합이 어디서 일어나는지도 결정하세요. 이상적으로 병합은 한 곳(사람/회사 병합은 보통 CRM, 결제와 연관된 계정 병합은 보통 Billing)에서만 수행되어야 합니다. 다른 시스템은 매핑을 업데이트하고 오래된 ID를 retired로 표시하여 병합을 반영해야 합니다.
ID 전략: 내부 고객 ID와 시스템 간 매핑
단일 고객 프로필 스키마는 정체성을 세 가지 식별자 유형으로 분리할 때 가장 잘 작동합니다: 내부에서 관리하는 Customer ID, 각 도구가 부여한 외부 ID들, 그리고 이메일이나 도메인 같은 유용하지만 보장되지 않는 자연 키들입니다.
불변의 내부 Customer ID(예: UUID)를 하나 만들고 한 번 생성하면 재사용하거나 변경하지 마세요. 고객이 병합되거나 리브랜딩하거나 이메일을 바꿔도 이 내부 ID는 보고, 권한, 통합의 앵커로 남습니다.
외부 ID는 CRM, 청구, 지원 도구 내부의 ID입니다. 한 시스템의 ID를 보편적으로 강제하려 하지 마세요. 이를 전용 매핑 테이블에 저장해 여러 레코드와 마이그레이션에서 하나의 내부 고객을 추적하세요.
간단한 매핑 테이블 예시는 다음과 같습니다(예: PostgreSQL):
- customer_id (internal, immutable)
- system (crm | billing | support)
- external_id (해당 시스템 내의 ID)
- status (active | inactive)
- first_seen_at / last_seen_at
이메일은 일부 경우에만 유용한 자연 키입니다. 온보딩 중 매칭을 제안하는 데 도움이 될 수 있지만 공유 메일박스, B2B의 잦은 이직, 별칭 등 때문에 기본 키로 사용하면 안 됩니다.
소프트 삭제와 감사 계획을 세우세요. 외부 레코드가 제거되거나 병합되면 매핑 행은 비활성으로 표시하고 변경 시점을 저장하세요. 이렇게 하면 분쟁, 환불, "왜 이 고객이 사라졌나" 조사에 필요한 과거 ID를 보존할 수 있습니다.
CRM, 청구, 지원에서 효과적인 중복 제거 규칙
중복 제거는 매칭과 병합 두 가지 작업입니다. 매칭은 가능한 중복을 찾고, 병합은 데이터를 영구적으로 변경합니다. 이 둘을 분리해 매칭을 조정하면서도 잘못된 병합을 피할 수 있도록 하세요.
결정적 규칙부터 시작하세요. 이런 규칙은 자동 병합에 가장 안전합니다. 시스템 전반에서 같은 의미를 가져야 하는 식별자를 사용합니다:
- 동일한 billing customer ID가 동일한 내부 customer ID에 매핑된 경우
- 회사 계정에 동일한 세금번호 또는 VAT 번호가 있는 경우
- 지원 포털 사용자 ID(지원 도구가 부여하는 경우)가 동일하게 사람에 매핑된 경우
- 사람 레코드에 동일한 이메일 주소가 있고 이메일이 검증된 경우
- 결제 공급자가 안정성을 보장하는 결제 수단 지문이 동일한 경우
그다음 검토 필요 규칙을 정의하세요. 이들은 드리프트를 잘 찾아내지만 자동 병합은 위험한 규칙입니다(공유 메일박스, 자회사, 계약직 등과 충돌할 수 있음):
- 유사한 이름 + 동일한 회사 도메인([email protected]과 [email protected])
- 동일한 전화번호(특히 대표 번호)
- 약간의 형식 차이가 있는 동일 배송 주소
- 회사명 변형(ACME Inc vs ACME Incorporated)
- 동일 도메인에서 생성된 티켓이지만 다른 연락처들
신뢰도(confidence) 임계값과 수동 검토 큐를 설정하세요. 예: 0.95 이상은 자동 병합, 0.80~0.95는 검토로 보냄, 0.80 미만은 무시. 검토 큐는 "왜 매칭되었는가", 값의 나란히 비교, 실행 취소 가능한 단일 병합 액션을 보여줘야 합니다.
병합 후에도 이전 레코드가 존재하지 않았던 것처럼 가장하지 마세요. 오래된 ID를 살아남은 내부 customer ID로 리디렉션하고, 별칭(이전 이메일, 이전 회사명), 모든 시스템 간 매핑 행을 업데이트해 향후 동기화가 중복을 다시 만들지 못하게 하세요.
예시: Billing에는 세금번호가 있는 "Acme LLC"가 있고 CRM에는 세금번호 없이 "ACME, LLC"가 있으며 지원에는 티켓으로 생성된 "Acme"가 있다면, 세금번호가 회사 자동 병합을 트리거합니다. 유사한 연락처 이메일은 병합하기 전에 수동 검토로 보냅니다.
통합 매핑: 무엇을 어디로, 어떤 트리거로 이동시킬지
단일 고객 프로필은 무엇이 실제로 이동해야 하는지를 결정할 때만 '단일'로 유지됩니다. 모든 것을 동기화하면 안전해 보이지만 충돌, 비용, 드리프트가 증가합니다.
동기화할 최소 필드(모든 항목이 아님)
각 도구가 일을 할 수 있게 하는 가장 작은 집합으로 시작하세요:
- 내부 Customer ID와 외부 ID들(CRM ID, Billing ID, Support ID)
- 법적 이름과 표시명(및 B2B인 경우 회사명)
- 기본 이메일과 전화번호(검증 상태 포함)
- 계정 상태(active, past-due, closed) 및 구독 요약
- 담당자/팀 라우팅(영업 담당자 또는 지원 큐)
빠르게 변하는 데이터나 무거운 데이터는 로컬에 두세요. 티켓 메시지는 지원에, 송장 항목은 청구에, 활동 타임라인은 CRM에 둡니다.
필드별 매핑: 출처, 목적지, 방향, 빈도
각 매핑을 계약처럼 문서화하세요. 이렇게 하면 "핑퐁" 업데이트를 방지할 수 있습니다.
- 이메일: CRM -> Support(변경 시 실시간), CRM -> Billing(시간별 배치 또는 실시간)
- 구독 상태: Billing -> CRM, Billing -> Support(이벤트 발생 시 실시간)
- 회사명: CRM -> Billing/Support(일일 또는 변경 시, 단 Billing에서 필요한 경우만)
- 지원 플랜 티어: Billing -> Support(실시간), 선택적으로 Billing -> CRM(일일)
- 기본 전화번호: CRM -> Support(변경 시), CRM이 허용하지 않으면 쓰기 금지
각 필드에 대해 허용 형식(대소문자, 공백, 전화번호 정규화), 빈 값이 덮어쓸 수 있는지 여부, 두 시스템이 다를 때의 처리 방법을 정의하세요.
트리거: 중요한 순간들
전체 동기화 대신 이벤트 트리거를 사용하세요. 일반적 트리거는: 신규 고객 생성, 구독 시작/갱신, 티켓 생성, 이메일 변경, 계정 종료입니다.
업데이트가 실패하면 숨기지 마세요. 아웃바운드 업데이트를 큐에 넣고 지수적 백오프를 사용하며 최대 재시도 창(예: 24시간) 이후에는 데드레터 큐로 옮겨 검토하도록 하세요.
항상 감사 로그를 남겨 내부 customer ID, 필드 이름, 이전 값, 새 값, 타임스탬프, 출처 시스템을 기록하세요.
운영 시작 후 드리프트를 방지하는 방법
런칭 후 단일 프로필은 다시 흩어질 수 있습니다. 드리프트는 보통 사소한 것으로 시작합니다: 전화번호가 지원에서 고쳐지고, 청구가 법적 이름을 송장을 위해 업데이트하고, CRM은 옛값을 유지합니다. 한 달 뒤에는 아무도 프로필을 신뢰하지 않게 됩니다.
드리프트는 부분 업데이트(한 시스템만 변경), 잘못된 곳에서의 수동 편집, 통합의 오래된 캐시가 어제의 데이터를 계속 복사하는 것에서 시작합니다. 해결책은 더 열심히 동기화하는 것이 아니라 변경 가능한 위치를 명확히 정하는 것입니다.
쓰기 펜스 도입(오직 소유자만 쓸 수 있게)
중요 필드마다 한 개의 소유 시스템을 정하고 다음을 적용하세요:
- 가능한 경우 비소유 시스템에서 해당 필드를 읽기 전용으로 만들기(폼에서 숨기거나 권한으로 잠그기)
- UI를 잠글 수 없다면 통합 계층에서 업데이트를 차단하고 명확한 오류를 반환
- 사람들이 작업하는 곳에 편집 라우팅 가이드 추가: "주소는 CRM이 아닌 Billing에서 변경하세요"
- 거부된 모든 쓰기 시도와 누가 어디서 무엇을 바꾸려 했는지 기록
의도적인 정합성 검사, 검증, 백필(backfill)
펜스를 둬도 불일치는 발생합니다. 시스템을 비교하고 불일치 보고서를 생성하는 소규모 정합성 작업을 추가하세요(일일 또는 주간). 법적 이름, 청구 주소, 세금 ID, 기본 이메일, 계정 상태 같은 영향 큰 필드에 집중하세요.
중요 필드에 대해 last_verified_at 타임스탬프를 별도로 두세요. 이는 단순 변경 시점과 달리 누군가 확인한 시점을 알려줍니다.
소급 변경을 어떻게 처리할지도 결정하세요. 예: Billing이 법적 엔티티 이름을 정정하면 과거 송장, 과거 지원 티켓, 과거 CRM 노트를 모두 백필할지, 앞으로의 새 레코드에만 적용할지, 절대 백필하지 않을지 필드별로 규칙을 정하세요. 규칙이 없으면 시스템들이 서로를 영구히 수정하려 듭니다.
단계별: 스키마를 만들고 안전하게 배포하는 법
'좋음'의 정의를 하세요: 영업이 CRM을 업데이트하고, 청구가 송장을 게시하고, 지원이 티켓을 병합해도 하나의 프로필이 일관되게 유지되는 상태입니다.
통제된 방식으로 기반 다지기
혼란을 새 모델에 내장하지 않으려면 다음 순서로 작업하세요:
- CRM, 청구, 지원의 모든 고객 관련 필드를 목록화하고 필드별 소유자를 지정
- 실제로 저장할 통합 테이블 설계: Customer, Company/Account, Contact, Mapping(시스템 간 ID), Alias(이전 이름, 이메일, 도메인)
- 기존 내보내기를 통합 모델에 로드하고 매칭을 실행해 중복 후보 생성(자동 병합은 하지 않음)
- 중복을 해결하고 매핑을 생성한 뒤 편집 권한을 잠궈 필드가 세 곳에서 바뀌지 않게 함
- 생성, 업데이트, 병합, 취소 같은 명확한 트리거로 동기 흐름 구현 및 실패/불일치 모니터링 추가
작은 세그먼트로 파일럿을 실행한 후 확장하세요. 복구 가능한 작은 범위(지역 하나나 제품 라인 하나)를 선택해 충분한 사례가 나오도록 하되 실수 발생 시 복구 가능하게 하세요.
재작업을 막는 롤아웃 팁
병합 결정마다 이유(why)를 포함한 간단한 변경 로그를 유지하세요. 병합이 나중에 문제될 때 시간을 크게 절약해 줍니다.
파일럿 전에 롤백 계획을 정의하세요. 예: 프로필의 1% 이상이 불일치하면 동기화 중단, 마지막 깨끗한 스냅샷으로 복원, 더 엄격한 규칙으로 매칭 재실행 같은 계획을 세우세요.
현실적 예: 한 회사, 두 연락처, 엇갈린 레코드
Acme Parts는 B2B 고객입니다. 두 사람이 상호작용합니다: 운영 담당 Maya와 재무 담당 Jordan. 재무는 송장을 공유 메일([email protected])으로 받으려 합니다. 3개월 동안 지원 티켓이 세 건 들어왔고 그중 두 건은 Maya로, 한 건은 공유 청구 주소에서 왔습니다.
단일 고객 프로필 스키마를 적용하기 전에는 동일한 실제 고객이 세 가지 방식으로 존재했습니다:
- CRM: "Acme Parts"라는 리드와 Maya( [email protected] )만 있는 연락처
- Billing: 고객이 "[email protected]"으로 등록되어 있고 회사명은 "Acme Parts LLC", 배송 주소 포함
- Support: requester 레코드가 [email protected]과 [email protected]으로 각각 존재하고 티켓은 CRM 리드에 연결되지 않음
이제 실용적인 중복 제거 규칙을 적용하세요: 법적 이름 + 정규화된 도메인(acmeparts.com)이 일치하면 회사 레코드를 병합하되, 연락처는 회사가 같다고 해서 자동 병합하지 않습니다. Maya와 Jordan은 하나의 회사 계정 아래 별도 연락처로 남고, 공유 청구 메일박스는 주요 개인이 아니라 "billing contact" 역할로 처리합니다.
다음은 필드 수준 소유권과 동기화 예시입니다:
| Field | Owned by (system of record) | Synced to | Notes |
|---|---|---|---|
| Company legal name | Billing | CRM, Support | 세금 및 송장 데이터 관점에서 Billing이 가장 정확한 경우가 많음 |
| Plan / subscription status | Billing | CRM, Support | 영업이나 지원이 플랜을 추정하지 않게 함 |
| Support priority / SLA tier | Support | CRM | 일상적 권한은 Support가 주도 |
| Main phone | CRM | Support | 영업이 가장 자주 업데이트 |
| Billing address | Billing | CRM | 배송 주소와 청구 주소를 분리 유지 필요 시 분리 |
Maya가 이메일을 [email protected]에서 [email protected]으로 바꾸고 새 티켓을 열면 무슨 일이 일어날까요?
지원은 새 요청자 이메일로 티켓을 받습니다. 식별 규칙은 (1) 정확한 이메일 매칭, (2) 검증된 연락처 ID 매핑, (3) 도메인 기반 회사 매칭(검토 필요 플래그) 순으로 시도합니다. 시스템은 새 요청자 레코드를 만들지만 도메인 기반으로 티켓을 Acme Parts에 연결합니다. 내부 작업으로 이메일 변경을 확인하면 CRM(사람 정보의 소유자)에서 Maya의 연락처가 업데이트되고, 지원은 요청자 매핑을 동일한 내부 Contact ID로 갱신합니다. 공유 청구 메일박스는 계속 송장을 수신하고 회사는 하나의 계정으로 유지됩니다.
체크리스트와 다음 단계
단일 프로필을 완료했다고 부르기 전에 지루한 세부사항을 확인하세요. 이들이 먼저 망가지고 프로젝트가 작을 때 고치기 가장 쉽습니다.
빠른 체크리스트(드리프트를 막는 항목들)
- IDs가 완전하고 일관된가: 모든 고객 레코드에 내부 Customer ID가 있고 각 연결 도구의 외부 ID가 매핑 테이블에 저장되어 있는가?
- 공유 필드마다 한 소유자가 지정되어 있는가: 동기화되는 모든 필드(법적 이름, 청구 이메일, 세금 ID, 플랜, 상태 등)에 대해 시스템 오브 레코드와 진실의 방향이 선언되어 있는가?
- 중복 제거는 되돌릴 수 있는가: 별칭과 병합 히스토리(이전 이메일, 이전 회사명, 이전 외부 ID)를 보존하고 병합을 실행 취소할 수 있는가?
- 동기 실패는 의도적으로 처리되는가: 재시도 로직이 있고 실패 이벤트는 데드레터 큐나 보관 테이블로 가며 감사 로그가 누가 무엇을 보냈는지 보여주는가?
- 사람에게 안전한 재량권이 있는가: Support와 Finance가 "자동 병합 금지" 또는 "검토 필요"를 표시할 수 있어 예외 케이스가 반복적으로 깨지지 않도록 하는가?
다음 단계
하나의 실제 워크플로우를 골라 엔드투엔드로 프로토타입하세요: "새 회사가 가입하고 첫 송금을 하고 지원 티켓을 여는 흐름" 같은 시나리오. 필요한 최소 엔터티와 매핑만 만들어 20~50개의 실제 레코드를 돌려 수동 검토가 얼마나 자주 필요한지 측정하세요.
데이터베이스, 워크플로우, API를 빠르게 모델링할 방법을 원한다면 AppMaster(appmaster.io)에서 스키마를 프로토타입해 실제 백엔드 코드를 생성하는 방법을 고려하세요. 먼저 매핑 테이블, 병합 히스토리, 감사 로그를 모델링하는 데 집중하세요. 이들이 통합이 커질 때 정체성이 드리프트하지 않게 막아주는 핵심입니다.
자주 묻는 질문
단일 고객 프로필은 CRM, 청구, 지원, 제품 사용자 데이터베이스 전반에서 동일한 사람과 회사를 연결하는 공통 정체성 계층입니다. 기존 도구들을 대체하는 것이 아니라 누구인지와 어떤 권한을 갖고 있는지를 충돌 없이 일관되게 답할 수 있도록 해줍니다.
실제 운영을 이끄는 가장 작은 집합에서 시작하세요: CRM, 청구, 지원, 그리고 제품 사용자 데이터베이스입니다. 마케팅과 분석은 나중에 추가하세요. 이들은 범위를 확장하고 정체성 규칙을 복잡하게 만들기 쉽습니다.
두 가지 기본 엔터티를 사용하세요: Person(사람)과 Company(회사). 추가로 Company에 연결된 별도의 Billing Customer 엔터티를 두고, 송장과 구독은 Billing Customer에 붙입니다. 이렇게 하면 담당자가 바뀌어도 결제 내역을 잃지 않습니다.
필드별로 시스템 오브 레코드를 선정하세요. 모든 것을 한 시스템에 몰아넣기보다 단일 연락처 정보는 CRM, 법적 이름과 주소 및 구독 상태는 Billing, SLA/우선순위는 Support가 소유하는 식입니다. 비소유 시스템은 해당 필드를 읽기 전용으로 취급하게 하세요.
마지막 수정시간을 기준으로 결정하지 마세요. 의미 기반 규칙을 사용하세요. 예를 들어 검증된 값은 자유 텍스트보다 우선하고, 결제 관련 이벤트는 영업 메모보다 우선합니다. 언제 어떤 규칙이 적용되는지 문서화해 일관되게 처리하세요.
내부에서 제어하는 불변의 고객 ID(예: UUID)를 생성하고 각 도구의 외부 ID를 매핑 테이블에 저장하세요. 이메일은 보조 키로는 유용하지만 주 키로는 신뢰할 수 없습니다(공유 메일박스, 별칭, 이직 등 때문에).
매칭(중복 후보 찾기)과 병합(데이터를 영구 변경하기)을 분리하세요. 세금번호, 검증된 이메일, 기존 매핑처럼 결정적인 규칙은 자동 병합으로 처리하고, 이름 유사도나 도메인 일치 등 불확실한 경우는 수동 검토 큐로 보냅니다.
구독 변경, 계정 종료, 이메일 변경, 새 티켓 생성 같은 중요한 순간에 이벤트 기반 트리거를 사용하세요. 각 도구가 일상 업무에 필요한 최소한의 공유 필드만 동기화하고, 티켓 메시지나 송장 항목처럼 무거운 데이터는 출처 시스템에 두세요.
중요 필드에 대해 쓰기 권한을 한 곳으로 제한하고, 비소유 시스템의 쓰기 시도를 기록하세요. 매칭 규칙과 소규모 정합성 검사를 주기적으로 돌려 불일치 보고서를 생성하고, last_verified_at 같은 별도 검증 타임스탬프를 두어 무엇이 실제로 확인되었는지 추적하세요.
AppMaster 같은 노코드 플랫폼에서 데이터베이스 스키마, 매핑 테이블, 워크플로우를 프로토타입한 뒤 프로덕션 준비가 되면 실제 백엔드와 앱 코드를 생성할 수 있습니다. 핵심은 매핑 테이블, 병합 히스토리, 감사 로그를 초기에 모델링하는 것입니다. (AppMaster, appmaster.io)


