ADR-009 PartnerAuditLog 별도 테이블 + 필터 레벨 비동기 기록
- 상태: 채택
- 날짜: 2026-07-03
- 근거: PRD FR-8 / Success Metrics(커버리지 100%) / AS-IS
McpAuditLogAsyncRecorder
맥락
Partner의 등록·수정 활동 감사 로그를 어디에·어떻게 남길지 결정한다. mcp에 비동기 기록기 패턴이 존재하나, 등록 요청은 기존 여러 컨트롤러에 분산돼 있고 파트너/비파트너 구분이 필요하다.
결정
- 별도 테이블
partner_audit_log—mcp_audit_logs미공유(도메인 격리, ADR-001). - 필터 레벨 기록 —
PartnerApiKeyAuthenticationFilter가 체인 완료 후(응답 status·latency 확보)PartnerActivityRecorder.record(...)호출. 필터는 모든 파트너 요청의 단일 통과점 → 구조적 100% 커버리지. - 비동기·비실패 —
PartnerActivityRecorderinterface(domain) /AsyncPartnerActivityRecorder(infra,@Async("partnerAuditExecutor")). 적재 실패는 요청을 실패시키지 않고 WARN 로그만(mcp 패턴). - 전용 스레드풀 — 등록 요청 P95(300ms)에 감사 I/O가 끼지 않게
partnerAuditExecutor분리(신규PartnerAsyncConfig, 기존AsyncConfig.kt미수정 → Single Writer 보호).
근거
- 필터는 등록/수정/조회 모든 파트너 요청을 통과 → AOP·컨트롤러 산개 대비 커버리지·구분이 구조적으로 해결.
- mcp가 AOP를 회피한 이력(CGLIB proxy 우회) + 등록 API 다컨트롤러 분산 → AOP 미채택.
- 도메인이 interface(
PartnerActivityRecorder)를 정의하고 infra가 구현 → 필터(infra)는 domain interface에만 의존(레이어 규칙 준수).
대안 (미채택)
mcp_audit_logs공유: 도메인 격리 위반(ADR-001), PRD FR-8 별도 테이블 명시.- AOP(@Around) 컨트롤러 부착: 등록 API 산개 + 파트너 구분 로직 필요, mcp의 CGLIB 이슈.
- 동기 기록: 등록 트랜잭션에 감사 I/O 결합 → P95 악화·감사 실패가 등록 실패로 전파.
영향
partner_audit_log: partnerId·userId·method·path·status_code·latency_ms·ip·userAgent·called_at. 인덱스(partner_id, called_at).- 커버리지 측정: access log 등록 건수 vs
partner_audit_log적재 건수 대조 → 누락 0건(Success Metric). - 감사 조회는 QueryDSL Custom Repository(
findBy(partnerId, from~to, paged)).