<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Operational UX on jyukki's Blog</title><link>https://jyukki.com/tags/operational-ux/</link><description>Recent content in Operational UX on jyukki's Blog</description><generator>Hugo -- 0.147.0</generator><language>ko-kr</language><lastBuildDate>Thu, 30 Jul 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://jyukki.com/tags/operational-ux/index.xml" rel="self" type="application/rss+xml"/><item><title>백엔드 커리큘럼 심화: Activity Timeline과 Event Feed, 운영자가 믿을 수 있는 이력 화면 설계하기</title><link>https://jyukki.com/learning/deep-dive/deep-dive-activity-timeline-event-feed-playbook/</link><pubDate>Thu, 30 Jul 2026 00:00:00 +0000</pubDate><guid>https://jyukki.com/learning/deep-dive/deep-dive-activity-timeline-event-feed-playbook/</guid><description>주문·결제·권한·배치 작업의 이력을 단순 로그 검색이 아니라 운영자가 판단할 수 있는 Activity Timeline과 Event Feed로 설계하는 실무 플레이북입니다.</description><content:encoded><![CDATA[<p>운영자가 장애나 고객 문의를 받을 때 가장 자주 묻는 질문은 &ldquo;지금 상태가 뭐지?&ldquo;가 아니라 &ldquo;여기까지 어떻게 왔지?&ldquo;입니다. 주문이 왜 취소됐는지, 파일 업로드가 왜 아직 공개되지 않았는지, 권한 회수가 언제 적용됐는지, 배치 작업이 재시도됐는지 한눈에 볼 수 있어야 다음 조치를 결정할 수 있습니다. 그런데 많은 서비스는 이 질문을 애플리케이션 로그 검색으로 넘깁니다. 로그는 개발자 디버깅에는 좋지만, 고객·CS·운영자가 믿고 판단할 이력 화면으로는 부족합니다.</p>
<p>Activity Timeline과 Event Feed는 이런 간극을 메우는 읽기 모델입니다. 중요한 도메인 이벤트를 선별하고, 상태 전이와 감사 로그, 작업 영수증, 외부 연동 결과를 같은 시간축으로 보여 줍니다. 이 글은 <a href="/learning/deep-dive/deep-dive-operational-state-machine-design/">운영용 상태 머신 설계</a>, <a href="/learning/deep-dive/deep-dive-tamper-evident-audit-log-playbook/">Tamper-Evident Audit Log</a>, <a href="/learning/deep-dive/deep-dive-execution-receipt-operations-playbook/">Execution Receipt</a>, <a href="/learning/deep-dive/deep-dive-structured-logging/">구조화 로깅</a>을 이어서, 운영자가 실제로 쓸 수 있는 이력 화면을 어떻게 설계할지 정리합니다.</p>
<h2 id="이-글에서-얻는-것">이 글에서 얻는 것</h2>
<ul>
<li>애플리케이션 로그, 감사 로그, 도메인 이벤트, 사용자용 timeline의 역할 차이를 구분할 수 있습니다.</li>
<li>Activity Timeline 이벤트 스키마에 들어가야 할 필드와 민감정보 마스킹 기준을 잡을 수 있습니다.</li>
<li>이벤트 반영 지연, 중복 제거, 정렬, 누락 표시, 보존 기간을 숫자로 설계할 수 있습니다.</li>
<li>고객 화면과 백오피스 화면, 보안 감사 화면을 같은 원본 이벤트에서 다르게 projection하는 방법을 가져갈 수 있습니다.</li>
</ul>
<h2 id="핵심-개념이슈">핵심 개념/이슈</h2>
<h3 id="1-timeline은-로그-뷰어가-아니라-도메인-읽기-모델이다">1) Timeline은 로그 뷰어가 아니라 도메인 읽기 모델이다</h3>
<p>로그는 보통 &ldquo;시스템이 무엇을 했다&quot;를 남깁니다. <code>payment request failed</code>, <code>retry scheduled</code>, <code>status update rows=1</code> 같은 메시지는 개발자에게는 의미가 있지만 고객이나 CS에게는 충분하지 않습니다. Timeline은 &ldquo;업무적으로 어떤 일이 일어났는가&quot;를 보여 줘야 합니다.</p>
<p>예를 들어 결제 실패 로그는 아래처럼 timeline 이벤트로 바뀌어야 합니다.</p>
<table>
  <thead>
      <tr>
          <th>원본 신호</th>
          <th>Timeline 이벤트</th>
          <th>운영자가 얻는 판단</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>PG timeout log</td>
          <td>결제 승인 응답 지연으로 확인 대기 전환</td>
          <td>고객에게 중복 결제 안내가 필요한가</td>
      </tr>
      <tr>
          <td>retry job created</td>
          <td>결제 상태 재확인 예약</td>
          <td>언제 자동 확인되는가</td>
      </tr>
      <tr>
          <td>reconciliation matched</td>
          <td>승인 완료로 보정</td>
          <td>수동 환불이 필요한가</td>
      </tr>
      <tr>
          <td>correction job approved</td>
          <td>운영자 승인 보정 완료</td>
          <td>누가 어떤 근거로 처리했는가</td>
      </tr>
  </tbody>
