연락처 & 동의
갖고만 있는 목록이 아니라 방어할 수 있는 목록
만 개의 이메일 주소를 갖고 있는 것은 누구나 할 수 있어요. 중요한 질문 — 규제 기관과 프로바이더, 그리고 여러분 자신의 양심이 조금씩 다른 말로 던지는 그 질문 — 은 각 주소가 어디에서 왔고, 어떤 근거로 메일을 쓸 수 있는지예요. ClickSomo는 그것을 나중에 재구성해야 할 것이 아니라 저장된 사실로 만들어요.
식별자는 이메일 주소예요
프로젝트당 주소당 연락처 하나, 희망이 아니라 데이터베이스가 강제해요. 주소는 쓸 때 정규화되지, 읽을 때가 아니에요 — 읽을 때 정규화하면 이 제약은 Anna@와 anna@를 둘 다 들여보내는 장식에 불과해져요.
전화번호는 존재하는 경우 E.164로 저장되지만, 전화번호는 속성이지 식별자가 아니에요. 식별자 해소 그래프도, 병합 프로토콜도, 병합 감사 기록도 없어요. 여기의 모든 연락처는 이미 주소를 갖고 있는 채널 — 가져오기, 폼, 구독, 또는 직접 작성한 코드 — 을 통해 들어오기 때문이에요.
이름은 통째로 저장돼요
display_name은 입력된 그대로 유지되며 절대 부분으로 나뉘지 않아요. 이름 분할은 버그 공장이에요 — "van der Berg", "Kim Min-jun", 단일명, 호칭, 그리고 앵글로식이 아닌 모든 이름 순서 관습 — 그리고 잘못된 분할은 병합 태그에서 "Dear van,"으로 드러나는데, 이는 개인화를 아예 안 하는 것보다 더 나빠요.
구조화된 부분은 이미 분리된 형태로 제공하는 소스에만 존재해요. 아무것도 이를 유추하지 않아요. 그리고 본인이 직접 입력한 이름은 우연히 다르게 관찰된 나중의 CSV에 의해 절대 덮어쓰이지 않아요. 마지막 쓰기 우선 방식은 가장 엉망인 가져오기가 이기게 해요.
- 1식별자정규화된 이메일. 프로젝트 내에서 고유해요.
- 2이름통째로 저장돼요.
first_name은 렌더링 시점에 유추되며 절대 저장되지 않아요. - 3속성으로 무엇이든 담을 수 있어요. 여러분의 것이며
attrs.*로 보간할 수 있어요. - 4태그와 목록태그는 일급 객체로 하나의 저장소에 살아요; 목록은 명시적인 멤버십이에요.
- 5동의채널당 한 행, 합법적 근거와 그 증거를 함께 담아요.
- 6이벤트이 사람이 한 모든 일의 추가 전용 로그. 제품이 의존하는 테이블이에요.
- ×사용 안 함비밀번호도, 해시도, 세션도, API 키도 없어요. 누군가를 인증하는 컬럼은 기능이 아니라 사고예요.
테넌트와 프로젝트, 둘 다에 범위가 한정돼요
동의 장부
부재는 권한이 아니에요
연락처당 채널당 한 행 — 이메일, SMS, 편지, 푸시 — 각각 상태, 합법적 근거, 출처, 증거, 타임스탬프, 관할권을 담아요. 어떤 채널에 근거 행이 없는 연락처에게는 그 채널로 아무것도 보낼 수 없어요. "표시됨"이 아니에요. 불가능해요.
consent
누군가 능동적으로 요청했어요. 증거가 저장된 폼 제출, 더블 옵트인, 본인이 직접 체크한 체크박스. 가장 강한 근거이며 폼이 만들어낼 수 있는 유일한 근거예요.
legitimate_interest
CSV 가져오기가 도달할 수 있는 최선이에요. 스프레드시트는 누군가 무언가에 동의한 것을 기억할 수 없으므로 동의했다고 주장하는 것은 절대 허용되지 않아요 — 그리고 같은 파일을 다시 올린다고 업그레이드되지 않아요.
contract
여러분과 상대방이 모두 당사자인 무언가 때문에 쓰는 거예요. 서비스 알림, 갱신 통지, 받지 못하면 짜증낼 그런 것.
캠페인이 발송되기 전에 수신자의 근거 구성을 보게 돼요: 이 사람들 중 몇 명이 요청했는지, 몇 명을 정당한 이익으로 연락하는지, 몇 명이 계약 때문에 있는지. 경고 배너 그 어떤 것보다 많은 나쁜 발송을 막아온 단 하나의 숫자예요.
여러분에게 필요한 것보다 엄격한 이유: 사실 여러분 때문이 아니에요. 대량 발송 평판은 공유 자원이고, 부주의한 목록 하나가 같은 인프라에서 발송하는 모든 사람의 우물을 오염시켜요. 테넌트별 불만 및 반송률이 감시되고, 임계값을 넘는 계정은 여기서 — 제공자가 모두를 한꺼번에 막기 전에 — 속도가 제한돼요.

