Service operation
로그인, 보안, 결제, entitlement처럼 사용자가 요청한 기능을 제공하는 목적이다.
필요성·비례성·적용 근거를 법무와 확인하며, analytics 동의를 기능 사용의 전제처럼 묶지 않는다.분류: Layer 13 - Product Engineering & Growth Systems
Product Engineer는 제품 개선을 위해 사용자 행동 데이터를 수집한다. 하지만 모든 데이터를 모으면 좋은 제품이 되는 것이 아니다. 어떤 데이터가 필요한지, 어떤 목적과 처리 근거로 사용하는지, 얼마나 오래 보관할지, 삭제나 열람 요청이 오면 어느 복제본까지 찾아갈지, analytics·RUM(Real User Monitoring, 실제 사용자 모니터링)·billing·support 경로에 민감한 값이 섞이지 않는지를 lifecycle 전체에서 설계해야 한다.
Privacy, Consent & Product Data Governance는 제품 데이터가 수집되는 순간부터 변환·사용·공유·보존·삭제되는 순간까지, 목적과 권한과 책임을 설명 가능하게 유지하는 제품·엔지니어링 역량이다.
제품 데이터를 의사결정에 신뢰하려면 먼저 사용자가 그 처리 방식을 신뢰할 수 있어야 한다. 최소수집, 동의, 보존, 삭제, 접근 통제는 제품 학습 루프 밖의 승인 절차가 아니라 그 루프가 성립하는 조건이다.
여기서 privacy(프라이버시) 는 사람에 관한 데이터 처리가 그 사람에게 예상 가능하고 적절한 범위에 머물도록 하는 문제다. security(보안) 는 허가받지 않은 접근·변조·유출을 막는 문제다. 암호화된 고객 이메일도 목적 없이 영구 보관하면 privacy 문제이고, 목적이 정당한 데이터도 공개 버킷에 놓이면 security 문제다. 둘은 겹치지만 서로 대신하지 않는다.
Data governance(데이터 거버넌스) 는 수집을 무조건 허용하거나 금지하는 문서가 아니다. 누가 어떤 목적의 데이터를 결정하고, 어느 시스템이 보유하며, 누가 접근할 수 있고, 언제 변환·삭제하며, 그 사실을 어떻게 검증할지를 연결하는 의사결정 구조다.
초기 제품에서는 클릭 이벤트, page view, error log, support note를 넉넉히 모아 두면 나중에 답을 찾을 수 있다고 생각하기 쉽다. 그러나 track() 한 번은 한 행만 만들지 않는다. 브라우저 SDK(Software Development Kit, 외부 기능을 붙이는 개발 도구 모음), 수집기, queue, analytics SaaS(Software as a Service, 서비스형 소프트웨어), warehouse, 대시보드 extract, 오류 알림에 같은 값의 복제본을 만들 수 있다.
수집 뒤에 마스킹하면 최초 payload와 전송 로그는 이미 남았을 수 있다. 대시보드에서 열을 숨겨도 warehouse 권한과 삭제 범위는 줄지 않는다. 계정 DB(Database, 데이터베이스)에서 사용자를 삭제해도 무작위처럼 보이는 user_id가 support ticket, 결제 고객 ID, IP(Internet Protocol, 인터넷 통신 규약) 주소와 다시 연결되면 그 사람의 기록은 계속 식별 가능하다.
그래서 핵심 철학은 먼저 많이 모으고 나중에 통제하는 것에서 답할 질문과 허용된 처리를 먼저 정하고, 가장 덜 민감한 형태만 lifecycle에 흘려보내는 것으로 바뀐다. GDPR 제25조의 data protection by design and by default도 보호 원칙을 설계 시점과 기본 설정에 반영하도록 요구한다. 다만 이 조항의 직접 적용 여부와 구체적 조치는 관할 및 위험 평가에 따라 판단해야 한다.
제품 질문 -> 목적과 적용 정책 -> 수집 데이터와 식별 수준 -> 허용된 destination -> 사용·결합·접근 권한 -> 보존 또는 익명화 기준 -> 열람·정정·삭제·철회 전파 -> 증거와 다음 설계 변경Governance가 실패하면 세 가지 신호가 함께 나타난다.
Personal data(개인 데이터 또는 개인정보) 는 식별되었거나 식별 가능한 자연인과 관련된 정보다. GDPR 제4조는 이름뿐 아니라 식별번호, 위치 데이터, online identifier 등으로 직접 또는 간접 식별 가능한 정보도 포함한다. 이 문서에서는 특정 법률의 번역어가 필요한 곳 외에는 쉬운 표현인 개인 데이터를 사용한다.
Direct identifier(직접 식별자) 는 그 값 자체가 특정 사람을 바로 가리키는 이름, 개인 이메일 주소, 전화번호 같은 값이다. 반면 IP 주소, cookie ID, 기기 특성, 정확한 시각과 희귀한 행동의 조합은 단독으로 이름을 말하지 않아도 사람을 구별하거나 다른 데이터와 연결할 수 있는 간접 식별자가 될 수 있다.
PII(Personally Identifiable Information, 개인 식별 정보)도 실무에서 자주 쓰지만, 모든 관할에서 personal data와 정확히 같은 법률 범위를 뜻하는 보편 용어는 아니다. 따라서 PII 없음이라는 체크 하나보다 누구와 연결 가능한지, 누가 연결 키를 갖는지, 어떤 결합이 가능한지를 기록하는 편이 안전하다.
Pseudonymous data(가명 데이터) 는 이름 같은 식별자를 토큰으로 바꾸고 재연결에 필요한 추가 정보를 분리한 데이터다. user_id = u_7f91만 보이는 analytics 행이 예다. 가명화는 노출 위험을 줄이는 유용한 safeguard(보호 조치)이지만, 연결표나 다른 데이터로 사람을 다시 알아볼 수 있다면 여전히 개인 데이터다. GDPR 제4조 제5항과 전문 제26항도 이 경계를 구분한다.
Anonymous data(익명 데이터) 는 합리적으로 사용될 가능성이 있는 수단을 고려해도 더는 사람을 식별할 수 없는 정보다. 이메일 열을 지우거나 hash했다고 자동으로 익명이 되지는 않는다. 이메일은 후보 목록을 같은 hash 함수에 넣어 비교할 수 있고, 안정적인 사용자 ID는 여러 달의 행동을 하나의 프로필로 묶을 수 있다.
EDPB는 2026-07-07 Guidelines 02/2026 on Anonymisation을 채택했고 2026-07-08 공개 의견수렴을 시작했다. 현재 문서는 2026-10-30까지 의견을 받는 public consultation draft(공개 의견수렴 초안) 이며 최종 지침이 아니다. 이 초안은 익명 여부가 정보를 다루는 entity(주체)에 따라 달라질 수 있다는 전제에서 두 접근을 설명한다.
이 문서의 정의와 아래 분류표는 확정된 보편 법률 정의를 새로 선언하는 것이 아니다. Product Engineering에서는 데이터가 이동하는 controller·processor·vendor·공개 recipient 중 관련 주체의 재식별 가능성이 남아 있으면 개인 또는 가명 데이터 통제를 유지하는 simplified safety policy 를 기본값으로 사용한다. 특정 recipient에게 실제로 익명인지에 관한 법적 결론은 최종 지침, 적용 관할, 전달 맥락과 해당 주체의 합리적 수단을 바탕으로 법무·개인정보 보호 책임자가 별도로 판단한다.
Aggregate data(집계 데이터) 는 여러 레코드를 합계·비율·분포로 요약한 결과다. 집계는 식별 위험을 줄일 수 있지만 익명과 동의어가 아니다. 서울, 희귀 브라우저, 새벽 03시, 결제 실패 1명처럼 집계 cell이 한 사람뿐이면 사실상 그 사람의 사건을 드러낼 수 있다. 작은 cell 억제, 범주 일반화, 시간 bucket 확대 같은 조치와 재식별 가능성 평가가 함께 있어야 한다.
작은 cell만 숨겨도 충분하다는 직관도 위험하다. Auxiliary data(보조 데이터) 는 공개 기록이나 다른 데이터셋처럼 공격자가 결합에 사용할 수 있는 정보다. 예를 들어 전체 11명의 결제 실패 건수와, 공개 정보로 이미 아는 10명을 제외한 겹치는 query 결과를 비교하면 남은 1명의 상태를 추론할 수 있다. 이렇게 서로 겹치는 집계 결과의 차이를 이용하는 differencing attack(차분 공격) 과 반복 공개는 단일 dashboard만 볼 때보다 많은 정보를 드러낸다.
NIST SP 800-226 최종판은 보조 데이터를 이용한 linking attack과 집계 통계로 원래 레코드를 재구성하는 위험을 설명한다. 따라서 small-cell suppression 하나를 익명성 보증으로 취급하지 않고, 공개 차원과 query 횟수, 공격자가 가진 보조 정보, 여러 release의 누적 효과를 함께 평가한다. Differential privacy(차등 개인정보 보호)는 이런 누적 privacy loss를 수학적으로 제한할 수 있는 한 선택지이지만, 모든 제품 dashboard에 자동 적용할 보편 해법은 아니다. 정확도·단위·privacy parameter 설계에는 별도 전문 검토가 필요하다.
| 형태 | 쉬운 예 | 다시 사람과 연결 가능한가 | 기본 판단 |
|---|---|---|---|
| 직접 식별 데이터 | dawn@example.com, 이름, 전화번호 | 값 자체로 가능 | 목적이 명확한 원본 시스템에 한정 |
| 가명 데이터 | 무작위 user_id, 별도 보관된 연결표 | 추가 정보나 결합으로 가능 | 개인 데이터로 취급하고 키·접근 분리 |
| 익명 데이터 | 재식별이 합리적으로 가능하지 않게 처리된 통계 | 합리적으로 가능하지 않아야 함 | 처리 방법과 공격 모델을 근거로 판단 |
| 집계 데이터 | 주간 workspace별 전환율 | cell 크기와 차원에 따라 다름 | 집계라는 이름만으로 익명이라 단정 금지 |
퀴즈
힌트: 변환 방법보다 누가 어떤 추가 정보로 원래 사람을 알아볼 수 있는지 본다.
자동으로 익명이 되지 않는다. 이메일 후보를 같은 방식으로 hash해 대조할 수 있고 다른 데이터와 결합할 수도 있다. 분석 목적에는 무작위 invite_id, role, source처럼 원문에서 유도되지 않은 최소 식별자와 속성이 더 적합할 수 있다.
| 분류 | 예시 | 기본 설계 방향 |
|---|---|---|
| Anonymous data | 재식별 위험 평가를 통과한 공개·공유 통계 | 평가한 entity·맥락·기술 상태를 기록하고 정기 재검토 |
| Aggregate data, anonymity 미확정 | 주간 feature 사용률, cohort conversion | 집계만으로 익명이라 보지 않고 cell·차분·보조 데이터 평가 |
| Pseudonymous identifier | user_id, workspace_id, session_id | 연결 키 분리, 접근·목적·보존 제한 |
| Direct identifier | email, name, phone | 원본 시스템에 한정하고 분석 전송은 기본 제외 |
| Sensitive content | 메시지 원문, 문서 내용, 인증 정보, 결제 상세 | analytics·RUM 전송 금지, 업무상 필요 경로만 허용 |
| Billing metadata | customer_id, subscription_id, invoice_id | 결제 역할 중심 접근, logging 최소화 |
| Technical diagnostics | error code, stack, device, browser | allowlist 수집, token·입력값·URL 마스킹 |
route, feature_key, event_name도 언제나 anonymous usage인 것은 아니다. 안정적인 session ID와 정확한 시각에 묶이면 한 사람의 행동 기록이 될 수 있다. 분류는 열 이름이 아니라 레코드 전체와 사용 맥락에 붙여야 한다.
Purpose limitation(목적 제한) 은 개인 데이터를 구체적이고 명시된 정당한 목적에 맞게 수집하고, 양립할 수 없는 새 목적으로 함부로 재사용하지 않는 원칙이다. 결제 영수증 발행을 위해 받은 주소를 별도 판단 없이 지역별 구매성향 광고에 쓰면 목적이 바뀐다. 데이터가 이미 있다는 사실은 새 사용의 허가가 아니다.
Data minimization(데이터 최소화) 은 무조건 0개를 모으라는 뜻이 아니다. 정한 목적에 적절하고 관련 있으며 필요한 범위로 제한하라는 원칙이다. 질문을 답하지 못할 정도로 데이터를 지우는 것도 좋은 설계가 아니다. 먼저 질문을 좁히고, 원문 대신 category·boolean·bucket으로 답할 수 있는지 보고, 그래도 필요한 식별 수준만 남긴다.
아래 표의 URL(Uniform Resource Locator, 웹 주소)은 화면 위치뿐 아니라 query에 식별자와 token을 포함할 수 있어 원문 전체가 분석 목적보다 민감해지기 쉬운 예다.
| 제품 질문 | 과한 수집 | 더 작은 표현 | 잃는 것과 선택 기준 |
|---|---|---|---|
| 유입 source별 활성화 차이는? | full referrer URL | normalized source enum | 세부 campaign 분석이 정말 필요할 때만 별도 허용 |
| 어느 form 영역에서 실패하는가? | 입력값 원문 | field_group + error_code | 재현에 원문이 필요하면 사용자가 선택해 support 경로로 제출 |
| 초대 전환이 role별로 다른가? | invited email | invite_role + domain_category | 개인별 follow-up이 목적이면 analytics와 다른 운영 시스템 사용 |
| editor 오류가 문서 유형별로 다른가? | 문서 본문 | document_type + error_code | 내용 기반 원인 분석은 제한된 진단 세션으로 분리 |
| 결제 실패 원인은 무엇인가? | card detail, provider 응답 원문 | provider error category | 분쟁 처리에 필요한 원본은 결제 경로에만 보존 |
Lawful basis(적법한 처리 근거) 는 특정 목적의 개인 데이터 처리를 허용하는 법적 근거다. GDPR 제6조는 consent(동의), contract(계약 이행에 필요한 처리), legal obligation(법적 의무), vital interests(중대한 이익), public task(공적 업무), legitimate interests(정당한 이익)라는 여러 근거를 둔다. 민감정보에는 제9조의 추가 조건이 필요할 수 있다.
이 목록은 모든 나라에 그대로 적용되는 제품 분류표가 아니다. Essential, analytics, diagnostics도 법적 근거가 아니라 제품 목적의 이름이다. 예를 들어 로그인 session을 essential이라 부른다고 자동으로 계약 근거가 성립하지 않고, 오류 진단을 legitimate interests라고 적는다고 이익형량과 투명성 의무가 사라지지 않는다.
제품팀의 책임은 각 processing activity(처리 활동)에 다음 사실을 제공하는 것이다.
법무·개인정보 보호 책임자는 이 사실과 적용 법률을 바탕으로 적법 근거, 고지, 이익형량, 동의 요건, 데이터 처리계약, 국외 이전 등 법률 판단을 확정한다. 엔지니어가 lawful_basis = consent 값을 임의로 고르는 것도, 법무가 실제 데이터 흐름 없이 문구만 승인하는 것도 충분하지 않다.
Consent(동의) 는 동의를 처리 근거로 선택한 경우 당사자가 자유롭게, 구체적으로, 충분한 정보를 받고, 모호하지 않은 적극적 행동으로 허용 의사를 표시하는 것이다. GDPR 제7조는 동의 사실을 입증할 수 있어야 하고, 철회가 동의만큼 쉬워야 한다고 규정한다.
따라서 하나의 analytics=true boolean만으로는 부족할 수 있다. 최소한 subject, purpose, policy version, jurisdiction 또는 적용 정책, 상태, 결정 시각, 수집 경로를 재현할 수 있어야 한다. 목적을 product analytics, personalized marketing, session replay처럼 나눠야 하는지는 적용 법률과 실제 처리 차이에 따라 정한다.
동의 철회는 과거의 유효한 처리를 자동으로 불법으로 만들거나 모든 데이터의 즉시 삭제와 항상 같은 명령이 되는 것은 아니다. 반대로 철회 뒤 새 수집을 계속해도 된다는 뜻도 아니다. 앞으로의 수집 중단, 이미 수집한 데이터의 후속 처리, 다른 근거로 보존해야 하는 데이터, 삭제 요청을 별도 상태 전이로 모델링해야 한다.
또한 브라우저나 기기에 정보를 저장하거나 읽는 행위에는 GDPR 외에 ePrivacy Directive(전자통신 프라이버시 지침)와 각국 이행법 같은 별도 규칙이 적용될 수 있다. cookie가 아니어도 local storage, tracking pixel, 링크 추적, 일부 SDK 동작이 검토 대상이 될 수 있음을 EDPB의 2024년 최종 Guidelines 2/2023이 설명한다. first-party 또는 RUM이라는 기술 이름만으로 면제 여부를 단정하지 않는다.
로그인, 보안, 결제, entitlement처럼 사용자가 요청한 기능을 제공하는 목적이다.
필요성·비례성·적용 근거를 법무와 확인하며, analytics 동의를 기능 사용의 전제처럼 묶지 않는다.제품 사용 흐름과 개선 질문을 위해 행동 데이터를 처리하는 목적이다.
관할과 구현에 따라 동의 등 적절한 근거와 저장·접근 기술 규칙을 별도로 확정한다.variant 노출과 outcome을 연결해 변경 효과를 비교하는 목적이다.
assignment 자체, 분석 수집, 개인화가 각각 같은 근거인지 분리해 검토한다.성능, 오류, 안정성을 개선하기 위해 실제 환경의 기술 신호를 처리하는 목적이다.
필수성이라는 라벨보다 payload, sampling, 식별 기간, 브라우저 저장·접근을 구체적으로 검토한다.정책 문서 하나는 복제본을 지우지 못한다. Governance는 처리 활동과 실제 데이터 흐름을 연결해야 작동한다.
Data lifecycle(데이터 생명주기) 은 데이터의 수집, 생성, 변환, 사용, 공유, 보존, 폐기까지의 전체 흐름이다. Data lineage(데이터 계보) 는 특정 필드나 레코드가 어디서 생겨 어떤 변환을 거쳐 어느 destination과 파생 테이블로 갔는지 추적하는 연결 정보다. table-level lineage만으로는 email이 email_hash로 변환되어 export에 들어간 사실을 놓칠 수 있으므로 민감 필드는 column 또는 property 수준까지 내려가야 한다.
Browser / Server endpoint / Support form | collect: purpose + policy + schema vEvent router ---------> blocked payload quarantine | +--> Product analytics --> warehouse model --> aggregate dashboard +--> RUM/error vendor ---> alert / sampled replay +--> Billing system -----> invoice / entitlement audit +--> Support system -----> ticket / attachment | v retention / rights request / deletion propagation이 흐름을 구현하는 최소 단위는 processing record(처리 활동 레코드) 다. 법률상 기록 의무의 정확한 형식과 면제 여부는 별도 판단이지만, 엔지니어링 관점에서는 다음 필드를 연결해야 한다.
| 필드 | 답해야 하는 질문 |
|---|---|
purpose_id | 이 데이터로 어떤 제품·운영 질문을 해결하는가 |
data_subject와 identity_keys | 누구에 관한 데이터이며 어떤 키로 찾을 수 있는가 |
data_elements와 privacy_class | 어떤 원문·가명·집계 필드를 처리하는가 |
lawful_basis_review와 policy_version | 어느 관할 판단과 승인 버전을 따르는가 |
producer -> transform -> destination | 어디서 생겨 어떤 파생물과 vendor로 이동하는가 |
owner와 access_policy | 누가 변경을 승인하고 누가 원문을 볼 수 있는가 |
retention_rule와 deletion_action | 언제 삭제·익명화·보존하며 어떤 예외가 있는가 |
evidence | 배포·접근·삭제가 정책대로 작동했음을 무엇으로 검증하는가 |
Lineage는 예쁜 diagram보다 영향 범위를 계산하는 인덱스여야 한다. invited_email을 금지했을 때 어느 SDK와 warehouse model이 깨지는지, user_id 삭제 요청이 어느 vendor ID로 번역되는지, consent policy version을 바꿨을 때 어느 collector를 재배포해야 하는지를 찾을 수 있어야 한다.
Tracking plan에는 이벤트 이름과 타입뿐 아니라 purpose, privacy class, destination, retention, 삭제 동작이 있어야 한다. 아래 기간은 가상 제품의 정책 예시이며 법적 권고값이 아니다. 실제 기간은 질문의 분석 window, 계약·분쟁·회계 의무, 관할 법률, 위험을 근거로 정한다.
| Event | Property | Privacy class | Required | Example retention | Notes |
|---|---|---|---|---|---|
invite_created | workspace_id | pseudonymous id | yes | 24 months | internal random id, 연결표 분리 |
invite_created | invite_role | aggregate-friendly usage | yes | 24 months | enum |
invite_created | invited_email | direct identifier | no | no collect | raw email 금지 |
frontend_error | error_code | diagnostics | yes | 90 days | stack·입력 원문 기본 제외 |
checkout_completed | subscription_id | billing metadata | yes | restricted | 결제 역할만 접근, 기간은 별도 정책 |
24 months가 필요한 이유를 아무도 설명하지 못한다면 숫자는 정책이 아니라 관성이다. 반대로 13개월 cohort를 비교해야 하는데 30일 뒤 식별 가능한 이벤트를 모두 지우면 질문을 답할 수 없다. 이때 선택지는 원문 보존 연장이 아니라 월별 익명 집계의 생성, 더 짧은 식별 window, 제한된 research dataset 등도 있다.
퀴즈
힌트: 분석에 필요한 것은 개인 식별자가 아니라 흐름의 상태와 결과일 수 있다.
email은 직접 식별자라 SDK, queue, analytics 도구와 warehouse에 넓게 복제될 수 있다. 초대 성공률에는 무작위 invite_id, invite_role, source, seat_limit_state로 충분한 경우가 많다. 개인별 지원이 필요하면 접근이 제한된 운영 시스템에서 별도 목적과 정책으로 조회한다.
가상의 협업 제품이 L13 canonical 지표인 new workspace 7-day activation_rate를 개선한다고 하자. 한 달에 신규 workspace 10,000개, 초대 40,000건, frontend error 200,000건, billing event 8,000건, support ticket 1,000건이 생긴다. 수치는 규모감을 위한 예시이지 보편 기준이 아니다.
이 예시의 activation contract는 upstream과 같은 ITT(Intention-to-Treat, 실제 진입 여부와 관계없이 시작 집단 전체를 유지하는 분석) 방식이다. Cohort enrollment는 분석 기간 [start_at, end_at)에 production에서 workspace_created가 최초로 발생하고 creator가 admin인 신규 workspace로 고정한다. 분모는 생성 시점에 is_internal = false, is_test = false, is_automated = false인 eligible unique workspace다. 사전에 region·plan 조건을 선언했다면 같은 생성 시점 값을 사용한다.
분자는 같은 workspace_id에서 생성 뒤 7일 안에 invite_created가 발생하고, 그 created와 같은 invite_id 의 invite_accepted가 이어진 unique workspace다. UI modal뿐 아니라 API·integration 등 정상 entry point도 인정하고 workspace당 최대 한 번 센다. 결과가 나쁘거나 이후 해지·삭제·비활성 상태가 되었다는 이유로 cohort에서 제외하지 않는다. Outcome을 본 뒤 제외 조건을 추가하면 selection bias가 생긴다.
첫 공동 작업 완료는 초대 수락보다 실제 가치에 가까운 더 강한 별도 outcome 후보다. 하지만 이 예시에서는 event trigger, 분모, time window, unique unit을 별도 계약하지 않았으므로 activation numerator에 섞거나 별도 metric처럼 수치화하지 않는다.
초대받은 사람의 이메일 원문이나 초대 메시지 내용은 이 activation rate 계산에 필요하지 않다. 팀은 다음 결정을 처리 활동 레코드와 tracking plan에 함께 남긴다.
[start_at, end_at) production 최초 workspace_created, creator adminis_internal/is_test/is_automated = false와 사전 region·plan 조건을 만족한 unique workspaceinvite_created -> same invite_id invite_accepted를 충족한 unique workspaceworkspace_created부터 7일workspace_id, 같은 초대를 잇는 invite_iddomain_event_id; 누락 row는 quarantineworkspace_created + 7일이 지나지 않은 cohort는 실패로 세지 않고 보류invite_role, source, seat_limit_stateProduct analytics는 canonical 계약에 맞춰 workspace_created, invite_created, invite_accepted를 권위 있는 server event로 수집한다. 각 canonical server event는 transaction/outbox에서 한 번 발급해 재시도에도 유지하는 domain_event_id가 필수이며, ingestion은 이 값으로만 중복을 제거한다. 값이 누락된 row는 invite_id 같은 추정 key로 합치지 않고 quarantine dataset으로 분리한다. invite_created와 invite_accepted는 같은 invite_id로 join하고, 지표 계산은 eligible workspace와 7일 window를 명시한다.
workspace_created + 7일이 지나지 않은 최근 workspace는 아직 수락할 시간이 남은 immature cohort(미성숙 cohort) 다. 이를 실패로 분모에 확정하지 않고 window가 끝날 때까지 보류하거나 provisional이라고 명시한다. Event router는 허용된 property만 통과시키고 목적·policy version·schema version을 붙인다. 안정적인 workspace_id는 가명 데이터이므로 분석가가 email 연결표를 볼 수 없게 역할을 분리한다.
RUM은 실제 브라우저의 성능·오류를 관찰한다. URL은 /invite/:inviteId라는 route template으로 바꾸고 query string은 버린다. form state 대신 field_group=invitee, error_code=NETWORK_TIMEOUT을 보내며, 전체 session을 식별할 필요가 없다면 짧은 회전 ID와 sampling을 사용한다.
Billing은 plan과 seat entitlement를 판단하려고 subscription_id, invoice, 결제 상태를 보유한다. 초대 funnel에는 seat_limit_state=available|reached만 전달하고 invoice 원문과 결제 provider payload는 보내지 않는다. 법적·계약상 보존이 필요한 billing record와 제품 analytics의 보존기간은 같을 이유가 없다.
Support는 사용자가 직접 설명한 문제와 첨부파일을 받을 수 있다. 이 데이터는 맥락상 가장 풍부하고 예측하기 어렵다. ticket form에서 제출 전 고지와 민감정보 경고를 제공하고, 첨부파일 malware scan, 제한된 queue, redaction(가림 처리), ticket 종료 후 별도 retention을 적용한다. support note를 자동으로 analytics property로 복사하지 않는다.
| 계열 | 필요한 최소 데이터 | 피해야 할 결합 | 대표 owner |
|---|---|---|---|
| Analytics | 가명 workspace·invite ID, event, enum | email 연결표, support 원문 | Product data owner |
| RUM | route template, 성능값, error code, 짧은 session | full URL, form state, auth header | Frontend/Reliability owner |
| Billing | provider·subscription ID, 금액·상태, 감사 기록 | card detail의 광범위한 노출, analytics 원문 복제 | Billing owner |
| Support | ticket 목적에 필요한 설명과 제한된 첨부 | 전체 직원 검색, 학습 데이터 자동 전용 | Support operations owner |
브라우저는 UI(User Interface, 사용자 인터페이스) toggle 자체를 진실의 원본으로 삼지 않고 서버가 발급한 policy snapshot을 읽는다. event router는 purpose_id, 적용 정책, consent 또는 다른 승인 상태를 보고 destination을 결정한다. 분석 수집이 허용되지 않은 사용자에게도 초대 생성과 결제 같은 제품 기능은 정상 동작해야 한다.
invite transaction ----------> primary DB / security audit | +-- policy allows analytics --> analytics collector +-- policy blocks analytics --> no analytics payload
frontend error +-- permitted minimum diagnostics --> sampled RUM collector +-- otherwise ----------------------> local recovery only이 분리는 필수 기능이니 모든 telemetry도 필수라는 오해를 막는다. 보안 audit, 계약 이행, 제품 분석, session replay는 payload가 비슷해도 목적과 근거가 다를 수 있다.
workspace_id는 analytics vendor의 distinct_id, warehouse의 workspace_sk, support tool의 organization ID로 이름이 바뀐다. 단순 table 목록만 있으면 같은 사람·조직을 찾지 못한다. lineage에는 변환 규칙과 vendor delete/export key를 함께 둔다.
app.workspace_id -> router.workspace_id -> analytics.distinct_id -> warehouse.workspace_sk -> mart_invite_funnel.workspace_sk
app.user_id -> identity_map.analytics_distinct_id -> identity_map.rum_user_key -> identity_map.support_contact_id연결표는 정보주체 권리 요청과 삭제 전파에 필요하지만 그 자체가 재식별 능력을 높인다. 따라서 일반 분석 역할에서 분리하고, privacy operation service 같은 좁은 주체만 목적 제한된 job으로 읽게 한다.
가상 정책에서 analytics 가명 이벤트는 24 months, RUM error는 90 days, support ticket은 종료 뒤 12 months로 정했다고 하자. billing record는 거래·세무·분쟁 관련 적용 의무에 따라 별도 기간을 둔다. 이 숫자들은 다음 질문의 답과 함께 있어야 한다.
월별 job이 expires_at을 계산해도 vendor export나 오래된 materialized view가 빠지면 실제 lifecycle은 닫히지 않는다. 삭제 건수만 보지 말고 대상 대비 완료율, 가장 오래된 만료 레코드 나이, destination별 실패 queue를 관찰한다.
이 문서에서 SAR(Subject Access Request) 또는 DSAR(Data Subject Access Request, 정보주체 열람 요청) 는 GDPR 제15조에 따라 본인에 관한 개인 데이터를 처리하는지 확인하고, 처리 중인 데이터와 목적·범주·수신자·보존 정보 및 사본에 접근하려는 요청만 가리킨다. 정정·삭제·처리 제한·반대 등 다른 권리까지 DSAR라고 묶지 않는다.
이들을 포괄할 때는 data subject rights request(정보주체 권리 요청) 라고 부른다. 어떤 권리와 기한이 적용되는지는 관할과 요청 내용에 따라 다르다. GDPR 제12조는 제15조부터 제22조의 권리 요청에 원칙적으로 접수 후 1개월 안에 조치 정보를 제공하도록 하고, 복잡성과 요청 수에 따라 추가 2개월 연장 가능성과 통지 조건을 둔다. 이것을 모든 나라·모든 요청의 공통 SLA(Service Level Agreement, 서비스 수준 약속)로 복사해서는 안 된다.
이 사례에서 access request를 처리하려면 다음 판단이 필요하다.
user_id를 identity map의 analytics·RUM·support key로 변환한다.집계 dashboard만 보고 개인 데이터 없음이라고 답하면 raw event와 vendor copy를 놓친다. 반대로 식별할 필요가 없던 익명 통계를 SAR/DSAR 대응을 위해 다시 개인과 연결하는 것도 잘못된 설계다. 익명화가 실제로 성립했다면 연결 키를 보존하지 않는 것이 핵심이다.
사용자가 계정 삭제를 요청했다고 하자. 제품팀은 계정 상태를 즉시 deletion_pending으로 바꾸고 새 analytics 수집을 차단한다. privacy job은 lineage와 identity map으로 primary DB, analytics vendor, RUM vendor, warehouse, support tool에 삭제 또는 검토 요청을 보낸다.
그러나 모든 레코드를 같은 방식으로 지우지는 않는다. 한 번의 SQL DELETE로 아래 경계를 모두 해결할 수 없다는 뜻이다.
GDPR 제17조의 삭제권에도 예외가 있으며 제19조는 일정한 경우 정정·삭제·처리 제한을 수신자에게 알리는 의무를 둔다. 따라서 delete everything과 법 때문에 보존 중 하나를 코드에 고정하지 않는다. 제품팀은 데이터별 가능한 동작과 증거를 만들고, 법무가 적용 예외와 보존 범위를 승인한다.
삭제 완료 evidence는 원문 개인 데이터를 다시 남기는 로그가 아니다. request_id, destination, action, policy version, 완료 시각, 오류 category, 승인 주체처럼 재처리에 필요한 최소 메타데이터를 보존한다. 삭제 audit log에 email과 삭제된 payload를 그대로 복사하면 삭제 시스템이 새 개인정보 저장소가 된다.
한 사용자의 데이터가 네 계열, 각 두 destination에만 있어도 최대 8개 위치를 확인해야 한다. 여기에 raw·staging·mart 세 층이 있으면 warehouse만 3개 복제 범위를 만든다. 하루 deletion request가 100건이고 destination별 성공률이 99%여도 독립 실패라고 단순 가정하면 여덟 destination이 모두 성공할 확률은 0.99^8 ≈ 92.3%다. 즉 요청 약 8건은 적어도 한 곳의 재시도가 필요할 수 있다.
이 계산은 실제 SLA 예측이 아니라 fan-out이 신뢰도를 어떻게 깎는지 보여 주는 사고 실험이다. destination을 줄이고, idempotency key로 재시도를 안전하게 만들고, 완료 상태를 중앙에서 추적해야 하는 이유가 여기에 있다.
Privacy setting은 고지 화면이 아니라 데이터 경로를 바꾸는 제품 기능이다.
| UX 결정 | Governance 질문 | 구현 계약 |
|---|---|---|
| analytics consent toggle을 제공한다 | 목적별 선택과 적용 관할을 어떻게 표현하는가 | policy state가 event router와 허용 destination을 제어한다 |
| consent를 철회한다 | 새 수집 중단과 기존 데이터 처리를 어떻게 나누는가 | producer 차단 시각, 후속 처리 규칙, proof를 남긴다 |
| account deletion을 요청한다 | 무엇이 삭제·익명화·보존되는가 | deletion job이 primary DB, warehouse, analytics, RUM, support를 추적한다 |
| session replay를 일부 화면에서 끈다 | 민감 화면과 동적 content를 어떻게 분류하는가 | route-level capture policy와 element masking을 둔다 |
| privacy setting을 workspace 단위로 둔다 | user 선택과 workspace 정책이 충돌하면 무엇이 우선인가 | 더 제한적인 경로, 역할별 예외, audit 가능한 resolution rule을 정한다 |
User-level consent와 workspace-level policy는 같은 축이 아니다. 조직 관리자가 analytics를 허용해도 개인에게 적용되는 선택과 법적 근거를 덮을 수 있는지는 별도 판단이다. 반대로 한 사용자의 철회가 공동 workspace의 모든 비개인 집계를 지워야 한다고 단정할 수도 없다. UI는 이 차이를 숨기지 말고 실제 resolution rule과 같은 결과를 보여 줘야 한다.
RUM과 오류 수집은 개발자가 schema에 넣지 않은 값도 자동 context로 붙일 수 있다.
따라서 RUM은 denylist보다 allowlist를 기본으로 한다. route parameter와 query string을 수집 전에 template으로 바꾸고, 구조화된 error_code를 우선하며, user ID가 필요하지 않은 성능 집계는 짧은 session 또는 무식별 sample로 분리한다. session replay는 일반 RUM과 별도 목적·sampling·접근·보존 정책을 두는 편이 경계를 설명하기 쉽다.
시나리오
frontend_error 이벤트에 URL, component stack, form state, network request metadata가 함께 들어간다. checkout과 invite flow의 디버깅은 쉬워졌지만 full URL의 invite token, form email, provider response 일부도 vendor로 전송될 수 있다.
이 수집의 목적별 최소 payload, browser storage/access 규칙, 가명 ID 회전, masking 회귀 테스트, retention, support·billing 접근 분리를 어떻게 설계할 것인가?실패 신호는 PII scan 0건 하나로 끝나지 않는다. 새 route 배포 뒤 URL cardinality가 급증하거나, payload 평균 크기가 갑자기 커지거나, masking selector 적용률이 내려가거나, consent 거부 집단에서 vendor request가 관찰되면 데이터 경계가 깨졌다고 본다.
Access control(접근 통제) 은 로그인 여부만이 아니라 누가 어떤 목적과 기간으로 어느 식별 수준을 볼 수 있는지 제한하는 메커니즘이다. raw event, identity map, billing record, support attachment는 같은 employee 역할에 열어서는 안 된다.
| 데이터 | 적합한 접근 모델 | 피해야 할 모델 |
|---|---|---|
| 검증된 익명 지표 | 평가한 공유 맥락 안에서 넓은 read | 다른 recipient에서도 익명이라고 단정 |
| 익명성 미확정 집계 | 제한된 read, cell·query·export 통제 | 집계나 큰 집단이라는 이유로 공개 |
| 가명 analytics event | 분석 역할, row·column 정책, 시간 제한 export | 전사 공용 service account |
| identity map | privacy operation service와 소수 승인자 | 분석가의 상시 조회 |
| billing metadata | billing·finance 역할, 목적별 view | support ticket에 provider 원문 붙이기 |
| support attachment | ticket 담당자의 case-bound access, 만료 | 전체 직원 검색과 무기한 URL |
RBAC(Role-Based Access Control, 역할 기반 접근 통제)은 출발점이지만, 민감 원문에는 ticket ID·목적·시간을 조건으로 한 JIT(Just-In-Time, 필요 시점에만 여는) access가 더 적합할 수 있다. Audit log(감사 로그) 는 누가 언제 무엇을 왜 조회·export·삭제했는지 남겨 오용과 정책 오류를 조사하게 한다. 감사 로그 자체도 개인 데이터와 보안 자산이므로 원문 payload 대신 대상 category와 승인 근거를 남기고 접근·보존을 제한한다.
선택 기준은 단순하다.
정확한 timestamp, 희귀 route, device fingerprint, 안정적인 session ID를 결합하면 한 사람을 골라낼 수 있다. 열 단위 scanner가 email을 찾지 못해도 레코드 단위 재식별 위험은 남는다.
목적이 모호하거나 거부해도 같은 SDK request가 나가거나, 선택을 서비스 이용과 불필요하게 묶거나, 철회가 어렵다면 UI 존재만으로 유효한 동의를 증명하지 못한다. 동의가 적절한 처리 근거인지도 먼저 확인해야 한다.
복호화 키나 대조 가능한 원본 집합이 있으면 다시 연결할 수 있다. 암호화와 가명화는 위험을 낮추는 보호 조치이지 데이터 범주를 자동으로 익명으로 바꾸는 주문이 아니다.
queue retry, warehouse snapshot, analytics vendor, support attachment, dashboard extract가 남을 수 있다. 반대로 법적 보존 근거가 있는 billing record까지 무조건 지우는 구현도 잘못될 수 있다. lineage와 데이터별 action이 필요하다.
한 명짜리 cell, 반복 query 차분, 외부 공개 정보와의 결합으로 개인 행동이 드러날 수 있다. 집단 크기, 차원 수, 공격자가 가진 보조 정보, export 범위를 함께 판단한다.
사용자는 문제 해결을 위해 원문과 첨부를 제공했을 수 있다. 이를 product analytics나 model training으로 전용하면 목적과 기대가 달라진다. 새 목적의 적합성, 근거, 고지, 최소화를 별도로 검토한다.
| 관찰 신호 | 의미 | 먼저 확인할 경계 |
|---|---|---|
| consent 철회 뒤 vendor request가 계속 발생 | UI 상태와 router 정책이 분리됨 | producer·SDK 초기화·server-side forwarding |
| 삭제 완료율은 100%인데 vendor에 사용자가 검색됨 | inventory 또는 identity mapping 누락 | destination lineage·vendor delete key |
| SAR/DSAR마다 수동 SQL과 개인 계정 export가 필요 | identity·owner·응답 계약이 없음 | processing record·자동 export 범위 |
| raw table 접근자는 적지만 CSV(Comma-Separated Values, 쉼표 구분 파일) export가 많음 | 접근 통제가 복제 이후를 다루지 못함 | download 권한·만료·watermark·audit |
unknown source와 full URL cardinality 급증 | minimization transform이 producer 변경을 놓침 | schema allowlist·route templating |
| retention job은 성공하지만 oldest record가 계속 늙음 | 일부 partition·derived table이 정책 밖임 | partition clock·materialized view·backup |
| 작은 cohort dashboard에서 1명 단위 값이 보임 | aggregate를 anonymous로 오해함 | cell suppression·dimension·export |
| support와 billing 직원이 서로의 원문을 검색 가능 | 역할이 목적 경계를 반영하지 못함 | purpose-bound view·JIT access |
이때 먼저 banner 문구나 dashboard label을 고치지 않는다. producer, identity transformation, destination, policy version, retention clock, access path를 따라가며 실제 처리 흐름을 고친다.
이 문서는 L13의 마지막 안전 경계다. Privacy는 출시 마지막의 법무 검사가 아니라 앞 단계의 질문과 데이터 설계를 되돌리는 feedback이다.
Product Analytics & Tracking Plan: event property에 purpose, privacy class, destination을 추가한다.Frontend Product Quality & RUM: RUM payload, browser storage/access, error context, session replay를 제한한다.Billing, Subscription & Entitlement: billing 원본과 analytics용 category의 접근·보존을 분리한다.Product Discovery & UX Flow: 더 적은 데이터로 답할 수 있도록 제품 질문과 privacy UX를 함께 설계한다.아래 출처는 2026-07-14에 상태와 링크를 확인했다. EU 자료는 GDPR 적용 맥락의 1차 법령·공식 지침이며 다른 관할의 보편 규칙으로 읽지 않는다.