본문으로 건너뛰기

삭제와 소거

삭제 요청을 기한 안에 처리하세요.

Tahoe에서 읽은 데이터를 조금이라도 저장한다면, 이 페이지는 기능이 아니라 의무를 설명합니다. Tahoe는 세 종류의 삭제 신호를 알려 주며, 각각 다르게 대응해야 합니다. 하나라도 놓치면 데이터의 소유자나 데이터에 담긴 당사자가 지워 달라고 요청한 데이터가 내 사본에 그대로 남습니다.

세 가지 신호

신호의미해야 할 일
삭제 이벤트 (예: applicant.deleted)Tahoe에서 레코드가 삭제되었습니다.해당 레코드의 사본을 삭제하세요.
applicant.unsubscribed본인이 연락받지 않기를 요청했습니다.연락을 멈추세요. 레코드는 그대로 두고 아웃리치만 멈추세요.
삭제(소거) 통지 (data_subject.* 이벤트와 GET /erasures)본인이 권리를 행사했거나, 삭제가 요구되었습니다.7일 안에 사본을 삭제하고, 그 사람에 대한 처리를 멈추세요.

삭제 이벤트

삭제 이벤트는 job.deleted, application.deleted, applicant.deleted, sourced_profile.deleted, list.deleted, list_membership.removed의 여섯 가지입니다.

페이로드에는 식별자만 담기며, 삭제된 데이터는 절대 담기지 않습니다. 삭제된 채용 공고, 지원서, 지원자, 소싱한 프로필 이벤트에는 reason도 함께 옵니다. 값은 user_deleted, workspace_deleted, data_subject_erasure, retention_expiry, legal_hold_release, provider_takedown(데이터 출처나 플랫폼이 삭제를 요구한 경우), suppression 중 하나입니다.

사유에 따라 할 일이 달라지지는 않습니다. 레코드를 삭제하세요. 사유는 기록해 두세요. 그래야 나중에 레코드가 왜 사라졌는지 설명할 수 있고, 요구에 따른 삭제와 본인의 요청을 구분할 수 있습니다.

삭제 핸들러
DELETIONS = {
    "job.deleted": "job",
    "application.deleted": "application",
    "applicant.deleted": "applicant",
    "sourced_profile.deleted": "sourced_profile",
    "list.deleted": "list",
    "list_membership.removed": "list_membership",
}


def handle_deletion(store, event):
    object_type = DELETIONS[event["type"]]
    item = event["data"]["object"]
    reason = item.get("reason")  # list events carry no reason

    # Delete for real. A soft delete that keeps the personal data in a table
    # that still answers queries is not a deletion.
    store.purge(object_type, item["id"])
    store.audit("deleted", object_type, item["id"], reason=reason)

수신 거부는 범위가 좁지만, 예외가 없습니다

applicant.unsubscribed는 보관을 멈추라는 뜻이 아니라 연락을 멈추라는 뜻입니다. 고객은 계속 파이프라인을 운영하므로 지원 레코드는 유지하되, 그 사람을 다시는 아웃리치 시퀀스에 넣지 마세요.

삭제 통지: 7일의 기한

이 API에서 가장 강한 신호입니다. 두 가지 경로로 전달됩니다. 삭제 통지 피드와 data_subject.suppression_applied, data_subject.erasure_completed 이벤트입니다.

삭제 통지
{
  "object": "erasure",
  "id": "ers_5Nx3jLm7Qd2s",
  "action": "suppression_applied",
  "reason": "data_subject_erasure",
  "workspace_id": "wsp_4Kd8sPm2Qx7L",
  "resources": [
    { "object": "sourced_profile", "id": "cnd_8Fj3kLm2Qd7s", "workspace_id": "wsp_4Kd8sPm2Qx7L" }
  ],
  "action_required": "cease_processing_and_delete_your_copy",
  "deadline_at": "2026-09-14T14:02:11.408Z",
  "destruction_pending": true,
  "destruction_reason": "retention_floor",
  "at": "2026-09-07T14:02:11.408Z",
  "subject_identified": false
}

이 통지에서 알아 둘 네 가지:

  • deadline_at은 7일 뒤입니다. 이것이 주어진 기간입니다.
  • destruction_pending: true는 Tahoe 자체가 법정 보존 규정에 따라 아직 레코드를 보관해야 한다는 뜻입니다. 일부 고용 기록은 최대 4년까지 보관해야 합니다. 그래도 내 기한은 바뀌지 않습니다.
  • workspace_id: null은 통지가 특정 워크스페이스에 속하지 않는다는 뜻입니다. 그 사람의 데이터를 가진 모두에게 적용되므로 모든 키로 전달됩니다. 삭제 통지를 워크스페이스로 거르지 마세요.
  • 처리 중단 통지 없이 올 수도 있습니다. Tahoe가 레코드를 바로 파기할 수 있으면 erasure_completed만 받습니다. 어느 쪽이든 먼저 도착한 통지에 따라 삭제하세요.
삭제 통지 이행하기
def honor_erasure(store, notice):
    """Delete our copy and record that we did, within the 7-day window."""
    for resource in notice["resources"]:
        store.purge(resource["object"], resource["id"])
        # A tombstone that keeps the person OUT: a later sync must not bring
        # them back the next time they appear in a list. Store the handle
        # and nothing else about them.
        store.suppress_forever(resource["object"], resource["id"])

    store.audit(
        "erased",
        notice_id=notice["id"],
        reason=notice["reason"],
        deadline_at=notice["deadline_at"],
    )


def on_data_subject_event(store, event):
    # data_subject.suppression_applied and data_subject.erasure_completed
    # carry the same notice as GET /erasures, in data.object.
    honor_erasure(store, event["data"]["object"])

삭제 기록(툼스톤)을 남기고, 절대 만료시키지 마세요

올바른 순서로 따라잡기

리더가 멈춰 있었다면 삭제 통지 피드부터 읽으세요. 크기가 작고, 이벤트 워터마크와 별개로 자체 페이지를 넘기며, 뒤처졌을 때 가장 문제가 되는 피드입니다.

장애 후 따라잡는 순서
def catch_up(session, store):
    # Erasures first. Reading lists and the feed may write rows, so the list
    # of suppressed handles must be current BEFORE anything is written, or
    # you bring back someone who asked to be removed.
    consume_erasures(session, store)
    drain(store)

체크리스트

  • 변경 피드를 읽거나 웹훅을 받으세요. 삭제는 다른 경로로는 오지 않습니다.
  • 삭제 이벤트 여섯 가지를 모두 처리하세요. *.deleted 유형 다섯 가지와 list_membership.removed입니다.
  • 보내기 전마다 unsubscribed를 확인하세요.
  • 삭제 통지 피드를 하루에 한 번 이상 읽으세요.
  • suppression_applied를 받으면 erasure_completed를 기다리지 말고 삭제하세요. 레코드가 아직 남아 있다면 erasure_completed를 받았을 때도 삭제하세요.
  • 삭제 통지를 워크스페이스로 거르지 마세요.
  • 삭제한 핸들 목록을 영구히 보관하고, 절대 만료시키지 마세요.
  • 무엇을, 언제, 어떤 통지에 따라 삭제했는지 기록하세요.

관련 문서