</table>
<p>핵심은 원본 로그를 모두 보여 주는 것이 아닙니다. 운영 판단에 필요한 이벤트를 안정적인 이름과 스키마로 저장하는 것입니다. 로그 메시지는 바뀔 수 있지만 <code>PAYMENT_CONFIRMATION_DELAYED</code> 같은 이벤트 타입은 API 계약처럼 관리해야 합니다.</p>
<h3 id="2-audit-log와-timeline은-겹치지만-목적이-다르다">2) Audit Log와 Timeline은 겹치지만 목적이 다르다</h3>
<p>감사 로그는 나중에 검증하기 위한 증거입니다. 누가, 어떤 권한으로, 어떤 대상에, 어떤 결과를 만들었는지 조작 가능성을 낮춰 보존합니다. Timeline은 운영자가 지금 판단하기 위한 화면입니다. 같은 사건에서 출발하더라도 보여 주는 필드와 보존 정책이 달라야 합니다.</p>
<p>관리자 권한 변경을 예로 들면 감사 로그에는 actor id, policy version, before/after digest, ticket id, request id가 들어갑니다. 반면 운영 timeline에는 &ldquo;철수님에게 Billing Admin 권한이 부여됨&rdquo;, &ldquo;승인 티켓: SEC-1234&rdquo;, &ldquo;권한 정책 v18 기준&rdquo; 정도면 충분할 수 있습니다. 고객 화면에는 아예 보이지 않아야 할 수도 있습니다.</p>
<p>이 차이를 무시하면 두 가지 문제가 생깁니다. 모든 것을 timeline에 넣으면 민감정보가 새어 나갑니다. 반대로 timeline만 믿고 감사 로그를 생략하면 사고 후 검증이 어렵습니다. 실무에서는 audit log를 source of truth로 두고, timeline은 목적별 projection으로 만드는 편이 안전합니다.</p>
<h3 id="3-이벤트-스키마는-사람-문장보다-안정적인-필드가-먼저다">3) 이벤트 스키마는 사람 문장보다 안정적인 필드가 먼저다</h3>
<p>Timeline 이벤트에는 사람이 읽는 문장도 필요하지만, 운영 기준은 구조화 필드에서 나옵니다.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#ff79c6">activity_event</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#ff79c6">event_id</span>: evt_01H...
</span></span><span style="display:flex;"><span>  <span style="color:#ff79c6">type</span>: ORDER_PAYMENT_CONFIRMATION_DELAYED
</span></span><span style="display:flex;"><span>  <span style="color:#ff79c6">tenant_id</span>: t_123
</span></span><span style="display:flex;"><span>  <span style="color:#ff79c6">target</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">type</span>: order
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">id</span>: ord_456
</span></span><span style="display:flex;"><span>  <span style="color:#ff79c6">actor</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">type</span>: system
</span></span><span style="display:flex;"><span>    <span style="color:#ff79c6">id</span>: payment-reconciler
</span></span><span style="display:flex;"><span>  <span style="color:#ff79c6">result</span>: pending
</span></span><span style="display:flex;"><span>  <span style="color:#ff79c6">severity</span>: warning
</span></span><span style="display:flex;"><span>  <span style="color:#ff79c6">visibility</span>: operator
</span></span><span style="display:flex;"><span>  <span style="color:#ff79c6">reason_code</span>: PG_TIMEOUT
</span></span><span style="display:flex;"><span>  <span style="color:#ff79c6">occurred_at</span>: <span style="color:#f1fa8c">&#34;2026-07-30T09:21:13+09:00&#34;</span>
</span></span><span style="display:flex;"><span>  <span style="color:#ff79c6">recorded_at</span>: <span style="color:#f1fa8c">&#34;2026-07-30T09:21:14+09:00&#34;</span>
</span></span><span style="display:flex;"><span>  <span style="color:#ff79c6">correlation_id</span>: req_789
</span></span><span style="display:flex;"><span>  <span style="color:#ff79c6">source_event_id</span>: outbox_555
</span></span><span style="display:flex;"><span>  <span style="color:#ff79c6">dedupe_key</span>: <span style="color:#f1fa8c">&#34;order:ord_456:payment-confirmation:2026-07-30&#34;</span>
</span></span></code></pre></div><p>여기서 <code>occurred_at</code>과 <code>recorded_at</code>을 나누는 것이 중요합니다. 외부 시스템이나 비동기 worker에서 늦게 들어온 이벤트는 실제 발생 시각과 저장 시각이 다를 수 있습니다. Timeline 정렬은 보통 <code>occurred_at</code> 기준이지만, 운영 디버깅에는 <code>recorded_at</code> 지연도 필요합니다. 두 값 차이가 30초를 넘으면 ingestion lag로 표시하는 식의 기준을 둘 수 있습니다.</p>
<h3 id="4-모든-이벤트는-visibility-등급을-가져야-한다">4) 모든 이벤트는 visibility 등급을 가져야 한다</h3>
<p>Timeline이 커질수록 가장 위험한 실수는 &ldquo;일단 다 보여 주자&quot;입니다. 이벤트에는 반드시 노출 등급이 있어야 합니다.</p>
<table>
  <thead>
      <tr>
          <th>등급</th>
          <th>대상</th>
          <th>예시</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>public</td>
          <td>최종 사용자</td>
          <td>주문 접수, 결제 완료, 배송 시작</td>
      </tr>
      <tr>
          <td>support</td>
          <td>CS/백오피스</td>
          <td>PG 응답 지연, 재처리 예약, 고객 문의 메모</td>
      </tr>
      <tr>
          <td>operator</td>
          <td>개발/운영팀</td>
          <td>retry exhausted, provider error code, worker shard</td>
      </tr>
      <tr>
          <td>security</td>
          <td>보안/감사 권한자</td>
          <td>권한 변경, 개인정보 export, 정책 예외</td>
      </tr>
      <tr>
          <td>hidden</td>
          <td>내부 계산용</td>
          <td>dedupe, projection rebuild, migration marker</td>
      </tr>
  </tbody>
