본문으로 건너뛰기

Activity Log 모듈

학원 관리자·강사의 주요 행동을 자동으로 감사 로그(append-only)로 기록하고 커서 기반으로 조회하는 모듈입니다.

모듈 개요

항목내용
Gradle 서브프로젝트modules/activity-log
베이스 패키지com.lumie.activitylog
데이터베이스PostgreSQL (RLS, activity_logs 테이블)
수집 방식ActivityLogInterceptor (Spring MVC HandlerInterceptor)
외부 노출 internal-apiActivityLogService

주요 책임

  • HTTP 요청 완료 후 자동으로 감사 로그 삽입 (ActivityLogInterceptor)
  • 성공 응답(HTTP 2xx)에 한해서만 로그를 생성
  • 엔티티 유형·액션 유형을 URL 패턴과 HTTP 메서드에서 자동 추론
  • 커서 기반 페이지네이션으로 로그 목록 조회
  • ActivityLogService 인터페이스를 통해 다른 모듈이 직접 로그를 삽입 가능

도메인 모델

ActivityLog 엔티티

@Entity
@Table(name = "activity_logs")
public class ActivityLog extends AppendOnlyEntity {
Long id;
Long actorId;
String actorName;
Role actorRole; // Postgres enum: actor_role_type
ActionType action; // Postgres enum: activity_action_type
EntityType entityType; // Postgres enum: activity_entity_type
Long entityId;
String entityName;
String description;
Long tenantId; // @PrePersist로 자동 주입
}

AppendOnlyEntitycreated_at만 제공합니다. 활동 로그는 한 번 삽입 후 변경되지 않으므로 updated_at이 없습니다. tenant_idTenantScopedEntity를 상속하지 않고 직접 선언하여 불필요한 updated_at 컬럼 추가를 피합니다.

ActionType (Postgres enum)

매핑
CREATEPOST (일반)
UPDATEPUT / PATCH
DELETEDELETE
VIEWGET
DEACTIVATEPOST */deactivate
REACTIVATEPOST */reactivate
TERMINATEPOST */terminate
CHECK_INPOST */check-in
SENDPOST */send*
CLOSEPOST */close

EntityType (Postgres enum)

인터셉터가 URL 패턴으로 자동 매핑하는 엔티티 유형입니다.

URL 패턴EntityType
/v1/classes/*CLASS
/v1/classes/*/enrollments/**ENROLLMENT
/v1/students/**STUDENT
/v1/lectures/**LECTURE
/v1/assignments/**ASSIGNMENT
/v1/exams/**EXAM
/v1/sms/**SMS
/v1/attendance/**ATTENDANCE
/v1/files/**FILE
기타 다수(인터셉터 PATH_TO_ENTITY 맵 참조)

자동 로깅 메커니즘

ActivityLogInterceptor는 Spring MVC HandlerInterceptor로 등록되어 afterCompletion 시점에 실행됩니다.

HTTP 요청 완료

ActivityLogInterceptor.afterCompletion()
├─ ActivityLogContext.isLogged() → 이미 로깅됨이면 스킵
├─ UserId 없으면 스킵 (미인증 요청)
├─ HTTP 4xx/5xx이면 스킵
├─ URL 패턴으로 EntityType 결정
├─ HTTP 메서드 + URL suffix로 ActionType 결정
└─ ActivityLogService.log() 호출 → activity_logs INSERT

다른 모듈에서 세밀한 제어가 필요한 경우 ActivityLogContext.markLogged()로 인터셉터 자동 삽입을 억제하고 ActivityLogService를 직접 주입해 로그를 남길 수 있습니다.

REST API

기본 경로: /v1/activity-logs

메서드경로설명
GET/v1/activity-logs활동 로그 조회 (커서 기반 페이지네이션)

쿼리 파라미터

파라미터설명기본값
actorId특정 사용자 행동만 필터-
entityType엔티티 유형 필터-
startDate시작일 (ISO 날짜)-
endDate종료일 (ISO 날짜)-
search엔티티 이름 등 키워드 검색-
cursor다음 페이지 커서-
limit페이지 크기 (최대 100)30

응답 타입: CursorResponse<ActivityLogResponse>

내부 API (libs/internal-api)

public interface ActivityLogService {
void log(Long actorId, String actorName, String actorRole,
String action, String entityType, Long entityId,
String entityName, String description);
}

ActivityLogServiceAdapter(adapter/in/internal/)가 이를 구현합니다. 다른 모듈에서 인터셉터가 자동 포착하지 못하는 비즈니스 이벤트를 직접 기록할 때 사용합니다.

멀티테넌시

activity_logs 테이블에 tenant_id BIGINT NOT NULL이 있으며 RLS 정책이 적용됩니다. @PrePersist에서 TenantContextHolder.getRequiredTenantId()로 자동 주입됩니다.

관련 문서