목록의 모든 행 뒤에는 누군가가 예스라고 말했어요.
네 가지 경로
목록으로 들어오는 모든 경로는 여러분이 여러분의 데이터에 대해 행동하는 것이에요
서비스 토큰 수집 경로도 없고, 여러분의 연락처에 조용히 쓰는 형제 제품도 없어요. 누군가를 목록에 넣고 싶다면, 이 넷 중 하나가 그렇게 한 거예요.
CSV 가져오기
열 단위로 매핑되고, 쓸 때 정규화되고, MX 검사로 죽은 도메인과 오타 도메인이 하드 반송 전에 잡히고, 여러분이 명시적으로 설정한 근거로 들어와요. 가져오기에는 ID가 부여되고, 그것이 만든 모든 연락처는 그것을 가리켜요.
ClickSomo 폼
다른 모든 것과 같은 문서로 렌더링되며, 유효성 검사, 허니팟, 속도 제한이 있어요. 제출은 consent를 정당하게 만들어낼 수 있는 유일한 경로예요. 사람이 그 자리에 있는 유일한 경로이기 때문이에요.
dash-b에서 직접 만든 페이지
대시보드 디자이너가 페이지를 게시하고; 그 중 하나의 폼이 여러분의 자격 증명으로 여기에 전송해요. 같은 유효성 검사, 같은 동의 처리, 유지할 두 번째 통합은 없어요.
공개 API
POST /v1/contacts를 본인 토큰으로 호출하면, 업서트 방식으로 처리되고 멱등성 키도 존중됩니다. 앱은 이미 누가 가입했는지 알고 있으니, 그 사실에서 퍼널까지 가는 가장 짧은 길이에요.
세그먼트는 조건식이며, 컴파일됩니다
세그먼트는 연락처 필드, 속성, 태그, 목록 소속, 행동에 대한 조건 트리를 저장한 것으로, SQL로 컴파일되고 개수와 함께 캐시됩니다. 연산자는 평범한 것들 — 같음, 같지 않음, 포함(in), 미포함(not in), 시작 문자, 끝 문자, 포함(contains), 설정됨, 설정 안 됨 — 이고, and, or, not으로 원하는 만큼 깊게 조합할 수 있어요.
사용하기 전에 미리 보세요. 엔드포인트는 실제 연락처를 반환하므로, "실제로 여기에 누가 있는가"는 보내보고 알아내는 게 아니라 눈으로 확인하는 질문이에요.
세그먼트는 그래서 두 가지 역할을 해요: 캠페인의 오디언스, 퍼널 분기의 조건, 그리고 그 자체로 트리거 — segment_enter는 누군가 조건에 해당하는 순간 실행을 시작합니다.
- 1태그
tags contains "regular" - 2속성
attrs.total_orders >= 3— 여러분의 필드, 여러분이 붙인 이름이에요. - 3동작최근 90일간
order.paid이벤트가 없어요. - 4동의실제로 쓸 수 있는 이메일 근거예요. 근거가 없는 연락처는 개수에 포함되지 않아요. 어차피 보낼 수 없으니까요.
- i미리보기412명의 연락처가 나열되어 있어요. 발송 시점에 다시 집계됩니다. 세그먼트는 질문이지 스냅샷이 아니니까요.
SQL로 컴파일개수는 캐시, 답은 실시간
서프레션과 확인 시점
서프레션은 프로젝트 범위와 전역으로 존재해요: 하드 바운스, 불만 접수, 수신 거부, 수동 등록, 역할 주소. 발송 시점에 확인되고, 그다음 발송 서비스 내부에서 한 번 더 확인돼요.
두 번째 확인이 실제 일을 해요. 3일 대기가 있는 퍼널이라면 누군가 수신 거부할 수 있는 3일의 창이 있는 셈인데, 메시지가 큐에 들어갈 때 서프레션만 확인한 시스템은 그래도 메일을 보내버려요. 발송 시점에 확인하는 것이 수신 거부를 존중하는 것과 기록만 하는 것의 차이예요.
삭제도 같은 방식으로 동작해요: 삭제 요청은 여기서 연락처와 메시지 이력을 제거하고, 가족이 쓰는 것과 같은 내부 경로를 통해 사본을 보유한 모든 형제 서비스에 도달해요. 요청할 곳은 한 곳, 일어나는 일은 하나예요.