</table>
<p>초기 기준은 public/support/operator/security 네 단계면 충분합니다. public 이벤트에는 내부 오류 코드, 계정 식별자, provider raw response를 넣지 않습니다. security 이벤트는 별도 권한과 감사 조회 로그를 둡니다. support 등급은 고객 응대에는 필요하지만 고객 화면에는 보이면 안 되는 정보가 들어갈 수 있습니다.</p>
<h3 id="5-timeline의-신뢰도는-누락과-지연을-어떻게-표시하느냐에서-갈린다">5) Timeline의 신뢰도는 누락과 지연을 어떻게 표시하느냐에서 갈린다</h3>
<p>이력 화면은 항상 완벽하지 않습니다. 이벤트 수집이 늦어질 수 있고, projection rebuild 중일 수 있고, 외부 시스템이 나중에 결과를 보낼 수 있습니다. 좋은 timeline은 조용히 거짓말하지 않습니다.</p>
<p>운영 기준은 아래처럼 잡을 수 있습니다.</p>
<ul>
<li>일반 도메인 이벤트 반영 지연 p95: 5초 이하</li>
<li>결제·권한·보안 이벤트 반영 지연 p95: 1초 이하 또는 &ldquo;검증 중&rdquo; 표시</li>
<li>이벤트 ingestion lag가 30초 초과: timeline 상단에 지연 배너</li>
<li>source event와 projection count 차이: 0을 목표, 10건 이상이면 rebuild 알림</li>
<li>동일 target의 중복 이벤트 dedupe window: 1~5분</li>
<li>page size 기본값: 30~50개, 최대 100개</li>
<li>고객 화면 보존: 90~180일, 감사 이벤트 원장 보존: 규정에 맞춰 1년 이상</li>
</ul>
<p>특히 &ldquo;마지막 이벤트가 없으니 아무 일도 없었다&quot;는 해석을 막아야 합니다. 결제 확인 중, 외부 배송사 응답 대기, 보안 검토 대기처럼 진행 중 상태는 명시적으로 보여 줘야 합니다.</p>
<h2 id="실무-적용">실무 적용</h2>
<h3 id="1-이벤트-카탈로그를-먼저-만든다">1) 이벤트 카탈로그를 먼저 만든다</h3>
<p>처음부터 모든 로그를 timeline으로 만들지 않습니다. 도메인별로 운영 판단에 필요한 이벤트 타입을 10~20개만 고릅니다.</p>
<p>주문 도메인 예시는 아래와 같습니다.</p>
<table>
  <thead>
      <tr>
          <th>이벤트 타입</th>
          <th>visibility</th>
          <th>source</th>
          <th>보존</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>ORDER_CREATED</td>
          <td>public</td>
          <td>order service</td>
          <td>180일</td>
      </tr>
      <tr>
          <td>PAYMENT_AUTHORIZED</td>
          <td>public</td>
          <td>payment ledger</td>
          <td>180일</td>
      </tr>
      <tr>
          <td>PAYMENT_CONFIRMATION_DELAYED</td>
          <td>support</td>
          <td>reconciler</td>
          <td>180일</td>
      </tr>
      <tr>
          <td>ORDER_CANCEL_REQUESTED</td>
          <td>public</td>
          <td>order service</td>
          <td>180일</td>
      </tr>
      <tr>
          <td>REFUND_APPROVED_BY_OPERATOR</td>
          <td>security</td>
          <td>audit log</td>
          <td>1년 이상</td>
      </tr>
      <tr>
          <td>DELIVERY_PROVIDER_TIMEOUT</td>
          <td>operator</td>
          <td>adapter</td>
          <td>90일</td>
      </tr>
      <tr>
          <td>CORRECTION_JOB_APPLIED</td>
          <td>operator</td>
          <td>correction job</td>
          <td>1년</td>
      </tr>
  </tbody>
