서비스 초기에는 보통:
주문 1,000건
Audit Log 5,000건
Webhook 10,000건
Outbox 20,000건
정도라 관리가 어렵지 않다.
하지만 몇 년 지나면:
주문 수십만 건
Audit Log 수백만 건
Event 수천만 건
Export 파일 수천 개
AI Report / Artifact 누적
처럼 쌓일 수 있다.
문제는 단순히 저장 공간만 아니다.
예:
DB Size 증가
Backup 시간 증가
Restore 시간 증가
Index 크기 증가
Query 성능 저하
운영 화면 검색 부담
개인정보 보유 범위 증가
유출 사고 시 피해 범위 증가
즉 데이터 보관 정책은:
DB 최적화
만의 문제가 아니라:
운영
+
보안
+
복구
+
개인정보
전체 문제다.
Retention은:
데이터를 얼마 동안 보관할 것인가
를 정하는 정책이다.
예:
Application Log
30일
Outbox Event
90일
완료 Export File
30일
Audit Log
1년
주문 데이터
업무/법적 요구에 따라 별도
처럼 데이터 종류마다 다르게 정한다.
예를 들어:
Debug Log
와:
주문 이력
은 중요도가 완전히 다르다.
또:
Notification Provider Raw Response
와:
주문 상태 Audit
도 다르다.
따라서 먼저 데이터를 분류해야 한다.
현재 프로젝트 기준으로는 대략 다음처럼 나눌 수 있다.
1. Business Data
2. Operational Data
3. Audit Data
4. Event / Queue Data
5. Temporary Data
6. Artifact / File
7. Personal Data
예:
주문
상담
상품
신청 상태
고객 신청 내역
서비스의 핵심 업무 데이터다.
이 데이터는 무작정 자동 삭제하면 안 된다.
예:
Job 상태
WorkflowRun
ScheduleRun
Worker 상태
Deployment 기록
Reconciliation 기록
운영 추적을 위해 필요하지만 영구 보관할 필요는 없을 수 있다.
예:
누가 주문 상태를 변경했는가
누가 설정을 변경했는가
누가 Feature Flag를 켰는가
누가 수동 Retry를 했는가
운영 책임성과 사고 추적에 중요하다.
일반 로그보다 더 오래 보관할 수 있다.
예:
OutboxEvent
InboxEvent
WebhookEvent
Dead Letter
전달 안정성을 위한 데이터다.
영구 Event Store가 아니라면 일정 기간 후 정리할 수 있다.
예:
임시 Export 파일
Preview 파일
중간 생성 Artifact
Cache Data
임시 업로드
대부분 짧은 Retention이 적합하다.
예:
Excel Export
Markdown Report
첨부 파일
S3 Object
AI Output
DB Row와 실제 파일 수명주기를 같이 관리해야 한다.
예:
이름
전화번호
주소
생년월일
IP
상담 내용
주문 관련 개인정보
이 데이터는 단순히:
DB Size가 크니까 삭제
관점으로 보면 안 된다.
보관 필요성과 개인정보 최소화 원칙을 같이 봐야 한다.
PII는 일반적으로 개인을 식별하거나 식별 가능하게 만드는 정보다.
예:
이름
휴대폰 번호
주소
이메일
IP Address
고객 ID와 결합된 행동 정보
등이 포함될 수 있다.
실무에서는:
왜 수집했는가?
어디에 사용되는가?
얼마나 오래 필요한가?
삭제 가능한가?
익명화 가능한가?
를 같이 본다.
데이터도 하나의 생명주기를 가진다.
Collect
↓
Use
↓
Store
↓
Archive
↓
Anonymize / Delete
형태다.
처음 수집할 때부터:
이 데이터가 정말 필요한가?
를 묻는다.
필요하지 않은 개인정보는 아예 받지 않는 것이 가장 안전하다.
예:
분석 목적에:
고객 전화번호 전체
가 필요하지 않다면:
customerId
hash
통계 단위
정도로 대체할 수 있다.
보안에서 가장 강력한 전략 중 하나다.
수집 최소화
자체가 Retention 전략이다.
같은 전화번호가:
orders
audit_logs
outbox_events
application_logs
error_logs
analytics
에 모두 복제돼 있으면 위험하다.
예:
Outbox에는:
{
"orderId": "order_123"
}
만 저장하고,
전화번호가 필요하면 Worker가 필요한 시점에 Order를 조회한다.
전화번호가 바뀌거나 삭제 대상이 됐을 때:
여러 Event Payload까지 전부 찾아 삭제
할 필요가 줄어든다.
주 사용 DB에서 제거
하지만 별도 보관
데이터 자체 제거
다.
예:
2년 전 주문
을 관리자 목록에서 매일 검색할 필요는 없지만:
과거 문의
운영 감사
분쟁 확인
때문에 일정 기간 보관이 필요할 수 있다.
이 경우 Active DB와 Archive를 분리할 수 있다.
처음에는:
같은 PostgreSQL
+
Archived 상태
+
기간 필터
만으로도 충분할 수 있다.
Soft Delete:
삭제됐지만 DB에 Row 유지
Archive:
정상 데이터지만 일상 조회 대상에서 제외
이다.
ACTIVE
ARCHIVED
SOFT_DELETED
를 구분할 수 있다.
Soft Delete는:
실수 복구
운영 안전성
에는 좋다.
하지만:
삭제 후 수년간 그대로 보관
하면 실제 Retention 목적을 달성하지 못한다.
예:
ACTIVE
↓
SOFT_DELETED
↓
30일
↓
HARD_DELETE
형태를 둘 수 있다.
예:
주문 자체를 완전히 삭제
하면 과거 매출/운영 기록이 깨질 수 있다.
이런 경우 개인정보만 제거하고 업무 기록은 유지하는 방식이 더 적합할 수 있다.
예:
기존:
이름
홍길동
전화번호
010-1234-5678
주소
서울시 ...
익명화 후:
이름
삭제
전화번호
삭제
주소
삭제
orderId
유지
상품
유지
주문일
유지
할 수 있다.
이렇게 하면:
월별 판매량
기종별 주문 수
통신사별 통계
는 유지할 수 있다.
예:
customer_123
처럼 다른 식별자로 대체했지만 별도 Mapping을 통해 다시 원래 고객을 찾을 수 있다면 완전한 익명화와는 다르다.
전화번호를 단순 Hash하면:
가능한 전화번호 범위가 제한적
이므로 공격자가 사전 계산으로 추정할 수도 있다.
따라서:
Hash = Anonymous
라고 단정하면 안 된다.
예:
동일 고객 중복 여부
만 보고 싶다면:
salted hash
같은 방식이 유용할 수 있다.
하지만 이것 역시 보호해야 할 데이터로 보는 편이 안전하다.
예:
interface RetentionPolicy {
dataType: string;
retainForDays?: number;
action:
| 'ARCHIVE'
| 'ANONYMIZE'
| 'DELETE';
gracePeriodDays?: number;
}
나쁜 예:
if (createdAt < nowMinus90Days) {
delete();
}
여러 곳에서 90일이 반복되면 나중에 정책 변경이 어렵다.
예:
OUTBOX_EVENT
90일
EXPORT_FILE
30일
WORKFLOW_STEP_DETAIL
90일
처럼 한 곳에서 관리한다.
0928과 연결된다.
정책 변경:
90일 → 30일
은 엄청난 영향을 줄 수 있다.
잘못 바꾸면 수많은 데이터가 삭제될 수 있다.
예:
Actor
admin
Policy
EXPORT_FILE
Before
90 days
After
30 days
Reason
Storage optimization
을 기록한다.
나쁜 예:
DELETE FROM outbox_events
WHERE created_at < now() - interval '90 days';
한 번 실행으로 수백만 Row를 삭제할 수 있다.
예:
PLAN
↓
SCAN
↓
VALIDATE
↓
DELETE_BATCH
↓
VERIFY
↓
COMPLETE
형태로 만들 수 있다.
실제 삭제 전에:
대상 건수
가장 오래된 Row
가장 최근 대상 Row
예상 삭제량
을 확인한다.
Policy
OUTBOX_EVENT_90D
Candidates
12,451
Oldest
2026-01-01
Newest
2026-07-05
Estimated Size
340MB
정도다.
평소:
하루 삭제 1,000건
인데 갑자기:
250,000건
이 조회된다면 이상할 수 있다.
예:
expected
< 10,000
actual
250,000
이면:
MANUAL_REQUIRED
로 중단한다.
전체 Row의:
50%
를 한 번에 삭제하는 것도 이상할 수 있다.
예:
deleteRatio > 10%
이면 수동 확인하도록 할 수 있다.
예:
deleteCount > 50,000
OR
deleteRatio > 20%
이면 중단한다.
예:
status = PUBLISHED
publishedAt < cutoff
처럼 삭제 대상 조건이 명확해야 한다.
단순:
createdAt < cutoff
만 보면 아직 처리되지 않은 Event를 삭제할 수 있다.
삭제 가능:
PUBLISHED
90일 초과
삭제 금지:
PENDING
RETRY_PENDING
DEAD_LETTER
일 수 있다.
삭제 전에:
PROCESSED
상태인지 확인한다.
처리 중/실패 상태는 보존한다.
DLQ는 장애 분석에 중요하다.
예:
일반 Event
90일
DLQ
180일
처럼 정책을 다르게 할 수 있다.
예:
SUCCESS
90일
FAILED
180일
MANUAL_REQUIRED
삭제 금지
처럼 할 수 있다.
RUNNING
WAITING
COMPENSATING
같은 Active 상태를 날짜만 보고 삭제하면 안 된다.
예:
SUCCESS
FAILED
SKIPPED
같은 완료 상태만 대상으로 한다.
이게 중요하다.
Retention은 단순 날짜 SQL이 아니라:
이 데이터가 정말 업무적으로 끝난 상태인가?
를 확인해야 한다.
예:
Export DB Record
+
S3 Excel File
이 있다.
DB Row만 지우면 S3 파일이 남는 Orphan이 된다.
파일 삭제 성공 후 DB Update 전에 Worker가 죽을 수 있다.
DB에는:
AVAILABLE
인데 실제 파일은 없다.
예:
EXPIRED
↓
DELETE_FILE
↓
MARK_DELETED
처럼 상태를 나눈다.
S3 Delete 요청 후 Timeout.
실제로 파일이:
삭제됐는지
남아 있는지
모를 수 있다.
이 경우:
Object 존재 확인
후:
없음
→ DELETED
있음
→ Retry
로 복구한다.
AVAILABLE
EXPIRED
DELETE_PENDING
DELETING
DELETED
DELETE_FAILED
정도로 관리할 수 있다.
Presigned URL이 만료됐다고 S3 Object가 삭제되는 것은 아니다.
실제 Storage Cleanup 정책이 필요하다.
S3 같은 Storage는 일정 기간 후 자동 삭제 정책을 제공할 수 있다.
이런 경우 Application Cron보다 Storage Lifecycle이 더 단순할 수 있다.
Storage에서는 파일이 삭제됐는데 DB에는:
AVAILABLE
일 수 있다.
따라서 DB 상태 Reconciliation이 필요할 수 있다.
예:
S3 Lifecycle
30일 후 삭제
↓
주기적 Reconciler
↓
DB Artifact
DELETED
형태가 가능하다.
단순 파일 Retention은 Lifecycle이 편할 수 있다.
하지만:
특정 고객 삭제 요청
즉시 삭제
복잡한 조건
이면 Application Workflow가 필요할 수 있다.
예:
PostgreSQL
S3
Search Index
Backup
Log
Analytics
에 데이터가 있을 수 있다.
개인정보 종류별로:
어디에 저장되는가?
왜 저장되는가?
얼마나 보관하는가?
삭제 방법은 무엇인가?
를 알아야 한다.
| 데이터 | 위치 | 목적 | 보관 |
|---|---|---|---|
| 이름 | orders | 주문 처리 | 정책에 따름 |
| 전화번호 | orders | 고객 연락 | 정책에 따름 |
| 전화번호 | logs | 없어야 함 | 즉시 개선 |
| IP | lead | 유입 분석/중복 | 별도 정책 |
| Export | S3 | 관리자 다운로드 | 30일 |
이런 문서가 있으면 좋다.
예:
logger.info(req.body);
를 해두면 주문 Form 전체가 로그에 들어갈 수 있다.
로그에 처음부터:
전화번호
주소
이름
토큰
을 넣지 않는 것이 중요하다.
Retention을 짧게 하고 앞으로 Logging 정책을 수정한다.
단순히:
30일 후 없어지니까 괜찮다
가 아니라 생성 자체를 줄인다.
예:
{
"event": "order.created",
"orderId": "order_123",
"correlationId": "cor_1"
}
정도로 남긴다.
필요할 때 관리자 권한으로 실제 Order를 조회한다.
운영 로그가 개인정보 DB 역할을 하지 않게 한다.
현재 유입/중복 분석에 IP를 사용하더라도:
분석 목적
보관 기간
접근 권한
을 따로 정의하는 것이 좋다.
예:
ACTIVE
RETENTION_HOLD
ANONYMIZE_PENDING
ANONYMIZED
DELETE_PENDING
DELETED
같은 상태를 사용할 수도 있다.
일반 정책상 삭제 시점이 됐더라도 특정 사유로 일시 보존해야 하는 상황이 있을 수 있다.
이때:
retentionHold = true
인 Record는 Cleanup에서 제외한다.
모든 Record가:
혹시 필요할 수도 있으니까 Hold
가 되면 Retention 정책이 의미 없어진다.
예:
reason
createdBy
createdAt
expiresAt
을 기록한다.
누가:
삭제 예정 데이터를 왜 보존했는가?
추적할 수 있어야 한다.
예:
고객 삭제 요청
이 들어와도 업무/법적 보관 의무 때문에 모든 Record를 즉시 완전히 지울 수 없는 경우가 있을 수 있다.
업무 요구에 따라:
식별 정보 제거
업무 기록 유지
특정 필드 마스킹
일부 데이터 삭제
형태가 될 수 있다.
법적 보존 기간이나 삭제 요구는 실제 회사 정책/법무 기준으로 결정해야 한다.
개발자는:
정책을 구현할 수 있는 구조
를 만든다.
예:
OrderRetentionPolicy
가:
ANONYMIZE
라고 결정하면 코드가 그 Action을 수행한다.
Input:
policy
를 실행하는 역할만 한다.
예:
1. 대상 조회
2. Hold 여부 확인
3. 관련 Active 업무 확인
4. 개인정보 제거
5. Secondary Store 정리
6. Verify
7. Audit
형태다.
예:
주문 상담 진행 중
인데 전화번호를 먼저 삭제하면 업무가 깨질 수 있다.
예:
Order final status
No active workflow
No retention hold
같은 조건을 둔다.
예:
COMPLETED
CANCELLED
REJECTED
처럼 업무가 끝난 상태인지 확인한다.
정확한 상태는 프로젝트 정책에 맞춘다.
같은 DB 안에서:
customerName = null
phone = null
address = null
anonymizedAt = now
를 하나의 Transaction으로 처리한다.
예:
이름 삭제 성공
전화번호 업데이트 실패
같은 중간 상태를 막는다.
Audit Log에:
before.phone
after.phone
전체 값을 넣어뒀다면 주문 Row만 익명화해도 개인정보가 남는다.
예:
field
phone
before
[REDACTED]
after
[REDACTED]
또는:
changed=true
정도만 남기는 방법이 있다.
Audit 목적 때문에 모든 개인정보 원문을 저장할 필요는 없다.
무엇이 바뀌었는가
와:
실제 값 전체
는 다르다.
외부 Provider Webhook 전체 JSON을 장기간 저장하면 개인정보가 들어 있을 수 있다.
필요하다면:
Raw Payload
7일
Normalized Event
90일
처럼 구분할 수 있다.
운영 편의를 위해 영구 보관하지 않는다.
원본 Webhook:
{
"customerName": "...",
"phone": "...",
"messageId": "..."
}
에서 내부 Event에는:
{
"providerMessageId": "...",
"status": "DELIVERED"
}
정도만 저장한다.
External Raw Event
↓
Validation
↓
Normalized Internal Event
로 변환한다.
내부 시스템 전체에 외부 Raw Payload를 퍼뜨리지 않는다.
Backup도 데이터 복사본이다.
Production DB에서 삭제했다고 Backup까지 즉시 사라지는 것은 아니다.
예:
Daily Backup
30일
Monthly Backup
장기 보관
등 별도 정책이 있을 수 있다.
정확한 기간은 회사 정책에 맞춘다.
Backup은 즉시 Row 단위 삭제가 어려울 수 있다.
따라서:
백업 보관 기간
Restore 후 데이터 처리 절차
를 정책으로 갖는 것이 중요하다.
예:
10/01 개인정보 삭제
10/03 장애
09/30 Backup 복구
하면 삭제 전 데이터가 다시 들어올 수 있다.
Restore 후:
삭제/익명화 이력
을 다시 적용할 수 있는 구조를 고려할 수 있다.
예:
customerId
deletedAt
deletionType
같은 최소 삭제 이력을 별도 보관하는 방식이다.
목적은:
이 대상은 다시 활성화되면 안 된다
를 표시하는 것이다.
Backup Restore
↓
Deletion Ledger 확인
↓
해당 데이터 재익명화
같은 흐름을 만들 수 있다.
우선:
Backup Retention 정책 문서화
삭제 이력 Audit
Restore Runbook
정도부터 시작해도 충분하다.
예:
already deleted
된 Artifact에 다시 Delete 요청이 와도:
성공 취급
할 수 있다.
예:
name = null
phone = null
상태에서 다시 Anonymize해도 문제가 없어야 한다.
예:
PLANNED
SCANNING
READY
RUNNING
VERIFYING
SUCCESS
FAILED
MANUAL_REQUIRED
정도로 둘 수 있다.
예:
CleanupRun
run_123
Candidate IDs
를 기록한다.
다만 대량 ID를 JSON에 다 넣지 않는다.
필요하면:
cleanup_run_items
를 두고:
targetType
targetId
status
를 관리할 수 있다.
예:
매일 Outbox 2,000건 삭제
정도라면 Cursor 기반 Batch로 충분할 수 있다.
예:
id > lastId
AND createdAt < cutoff
를 사용해 Batch를 순서대로 처리한다.
삭제하면서 Offset이 계속 바뀌기 때문이다.
Keyset/Cursor 방식이 더 안정적이다.
예:
500
1,000
5,000
중 DB 부하를 보며 결정한다.
처음에는 작게 시작한다.
Production DB 부하가 민감하다면:
batch 처리
↓
200ms sleep
↓
다음 batch
같은 방식으로 속도를 조절할 수 있다.
예:
maxRowsPerMinute
를 둘 수 있다.
예:
DB CPU 상승
Latency 증가
Connection Pool 포화
가 발생하면 Cleanup을 중단한다.
초기에는 자동보다 운영자 수동 Pause도 충분하다.
LOW
로 두는 것이 일반적이다.
고객 요청 처리보다 우선해서는 안 된다.
트래픽이 상대적으로 낮은 시간에 실행할 수 있다.
단 모든 Batch Job이 같은 새벽 3시에 몰리지 않도록 0929의 Scheduler 원칙을 적용한다.
02:10
Outbox Cleanup
02:30
Workflow Cleanup
03:00
Artifact Cleanup
처럼 분산한다.
DB Timeout 같은 일시 오류는 Retry 가능하다.
하지만:
삭제 대상 500,000건
Safety Threshold 초과
는 Retry할 문제가 아니다.
Retryable:
DB_TIMEOUT
S3_TEMPORARY_ERROR
NETWORK_ERROR
Non-Retryable / Manual:
SAFETY_THRESHOLD_EXCEEDED
POLICY_MISSING
RETENTION_HOLD
UNKNOWN_DATA_STATE
등이다.
삭제 실패 자체가 고객 기능 장애는 아니지만:
계속 실패하면 오래된 데이터가 누적
된다.
운영자에게 정기적으로 노출한다.
예:
정책상 30일 보관
인데 실제로:
90일 된 파일이 5,000개 남아 있음
이면 Drift다.
예:
expired_records
expired_artifacts
oldest_expired_age
를 볼 수 있다.
예:
만료 데이터의 99%가
만료 후 24시간 이내 정리
같은 내부 운영 목표를 둘 수 있다.
예:
Retention 30일
Cleanup Daily
이면 실제 삭제는 최대 31일 시점일 수 있다.
이런 Grace를 정책에 반영한다.
예:
retainFor
30일
grace
24시간
처럼 관리할 수 있다.
자동 Retention Cleanup과:
특정 데이터 즉시 삭제 요청
은 다른 Use Case다.
예:
interface DeletionRequest {
id: string;
subjectId: string;
status:
| 'PENDING'
| 'REVIEWING'
| 'APPROVED'
| 'RUNNING'
| 'COMPLETED'
| 'REJECTED';
reason: string;
}
현재 요구가 없다면 구조만 이해하고 과도하게 만들지 않는다.
예:
Orders
Consults
Files
Lead Data
Webhook Raw
Logs
어디에 대상 데이터가 있는지 확인한다.
예:
삭제
전화번호
주소
보존
orderId
상품
가격
상태 이력
처럼 Policy가 정할 수 있다.
예:
anonymizedAt
을 남기면 이미 처리된 Row를 다시 판단하기 쉽다.
예:
anonymized customer 홍길동
처럼 로그에 원본 PII를 다시 기록하면 삭제 의미가 줄어든다.
예:
customerId
orderId
fieldsRedactedCount
policyVersion
정도로 남긴다.
삭제 시점에 어떤 Retention Policy를 적용했는지 알아야 한다.
예:
policyVersion
v7
이다.
예:
과거 정책
90일
현재 정책
30일
일 수 있다.
이것도 업무 결정이다.
코드는:
새 정책이 적용되는 기준 시점
을 지원할 수 있어야 한다.
예:
effectiveFrom
2026-10-01
을 둘 수 있다.
설정 변경 전에:
새 Retention 30일을 적용하면
삭제 대상 128,421건
같이 미리 계산하면 좋다.
정책 변경 저장 버튼을 누르기 전에:
예상 영향
을 보여준다.
예:
삭제 대상 < 10,000
→ Normal
삭제 대상 10,000~100,000
→ Warning
100,000 이상
→ Approval
처럼 운영할 수 있다.
정확한 숫자는 실제 규모에 맞춘다.
Plan
Validate
Apply
Verify
Monitor
한다.
Cleanup 후:
만료 Row가 남았는가?
Active Row가 실수로 삭제됐는가?
File Orphan이 있는가?
DB Record와 Storage가 일치하는가?
를 확인한다.
지워야 할 것이 지워졌다
만 보는 게 아니라:
지우면 안 되는 것이 살아 있다
도 확인한다.
대량 Cleanup은 처음부터 전체 적용하지 않는다.
예:
100건
↓
1,000건
↓
10,000건
으로 확대한다.
예:
가장 오래된 1일치
만 먼저 정리한다.
결과가 정상인지 확인한다.
실제 삭제 전:
랜덤 20건
가장 최신 대상 20건
가장 오래된 대상 20건
을 Sample로 확인할 수도 있다.
ID와 Metadata 위주로 보여준다.
Event/Log 데이터가 매우 커지면 날짜별 Partition이 유용할 수 있다.
예:
outbox_2026_09
outbox_2026_10
처럼 생각할 수 있다.
오래된 데이터를:
DELETE millions rows
하는 대신:
old partition drop
방식으로 빠르게 정리할 수 있다.
먼저:
Index
Retention
Batch Cleanup
으로 충분한지 본다.
예:
orders
audit_logs
outbox_events
workflow_step_runs
Table Row 수와 Disk Size를 주기적으로 본다.
단순 현재 Size보다:
하루에 얼마나 증가하는가?
가 중요하다.
예:
Outbox
+100k rows/day
이면 Retention 없이는 빠르게 커진다.
예:
현재
10GB
월 증가
3GB
6개월 후
28GB
처럼 대략 예측할 수 있다.
Query에서:
최근 3개월
만 기본 조회하도록 하는 것도 중요하다.
예:
기본
최근 30일
필요 시
기간 확대
로 하면 오래된 데이터가 있어도 일반 Query 부담이 줄어든다.
예:
주문 관리
과거 주문 조회
를 분리한다.
자주 조회하는 데이터:
Hot
드물게 조회:
Cold
로 볼 수 있다.
현재 규모에서는 굳이 별도 DB가 아니라:
Active Table
Archive Table
수준도 가능하다.
FK 관리
Query 분기
복구
데이터 이동
복잡도가 늘어난다.
실제 성능 문제가 있을 때 도입한다.
가장 현실적인 순서다.
Audit은 사고 조사와 운영 추적에 중요하다.
로그와 같은 짧은 Retention을 적용하지 않는다.
예:
actorId
action
targetType
targetId
timestamp
changedFields
정도다.
특히 Order 전체 JSON을 Audit에 저장하면:
PII 복제
Storage 증가
Schema 변화
문제가 생긴다.
예:
{
"changedFields": [
"status",
"planId"
]
}
또는 민감하지 않은 값만 저장한다.
AI 자동화에서는:
Prompt
Context
LLM Output
Tool Log
Report
가 쌓일 수 있다.
특히 Prompt에 코드, 업무정보, 개인정보가 섞일 수 있다.
Metadata:
runId
model
promptVersion
status
duration
는 오래 보관 가능하다.
Raw Prompt/Context:
짧은 Retention
을 고려할 수 있다.
예:
명령어
Exit Code
Duration
Artifact ID
정도는 남기되:
.env 전체
Secret Output
전체 DB Row
는 기록하지 않는다.
최종 Markdown은 성과 기록이라 오래 보관할 가치가 있다.
반면:
중간 Prompt
임시 Context
Raw Model Response
는 필요 없으면 짧게 보관하거나 저장하지 않아도 된다.
Run 전체는 1년 보관하더라도 Step의 큰 Output은 30일 뒤 삭제할 수 있다.
예:
WorkflowRun Metadata
365일
Step Raw Output
30일
같이 운영할 수 있다.
Run이 있었다
언제 성공했다
어떤 Error가 났다
는 남는다.
큰 Payload만 사라진다.
오래된 Stack Trace는 코드가 이미 바뀌어 활용 가치가 낮을 수 있다.
예:
Incident와 연결된 로그/Run
은 일반 Retention보다 길게 유지할 수 있다.
중요 Incident 조사 중에는 관련 데이터를 Cleanup에서 제외한다.
예:
correlationId
workflowRunId
incidentId
orderId
를 기준으로 연결된 데이터를 보존할 수 있다.
Incident 종료 후 Hold 해제 시점을 정한다.
예:
Cleanup Run
cleanup_123
Policy
OUTBOX_90D
Candidates
12,451
Deleted
12,449
Failed
2
정도를 기록한다.
수십만 건 Cleanup에서 Row마다 Audit를 쓰면:
삭제한 만큼 Audit가 다시 생김
이라는 문제가 생긴다.
Cleanup Run 단위로 요약 기록하는 편이 낫다.
개인정보 관련 Workflow는 대상별 상태를 남길 가치가 있다.
단 원문 PII는 남기지 않는다.
정상 삭제 10만 건은 Summary.
실패 5건만:
targetId
errorCode
를 저장한다.
예:
RETENTION_POLICY_MISSING
RETENTION_HOLD_ACTIVE
DELETE_THRESHOLD_EXCEEDED
ARTIFACT_DELETE_FAILED
ANONYMIZATION_FAILED
CLEANUP_VERIFICATION_FAILED
등이다.
예:
Expired Outbox
0
Expired Workflow
120
Expired Artifacts
42
Deletion Failures
2
Oldest Expired
3 days
정도로 볼 수 있다.
예:
PostgreSQL
32GB
S3 Export
4GB
Logs
8GB
Artifacts
2GB
등을 확인한다.
이번 달 +20%
처럼 급증하면 새 기능이 데이터를 과도하게 만들고 있을 수 있다.
예:
Workflow Step
180일 → 90일
Estimated Reduction
3.4GB
같은 Preview를 만들 수 있다.
보관 여부의 우선 기준은:
업무/정책상 필요성
이다.
Storage 최적화는 그다음이다.
S3 싸니까 전부 영구 저장
은 보안과 관리 측면에서 좋지 않다.
가능하면 데이터마다 명확한 목적을 둔다.
데이터 종류마다 담당 영역을 정할 수 있다.
예:
Orders
Business
Outbox
Backend
Logs
Infra
AI Artifacts
Automation
1인 개발이어도 목적이 명확해진다.
예:
interface RetentionDefinition {
dataType: string;
owner: string;
retainDays?: number;
action: string;
criticality: string;
}
형태로 중앙 관리할 수 있다.
OUTBOX_PUBLISHED
90d
DELETE
WORKFLOW_SUCCESS
180d
ARCHIVE
EXPORT_FILE
30d
DELETE
AI_RAW_CONTEXT
7d
DELETE
정도다.
실제 기간은 업무 기준으로 정한다.
새 Table을 만들었는데:
Retention Policy 없음
이면 Review 대상으로 띄울 수 있다.
새 Persistent Table 생성 시:
이 데이터는 언제 삭제되는가?
를 묻는다.
많은 시스템이:
데이터 생성 기능
은 열심히 만들지만:
데이터 종료 전략
은 만들지 않는다.
예:
ExportJob 생성
기능을 만들 때 동시에:
Export Artifact Retention
을 정의한다.
Outbox Event
가 영구 Event Store가 아니라면:
PUBLISHED 이후 얼마나 유지?
를 정한다.
Prompt/Output을 언제 정리할까?
를 처음부터 생각한다.
0925와 연결해서 테스트할 수 있다.
예:
삭제 중 Worker Crash
S3 Timeout
DB Batch 실패
Safety Threshold 초과
이다.
이미 완료한 Batch 재삭제 안전
Resume 가능
Active Data 삭제 없음
Failure 기록
이어야 한다.
예:
Batch 1
SUCCESS
Batch 2
절반 처리 후 Crash
다시 실행해도 이미 삭제된 Row 때문에 실패하지 않아야 한다.
삭제된 Row 기준 Cursor가 꼬이지 않게:
고정 cutoff
Primary Key cursor
를 사용한다.
예:
cutoffAt
2026-07-01T00:00:00Z
를 Run 시작 시 저장한다.
그렇지 않으면 Job 실행 중 대상 범위가 계속 늘어난다.
Run 입력:
policyVersion
cutoffAt
targetType
을 고정한다.
같은 Run을 Resume해도 대상 기준이 동일하다.
다음날 Cleanup Run이 새 범위를 처리한다.
삭제 대신 Archive라면:
Candidate Scan
↓
Copy / Move
↓
Verify Archive
↓
Remove Active
↓
Complete
형태가 된다.
먼저:
Archive 존재 확인
후 원본을 정리한다.
Archive Insert 성공
Active Delete 실패
하면 중복 데이터가 생길 수 있다.
예:
archive.sourceId UNIQUE
를 둔다.
Desired:
Archived record exists
Active record absent
Actual:
둘 다 존재
이면 Cleanup을 이어간다.
Archive Data를 일상 조회에서 제외하면 Active Index Size가 줄어들 수 있다.
하지만 실제 필요성이 생긴 뒤 도입한다.
예:
archivedAt IS NULL
을 기본 Query에 넣는다.
이 시점에 Partition/Archive Table을 검토한다.
우선순위는 다음이 현실적이다.
1. Export 파일
2. Outbox/Inbox 완료 기록
3. Workflow/Job 상세 로그
4. Raw Webhook Payload
5. AI 임시 Artifact
이다.
핵심 Business Data이므로 회사의 실제 보관 정책과 운영 요구를 먼저 확인해야 한다.
예:
orders.customerName
orders.phone
orders.birthDate
orders.address
leads.ip
consults.message
등을 정리한다.
삭제 요청이 와도 완전하게 처리할 수 없기 때문이다.
AI가 코드/Schema를 분석해:
phone
email
address
birth
name
ip
관련 Field 후보를 찾아줄 수 있다.
Field 이름만 보고는 의미가 애매할 수 있다.
사람이 검토한다.
예:
Field
orders.customerPhone
Usage
Order processing
References
5 files
Logs
No direct usage detected
Retention
Not defined
형태로 만들 수 있다.
Retention 없는 Table 찾기
PII 후보 Field 탐색
Log에 PII 출력 후보 찾기
Orphan Artifact 가능성 찾기
Cleanup 대상 Query 검토
Destructive SQL Risk Review
등이다.
특히 Production 데이터 삭제는:
Review
Dry Run
Approval
Execute
과정을 거친다.
예:
READ
자동 가능
DRY_RUN
자동 가능
DELETE_PREVIEW
자동 가능
DELETE_EXECUTE
Approval Required
정도로 나눈다.
예:
정책
Export 30일
↓
AI
대상/위험/예상 용량 정리
↓
System Dry Run
↓
Human Approval
↓
Cleanup Worker
형태가 안전하다.
새 Cleanup 정책을:
cleanup_export_v2_enabled
로 일부 범위에만 적용할 수도 있다.
정책이 정착하면 Legacy Flag를 정리한다.
문제가 생기면:
cleanup_enabled=false
로 모든 자동 Cleanup을 즉시 중지할 수 있으면 좋다.
예:
Outbox Cleanup
ON
Export Cleanup
OFF
처럼 특정 Cleanup만 멈춘다.
예:
CLEANUP_FAILED
3회 연속
Warning.
Expired PII
정책 기준 초과
Criticality를 높일 수 있다.
업무 중요도에 따라 다르게 한다.
예:
| Policy | 대상 | 삭제 | 실패 | 결과 |
|---|---|---|---|---|
| Outbox 90d | 12,451 | 12,451 | 0 | 성공 |
| Export 30d | 120 | 118 | 2 | 부분 성공 |
| Workflow 180d | 5,210 | 0 | 0 | Threshold 중단 |
이런 화면이 있으면 좋다.
Cleanup에서도 일부 File 삭제만 실패할 수 있다.
PARTIAL_SUCCESS
를 지원할 수 있다.
이미 삭제한 118개 파일을 다시 처음부터 처리할 필요 없다.
예:
DB:
Artifact DELETED
Storage:
Object Exists
이면 불일치다.
반대로:
DB:
AVAILABLE
Storage:
Missing
도 불일치다.
Expired Artifact
Desired
DB DELETED
Storage missing
형태다.
Storage에 파일이 있는데 DB Record가 없다면 Orphan이다.
DB Record가 실수로 삭제됐을 수도 있다.
바로 Storage 삭제하지 말고:
Orphan 발견
↓
Grace Period
↓
재확인
↓
삭제
가 안전하다.
예:
7일
등으로 두고 일시적 Race Condition을 피한다.
정확한 기간은 시스템 특성에 맞춘다.
예:
NotificationJob
orderId 존재
Order 없음
같은 참조 불일치다.
FK가 있으면 많은 문제를 예방할 수 있다.
Application Cleanup으로 Referential Integrity를 대신하지 않는다.
FK가 있다면:
Child
↓
Parent
순서가 필요할 수 있다.
Order Delete
↓
Audit
Notification
Workflow
모두 자동 Delete
되면 예상보다 훨씬 큰 데이터가 사라질 수 있다.
특히 Audit나 운영 기록이 같이 지워지지 않도록 한다.
예:
Order 100건 삭제
Related Rows
Notification 230
Workflow 400
Audit 1,200
처럼 보여주면 위험을 알 수 있다.
대량 Cleanup Query가 Full Scan으로 DB를 압박할 수 있다.
Index를 점검한다.
예:
status + createdAt
status + completedAt
deletedAt
등 Cleanup Query 패턴에 맞춘다.
쓰기 비용도 증가한다.
실제 Slow Query를 보고 판단한다.
PostgreSQL에서 대량 DELETE 후 디스크 공간이 즉시 파일 시스템에 반환되지 않을 수 있다.
즉:
Row 삭제
=
Disk 즉시 감소
는 아니다.
하지만 현재 단계에서는 Autovacuum과 일반 운영 정책을 우선하고 과도한 수동 Vacuum은 피한다.
정말 규모가 커졌을 때 고려한다.
예:
1. Policy 확인
2. 대상 Preview
3. Hold 확인
4. Safety Threshold 확인
5. Dry Run
6. Approval
7. Batch 실행
8. Verify
9. Failure Retry
10. Audit Summary
이다.
1. 대상 ID 확인
2. Active 업무 여부 확인
3. Retention Hold 확인
4. 적용 Policy 확인
5. DB PII 익명화
6. Secondary Store 확인
7. Artifact 처리
8. Verification
9. Audit
10. Monitoring
Restore 완료
↓
Deletion / Anonymization 상태 확인
↓
필요 시 재적용
↓
서비스 오픈
같은 체크를 둘 수 있다.
먼저 Inventory만 만든다.
어떤 Table / File이 있는가?
PII가 어디 있는가?
지금 Cleanup은 있는가?
현재 보관 기간은 무엇인가?
를 정리한다.
낮은 위험 데이터부터 자동 Cleanup한다.
예:
완료 Export File
Temporary File
완료 Outbox
이다.
Workflow/Job History Retention을 정한다.
Raw Webhook / Log의 PII와 Retention을 정리한다.
회사 정책이 확정된 뒤 주문/고객 개인정보 Lifecycle을 구현한다.
가장 위험한 접근이다.
먼저:
정책
운영 필요
보존 의무
복구 전략
을 확정한다.
1. PII Inventory
2. Export Artifact 30일 Cleanup 같은 저위험 정책
3. Outbox/Inbox Retention
4. Raw Payload/Log PII 제거
5. Cleanup Dry Run + Safety Threshold
정도다.
현재 규모에서는:
별도 Data Lake
복잡한 Data Governance SaaS
자동 법률 Policy Engine
대규모 Archive Cluster
모든 Table Partitioning
까지 갈 필요 없다.
현재 NestJS + Prisma + PostgreSQL + AWS 기반 프로젝트에
Data Retention / Cleanup 구조를 최소 범위로 추가해줘.
목표는 모든 데이터를 무조건 삭제하는 것이 아니라,
데이터 종류별 보관 정책을 명확히 하고
오래된 Operational / Temporary Data를
안전하게 정리할 수 있도록 만드는 것이다.
주문/고객 개인정보처럼 법적·업무상 정책 확인이 필요한 데이터는
임의의 보관 기간을 가정해서 자동 삭제하지 않는다.
먼저 현재 Schema, S3/File 사용, Job/Workflow/Event 구조를 분석한다.
1. Persistent Data Inventory를 작성한다.
최소 대상:
- orders
- consults
- audit logs
- application/event logs
- outbox/inbox/webhook
- jobs
- workflow runs / step runs
- schedule runs
- export files
- S3 artifacts
- AI report artifacts
각 항목에 대해:
- 목적
- 민감도
- PII 여부 후보
- 현재 Cleanup 여부
- 추천 Cleanup 방식
을 정리한다.
2. PII 후보 Field를 찾는다.
예:
- name
- phone
- birth
- address
- email
- ip
단 Field 이름만 보고 확정하지 말고
실제 사용 코드를 확인해서 후보로 정리한다.
3. RetentionPolicy 구조를 설계한다.
예:
- dataType
- retentionDays
- gracePeriod
- action
- enabled
- riskLevel
- version
action:
- ARCHIVE
- ANONYMIZE
- DELETE
4. 주문/고객 Core Business Data에는
실제 정책이 없는 상태에서 기본 DELETE Policy를 만들지 않는다.
5. 첫 자동 Cleanup 적용 대상은
저위험 데이터로 제한한다.
우선순위:
- 만료 Export Artifact
- 완료된 Outbox/Inbox
- 오래된 완료 Workflow Step Detail
- Temporary Artifact
6. CleanupRun 모델을 만든다.
필드 예:
- id
- policyType
- policyVersion
- cutoffAt
- status
- candidateCount
- processedCount
- deletedCount
- failedCount
- startedAt
- completedAt
- errorCode
7. CleanupRun 상태:
- PLANNED
- SCANNING
- READY
- RUNNING
- VERIFYING
- SUCCESS
- PARTIAL_SUCCESS
- FAILED
- MANUAL_REQUIRED
8. Cleanup 시작 시 cutoffAt을 고정한다.
Run 중간에 현재 시간을 다시 기준으로 삼아서
대상 범위가 계속 늘어나지 않게 한다.
9. 실제 삭제 전에 Dry Run을 지원한다.
Dry Run 결과:
- candidateCount
- oldestCandidate
- newestCandidate
- estimated size가 가능하면 해당 정보
- 삭제 대상 조건
10. Safety Threshold를 적용할 수 있게 한다.
예:
- maxDeleteCount
- maxDeleteRatio
Threshold를 초과하면
자동 삭제하지 않고 MANUAL_REQUIRED로 전환한다.
11. Cleanup 대상은 상태 조건을 포함한다.
예:
OutboxEvent는 단순 createdAt만 보지 말고
PUBLISHED 등 안전한 Terminal 상태인지 확인한다.
PENDING / RETRY_PENDING / DEAD_LETTER를
무조건 삭제하지 않는다.
12. Workflow / Schedule / Job 역시
Active 상태는 Cleanup 대상에서 제외한다.
예:
- RUNNING
- WAITING
- COMPENSATING
등.
13. Cleanup은 Batch 방식으로 처리한다.
Offset 기반보다는
Primary Key / Keyset Cursor 방식을 우선 고려한다.
14. Batch Size와
필요한 경우 batch delay를 설정할 수 있게 한다.
15. Cleanup Job은 Idempotent하게 만든다.
이미 삭제된 Resource를 다시 처리해도
안전해야 한다.
16. Artifact 삭제는 DB Row 삭제와 분리한다.
예:
- EXPIRED
- DELETE_PENDING
- DELETING
- DELETED
- DELETE_FAILED
상태를 고려한다.
17. S3/File 삭제 요청 결과가 불확실한 경우
Object 존재 여부를 재확인하는
Reconciliation 흐름을 고려한다.
18. DB Record와 Artifact 간 Orphan을
탐지할 수 있는 구조를 만든다.
Orphan을 발견했다고 즉시 삭제하지 않고
Grace Period 후 재확인할 수 있게 한다.
19. 개인정보가 Log / Audit / Event Payload에
과도하게 복제되고 있는지 분석한다.
특히 다음 패턴을 찾는다.
- logger.info(req.body)
- 전체 order/customer 객체 로그
- Outbox payload에 전화번호/주소 저장
- Audit before/after 전체 JSON
20. Logger에 이미 Redaction 구조가 있다면 재사용한다.
없다면 민감 Field 중앙 Redaction 방식을 제안한다.
21. Audit Log에서 개인정보 원문 보관을 최소화한다.
가능하면:
- changed field names
- targetId
- [REDACTED]
형태를 우선한다.
22. Anonymization 구조를 설계할 때
다음 Precondition을 고려한다.
- Active Workflow 없음
- Retention Hold 없음
- Business Final State
단 실제 주문 데이터 익명화는
정책 확정 전 자동 실행하지 않는다.
23. Retention Hold 구조를 고려한다.
필드 예:
- targetType
- targetId
- reason
- createdBy
- createdAt
- expiresAt
24. Hold 상태 데이터는
일반 Cleanup에서 제외한다.
25. Policy 변경은 Audit Log에 기록한다.
- before
- after
- actor
- reason
- version
26. Retention Policy 변경 시
실제 적용 전에 영향도를 계산할 수 있게 한다.
예:
90일 → 30일 변경 시
예상 Candidate Count 출력
27. Cleanup 자체는
Kill Switch 또는 enabled 상태로 중지할 수 있게 한다.
28. Cleanup 관련 Metric을 수집할 수 있게 한다.
- expired records
- cleanup success
- cleanup failure
- deleted count
- oldest expired age
- cleanup duration
29. 다음 Reliability Test를 작성한다.
- Dry Run 후 실제 데이터 변경 없음
- Threshold 초과 시 실행 중단
- Terminal 상태 데이터만 대상
- Active Workflow 삭제 방지
- Batch 삭제
- 중간 Worker Crash 후 Resume
- 동일 Cleanup 재실행 Idempotency
- Artifact delete timeout 후 Reconciliation
- Retention Hold 대상 제외
- 잘못된 Policy Version 차단
30. 실제 주문/고객 PII Hard Delete는
이번 구현 범위에서 자동화하지 않는다.
먼저 Inventory + Policy 적용 구조 + 저위험 Cleanup부터 구현한다.
현재 코드베이스를 분석한 후,
필요 이상의 Data Governance Platform을 만들지 말고
1인 개발자가 운영 가능한 수준으로 설계해줘.
현재 NestJS + Prisma 코드베이스에서
개인정보 또는 민감정보가 저장/전달/로그될 가능성이 있는 위치를 찾아
PII Inventory Report를 작성해줘.
코드나 데이터를 수정하지 않고 분석만 한다.
검토 대상:
1. Prisma Schema
2. DTO
3. API Request / Response
4. Logger
5. Audit Log
6. Outbox / Inbox / Webhook Payload
7. Queue Payload
8. S3 / File Artifact
9. Export Excel
10. AI Prompt / Context / Report
11. Analytics / Lead Tracking
찾을 후보:
- 이름
- 전화번호
- 주소
- 생년월일
- 이메일
- IP
- Token / Credential
- 상담 메시지
- 주문 개인정보
각 후보에 대해 다음을 정리한다.
## 데이터
## 저장 위치
## 생성 위치
## 사용 위치
## Log 포함 여부
## Event/Queue 복제 여부
## Export 포함 여부
## 삭제/익명화 경로 존재 여부
## Retention 정의 여부
## 위험도
HIGH
민감 데이터가 여러 저장소/로그로 복제됨
MEDIUM
필요한 저장이지만 Retention이 불명확함
LOW
ID 참조만 존재하거나 이미 Redaction됨
실제 코드에서 확인할 수 없는 보관 기간이나
법적 보관 의무는 추정하지 않는다.
마지막에 다음 세 가지를 별도로 정리한다.
1. 지금 바로 줄일 수 있는 불필요한 PII 복제
2. Retention 정의가 필요한 데이터
3. 삭제/익명화 구현 전에 정책 확인이 필요한 데이터
현재 DB Cleanup 후보를 분석하되
실제 DELETE / UPDATE를 실행하지 말고
Dry Run Report만 작성해줘.
대상:
- PUBLISHED Outbox
- PROCESSED Inbox
- 완료 Workflow Step
- 만료 Export Artifact
각 대상마다:
1. Cleanup 조건
2. Candidate Count를 구할 Query
3. 삭제하면 안 되는 상태
4. 필요한 Index
5. Batch 기준
6. Safety Threshold
7. Retry / Resume 전략
8. Verification Query
9. 예상 위험
을 정리한다.
특히 다음은 자동 삭제 대상에서 제외한다.
- PENDING
- PROCESSING
- RETRY_PENDING
- WAITING
- MANUAL_REQUIRED
- DEAD_LETTER
- Retention Hold
실제 Production 데이터는 수정하지 않는다.
1002에서는:
새 구조를 어떻게 안전하게 추가하고
구버전과 신버전을 공존시키고
마지막에 Legacy를 제거할 것인가
를 다뤘다.
1003에서는 시스템 운영의 반대편 질문을 다뤘다.
이 데이터는
언제까지 살아 있어야 하는가?
이다.
데이터 Lifecycle은:
Collect
↓
Use
↓
Store
↓
Archive
↓
Anonymize / Delete
로 볼 수 있다.
가장 먼저 기억할 것은:
모든 데이터는 영구 보관 대상이 아니다.
하지만 반대로:
오래됐다는 이유만으로
모든 데이터를 삭제해서도 안 된다.
는 것이다.
따라서:
Business Data
Audit Data
Operational Data
Event Data
Temporary Data
PII
를 구분하고 서로 다른 Retention Policy를 적용해야 한다.
특히 개인정보는:
DB Row 삭제
하나로 끝나는 문제가 아니다.
Log
Audit
Event
Queue
Export
File
Backup
등 다른 위치에도 복제돼 있을 수 있기 때문이다.
그래서 가장 먼저 필요한 것은:
Data Inventory
다.
즉:
어떤 개인정보가 어디에 있고 왜 존재하는지 모르는 상태에서는 안전한 삭제도 할 수 없다.
또 Cleanup 자체도 위험한 Production 작업이다.
따라서:
Cron
→ DELETE
로 만들기보다:
Policy
↓
Dry Run
↓
Candidate Count
↓
Safety Threshold
↓
Approval
↓
Batch Cleanup
↓
Verification
순서로 처리하는 것이 좋다.
특히:
평소 1,000건 삭제
오늘 250,000건 대상
처럼 예상 범위를 크게 벗어나면 자동 실행을 멈춰야 한다.
Cleanup도 지금까지 다룬 운영 원칙을 그대로 사용한다.
Idempotency
Batch
Retry
Resume
Reconciliation
Audit
Observability
가 필요하다.
Artifact도 마찬가지다.
DB Record 삭제
와:
S3/File 삭제
는 서로 다른 시스템이므로 불일치가 생길 수 있다.
따라서:
Expired
↓
Delete Pending
↓
Delete
↓
Verify
↓
Deleted
같은 상태를 두고 Reconciliation할 수 있다.
그리고 개인정보 관련 핵심 원칙은:
필요 없는 데이터는
나중에 잘 삭제하는 것보다
처음부터 저장하지 않는 것이 더 좋다.
는 것이다.
따라서:
Log PII 제거
Event Payload 최소화
Audit Snapshot 최소화
ID Reference 중심 설계
가 Cleanup보다 우선될 수 있다.
현재 프로젝트에서는 주문/고객 Core Data를 바로 자동 삭제하기보다 먼저:
1. PII Inventory
2. Export Artifact Cleanup
3. Outbox / Inbox Retention
4. Workflow History Retention
5. Raw Webhook / Log PII 정리
순서로 적용하는 것이 현실적이다.
전체 시리즈 흐름에 Data Lifecycle을 연결하면:
Create
↓
Process
↓
Observe
↓
Persist
↓
Retain
↓
Archive / Anonymize
↓
Cleanup
↓
Verify
↓
Audit
가 된다.
결국 Data Retention의 핵심은
“데이터를 얼마나 많이 보관할 수 있는가”가 아니라, 각 데이터가 왜 존재하는지 설명할 수 있고, 더 이상 필요하지 않을 때 안전하고 검증 가능한 방식으로 수명을 끝낼 수 있는가
이다.