</table>
<p>이 표가 없으면 개발자는 각자 다른 이름으로 이벤트를 남깁니다. <code>payment_failed</code>, <code>payFail</code>, <code>PG_TIMEOUT</code>이 섞이면 검색과 집계가 깨집니다. 이벤트 타입은 enum처럼 관리하고, 삭제보다 deprecated 상태를 둡니다.</p>
<h3 id="2-쓰기-경로와-projection-경로를-분리한다">2) 쓰기 경로와 projection 경로를 분리한다</h3>
<p>Timeline 이벤트를 업무 트랜잭션 안에서 직접 화면 테이블에 쓰면 간단합니다. 하지만 화면 요구가 바뀔 때 핵심 쓰기 경로가 같이 흔들립니다. 실무에서는 원본 이벤트와 읽기 projection을 분리하는 편이 낫습니다.</p>
<p>권장 흐름:</p>
<ol>
<li>도메인 트랜잭션에서 outbox 또는 audit log에 원본 이벤트를 남긴다.</li>
<li>projector가 visibility, 문구, masking, sort key를 계산해 timeline 테이블에 반영한다.</li>
<li>화면 API는 timeline projection만 읽고, 고위험 상세는 별도 권한으로 audit log를 조회한다.</li>
<li>projection rebuild가 가능하도록 source_event_id와 projector_version을 저장한다.</li>
</ol>
<p>이 구조는 <a href="/learning/deep-dive/deep-dive-transactional-outbox-cdc/">Transactional Outbox + CDC</a>와도 맞습니다. 원본 이벤트가 남아 있으면 화면 projection이 깨져도 다시 만들 수 있습니다. 반대로 화면 테이블만 source of truth가 되면 문구 변경, 마스킹 정책 변경, 중복 제거 버그를 복구하기 어렵습니다.</p>
<h3 id="3-문구는-template-version으로-관리한다">3) 문구는 template version으로 관리한다</h3>
<p>Timeline은 사람이 읽어야 하므로 문구 품질이 중요합니다. 하지만 문구를 이벤트 payload에 완성된 문자열로 저장하면 나중에 수정하기 어렵습니다. 이벤트에는 <code>type</code>, <code>reason_code</code>, <code>actor</code>, <code>target</code>, <code>metadata</code>를 저장하고, 화면에서는 template version으로 렌더링합니다.</p>
<p>예시:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#ff79c6">template</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#ff79c6">type</span>: PAYMENT_CONFIRMATION_DELAYED
</span></span><span style="display:flex;"><span>  <span style="color:#ff79c6">version</span>: <span style="color:#bd93f9">3</span>
</span></span><span style="display:flex;"><span>  <span style="color:#ff79c6">public</span>: <span style="color:#f1fa8c">&#34;결제 확인이 지연되고 있습니다. 보통 몇 분 안에 자동 확인됩니다.&#34;</span>
</span></span><span style="display:flex;"><span>  <span style="color:#ff79c6">support</span>: <span style="color:#f1fa8c">&#34;PG 응답 지연으로 결제 확인 대기 상태입니다. 자동 재확인 예정: {next_check_at}&#34;</span>
</span></span><span style="display:flex;"><span>  <span style="color:#ff79c6">operator</span>: <span style="color:#f1fa8c">&#34;PG timeout. provider={provider}, retry={retry_count}, correlation_id={correlation_id}&#34;</span>
</span></span></code></pre></div><p>이렇게 하면 같은 이벤트도 대상별로 다르게 보여 줄 수 있습니다. public 문구는 불안을 줄이고, support 문구는 응대에 필요한 다음 시각을 주고, operator 문구는 원인 추적 키를 줍니다.</p>
<h3 id="4-정렬과-중복-제거를-명시한다">4) 정렬과 중복 제거를 명시한다</h3>
<p>Timeline에서 정렬은 생각보다 어렵습니다. 외부 결제 승인 이벤트가 주문 생성보다 늦게 들어왔지만 실제 발생 시각은 더 빠를 수 있습니다. 재처리 중 같은 이벤트가 두 번 들어올 수도 있습니다. 단순 <code>created_at desc</code>만 쓰면 운영자가 순서를 오해합니다.</p>
<p>기본 정책:</p>
<ul>
<li>primary sort: <code>occurred_at desc</code></li>
<li>tie breaker: <code>recorded_at desc</code>, <code>event_id desc</code></li>
<li>같은 <code>dedupe_key</code> 중복은 최신 projection만 표시</li>
<li>중복으로 합쳐진 이벤트는 support/operator 화면에서 &ldquo;3회 반복&quot;처럼 표시</li>
<li><code>occurred_at</code> 신뢰도가 낮은 외부 이벤트는 source label을 붙임</li>
</ul>
<p>중복 제거는 무조건 숨기는 것이 아닙니다. 고객 화면에서는 &ldquo;결제 확인 재시도 중&rdquo; 하나로 합쳐도 되지만, 운영 화면에서는 5분 동안 4회 실패했다는 사실이 중요할 수 있습니다. 따라서 dedupe 결과와 원본 count를 같이 저장합니다.</p>
<h3 id="5-timeline-api에도-성능-예산을-둔다">5) Timeline API에도 성능 예산을 둔다</h3>
<p>이력 화면은 장애 때 많이 열립니다. 평소에는 조용하다가 사고가 나면 CS와 운영자가 동시에 조회합니다. 그래서 timeline API에도 별도 예산이 필요합니다.</p>
<p>초기 기준:</p>
<ul>
<li>target 단건 timeline p95: 200ms 이하</li>
<li>page size: 기본 50개, 최대 100개</li>
<li>필터 없는 전역 feed: 최근 24시간 또는 1,000건 상한</li>
<li>operator 검색 기간: 기본 7일, 최대 90일은 async export</li>
<li>index: <code>(tenant_id, target_type, target_id, occurred_at desc)</code>, 보안 feed는 <code>(tenant_id, visibility, occurred_at desc)</code></li>
<li>payload: 이벤트 1개당 2KB 이하, raw metadata는 별도 상세 조회</li>
</ul>
<p>이 기준은 <a href="/learning/deep-dive/deep-dive-response-payload-budget-field-projection-playbook/">Response Payload Budget</a>과 연결됩니다. Timeline은 보기 편해야 하지만, 모든 metadata를 목록 응답에 넣으면 장애 때 화면 자체가 느려집니다.</p>
<h2 id="트레이드오프주의점">트레이드오프/주의점</h2>
<p>첫째, timeline을 너무 풍부하게 만들면 개인정보 저장소가 하나 더 생깁니다. 고객 이름, 이메일, 주소, 결제 수단, 외부 provider raw response를 이벤트 metadata에 넣으면 검색과 export 경로가 모두 민감해집니다. 기본은 식별자와 reason_code, 필요한 경우 hash 또는 redacted value입니다.</p>
<p>둘째, 감사 로그와 사용자 이력을 같은 테이블로 합치면 처음에는 편하지만 장기적으로 위험합니다. 감사 로그는 조작 방지, 보존, 접근 통제가 핵심이고, 사용자 이력은 읽기 UX와 문구 변경이 핵심입니다. 원본은 강하게, projection은 유연하게 가져가는 편이 좋습니다.</p>
<p>셋째, 모든 상태 변화를 이벤트로 만들 필요는 없습니다. 내부 캐시 갱신, projector heartbeat, batch cursor 이동처럼 운영 판단과 무관한 신호까지 넣으면 중요한 사건이 묻힙니다. 숨겨진 technical event는 metric과 로그로 충분한 경우가 많습니다.</p>
<p>넷째, timeline이 있다는 이유로 source of truth가 바뀌면 안 됩니다. 결제 상태는 결제 원장, 권한 상태는 권한 정책 저장소, 파일 공개 상태는 파일 상태 머신이 기준입니다. Timeline은 판단을 돕는 화면이지 업무 원장을 대신하지 않습니다.</p>
<p>다섯째, 이벤트 문구는 제품 언어입니다. &ldquo;PG_TIMEOUT&quot;을 그대로 고객에게 보여 주면 불안만 키웁니다. 반대로 운영자에게 &ldquo;문제가 발생했습니다&quot;만 보여 주면 조치할 수 없습니다. visibility별 문구를 분리해야 합니다.</p>
<h2 id="체크리스트-또는-연습">체크리스트 또는 연습</h2>
<ul>
<li><input disabled="" type="checkbox"> 도메인별 timeline 이벤트 타입 10~20개를 카탈로그로 정의했다.</li>
<li><input disabled="" type="checkbox"> 이벤트에는 actor, action/type, target, result, reason_code, visibility, occurred_at, recorded_at, correlation_id가 있다.</li>
<li><input disabled="" type="checkbox"> public/support/operator/security visibility 등급과 마스킹 정책이 분리되어 있다.</li>
<li><input disabled="" type="checkbox"> 원본 이벤트와 timeline projection이 분리되어 있고, projection rebuild가 가능하다.</li>
<li><input disabled="" type="checkbox"> timeline p95 반영 지연, API p95, page size, 보존 기간 기준이 숫자로 정해져 있다.</li>
<li><input disabled="" type="checkbox"> 결제·권한·개인정보·환불 같은 고위험 이벤트는 audit log와 correlation_id로 연결된다.</li>
<li><input disabled="" type="checkbox"> 이벤트 누락 또는 ingestion lag가 있을 때 화면에 지연/불완전 상태를 표시한다.</li>
</ul>
<p>연습으로 주문 하나를 골라 <code>ORDER_CREATED</code>, <code>PAYMENT_AUTHORIZED</code>, <code>DELIVERY_PROVIDER_TIMEOUT</code>, <code>REFUND_APPROVED_BY_OPERATOR</code> 네 이벤트를 설계해 보세요. 각 이벤트에 public/support/operator/security 중 어떤 visibility를 줄지, 고객 화면에는 어떤 문구를 보여 줄지, 감사 로그와 연결해야 하는 필드는 무엇인지 적어 보면 timeline 설계의 감이 빨리 잡힙니다.</p>
<h2 id="함께-보면-좋은-글">함께 보면 좋은 글</h2>
<ul>
<li><a href="/learning/deep-dive/deep-dive-operational-state-machine-design/">운영용 상태 머신 설계</a></li>
<li><a href="/learning/deep-dive/deep-dive-tamper-evident-audit-log-playbook/">Tamper-Evident Audit Log</a></li>
<li><a href="/learning/deep-dive/deep-dive-execution-receipt-operations-playbook/">Execution Receipt</a></li>
<li><a href="/learning/deep-dive/deep-dive-response-payload-budget-field-projection-playbook/">Response Payload Budget</a></li>
</ul>
]]></content:encoded></item></channel></rss>