활동 로그 훅 레퍼런스 (Activity Log Hooks Reference)
모든 ActivityLog 리스너가 구독하는 훅의 전체 목록 (코어 + 모듈)
TL;DR (5초 요약)
목차
- 아키텍처 개요
- 코어 훅 (CoreActivityLogListener)
- 확장 모듈 훅
- 스냅샷/변경감지 패턴
- 새 모듈에 ActivityLog 추가하기
1. 아키텍처 개요
- Listener:
HookListenerInterface 구현, getSubscribedHooks()로 훅-메서드 매핑 정의
- 로그 기록:
Log::channel('activity')->info($action, $context) 직접 호출
- context 구조:
log_type, loggable, description_key, description_params, properties, changes
- LogType:
ActivityLogType::Admin (관리자 행위) / ActivityLogType::User (사용자 행위)
- 변경 감지:
ChangeDetector::detect($model, $snapshot) — 스냅샷과 현재 상태 비교
2. 코어 훅 (CoreActivityLogListener)
파일: app/Listeners/CoreActivityLogListener.php
총 66훅
User (8훅)
| 훅 이름 |
Listener 메서드 |
Action (DB) |
LogType |
Loggable |
core.user.after_create |
handleUserAfterCreate |
user.create |
Admin |
User |
core.user.after_update |
handleUserAfterUpdate |
user.update |
Admin |
User |
core.user.after_delete |
handleUserAfterDelete |
user.delete |
Admin |
User |
core.user.after_withdraw |
handleUserAfterWithdraw |
user.withdraw |
Admin |
User |
core.user.after_show |
handleUserAfterShow |
user.show |
Admin |
User |
core.user.after_list |
handleUserAfterList |
user.list |
Admin |
- |
core.user.after_search |
handleUserAfterSearch |
user.search |
Admin |
- |
sirsoft-core.user.after_bulk_update |
handleUserAfterBulkUpdate |
user.bulk_update |
Admin |
- |
Auth (9훅)
| 훅 이름 |
Listener 메서드 |
Action (DB) |
LogType |
Loggable |
core.auth.after_login |
handleAuthAfterLogin |
auth.login |
User |
User |
core.auth.logout |
handleAuthLogout |
auth.logout |
User |
User |
core.auth.register |
handleAuthRegister |
auth.register |
User |
User |
core.auth.forgot_password |
handleAuthForgotPassword |
auth.forgot_password |
User |
- |
core.auth.reset_password |
handleAuthResetPassword |
auth.reset_password |
User |
- |
core.auth.record_consents |
handleAuthRecordConsents |
auth.record_consents |
User |
User |
core.auth.login_failed |
handleAuthLoginFailed |
auth.login_failed |
User |
- |
core.auth.account_locked |
handleAuthAccountLocked |
auth.account_locked |
User |
User |
core.auth.account_unlocked |
handleAuthAccountUnlocked |
auth.account_unlocked |
User |
User |
Identity (3훅)
본인인증(IDV) 훅은 DTO(VerificationChallenge/VerificationResult)를 인자로 받으므로 sync => true 로 등록된다 — 큐 직렬화 대상에 POPO 가 포함되지 않아 큐로 넘기면 null 이 전달된다.
| 훅 이름 |
Listener 메서드 |
Action (DB) |
LogType |
Loggable |
core.identity.after_request |
handleIdentityRequested |
identity.request |
User |
- |
core.identity.after_verify |
handleIdentityVerified |
identity.verify / identity.verify_failed |
User |
- |
core.identity.challenge_expired |
handleIdentityExpired |
identity.expired |
User |
- |
Role (5훅)
| 훅 이름 |
Listener 메서드 |
Action (DB) |
LogType |
Loggable |
core.role.after_create |
handleRoleAfterCreate |
role.create |
Admin |
Role |
core.role.after_update |
handleRoleAfterUpdate |
role.update |
Admin |
Role |
core.role.after_delete |
handleRoleAfterDelete |
role.delete |
Admin |
Role |
core.role.after_sync_permissions |
handleRoleAfterSyncPermissions |
role.sync_permissions |
Admin |
Role |
core.role.after_toggle_status |
handleRoleAfterToggleStatus |
role.toggle_status |
Admin |
Role |
| 훅 이름 |
Listener 메서드 |
Action (DB) |
LogType |
Loggable |
core.menu.after_create |
handleMenuAfterCreate |
menu.create |
Admin |
Menu |
core.menu.after_update |
handleMenuAfterUpdate |
menu.update |
Admin |
Menu |
core.menu.after_delete |
handleMenuAfterDelete |
menu.delete |
Admin |
Menu |
core.menu.after_update_order |
handleMenuAfterUpdateOrder |
menu.update_order |
Admin |
- |
core.menu.after_toggle_status |
handleMenuAfterToggleStatus |
menu.toggle_status |
Admin |
Menu |
core.menu.after_sync_roles |
handleMenuAfterSyncRoles |
menu.sync_roles |
Admin |
Menu |
Settings (2훅)
| 훅 이름 |
Listener 메서드 |
Action (DB) |
LogType |
Loggable |
core.settings.after_save |
handleSettingsAfterSave |
settings.save |
Admin |
- |
core.settings.after_set |
handleSettingsAfterSet |
settings.set |
Admin |
- |
Schedule (6훅)
| 훅 이름 |
Listener 메서드 |
Action (DB) |
LogType |
Loggable |
core.schedule.after_create |
handleScheduleAfterCreate |
schedule.create |
Admin |
Schedule |
core.schedule.after_update |
handleScheduleAfterUpdate |
schedule.update |
Admin |
Schedule |
core.schedule.after_delete |
handleScheduleAfterDelete |
schedule.delete |
Admin |
Schedule |
core.schedule.after_run |
handleScheduleAfterRun |
schedule.run |
Admin |
Schedule |
core.schedule.after_bulk_update |
handleScheduleAfterBulkUpdate |
schedule.bulk_update |
Admin |
- |
core.schedule.after_bulk_delete |
handleScheduleAfterBulkDelete |
schedule.bulk_delete |
Admin |
- |
Attachment (3훅)
| 훅 이름 |
Listener 메서드 |
Action (DB) |
LogType |
Loggable |
core.attachment.after_upload |
handleAttachmentAfterUpload |
attachment.upload |
Admin |
Attachment |
core.attachment.after_delete |
handleAttachmentAfterDelete |
attachment.delete |
Admin |
Attachment |
core.attachment.after_bulk_delete |
handleAttachmentAfterBulkDelete |
attachment.bulk_delete |
Admin |
- |
Module (6훅)
| 훅 이름 |
Listener 메서드 |
Action (DB) |
LogType |
Loggable |
core.modules.after_install |
handleModuleAfterInstall |
module.install |
Admin |
- |
core.modules.after_activate |
handleModuleAfterActivate |
module.activate |
Admin |
- |
core.modules.after_deactivate |
handleModuleAfterDeactivate |
module.deactivate |
Admin |
- |
core.modules.after_uninstall |
handleModuleAfterUninstall |
module.uninstall |
Admin |
- |
core.modules.after_update |
handleModuleAfterUpdate |
module.update |
Admin |
- |
core.modules.after_refresh_layouts |
handleModuleAfterRefreshLayouts |
module.refresh_layouts |
Admin |
- |
Plugin (5훅)
| 훅 이름 |
Listener 메서드 |
Action (DB) |
LogType |
Loggable |
core.plugins.after_install |
handlePluginAfterInstall |
plugin.install |
Admin |
- |
core.plugins.after_activate |
handlePluginAfterActivate |
plugin.activate |
Admin |
- |
core.plugins.after_deactivate |
handlePluginAfterDeactivate |
plugin.deactivate |
Admin |
- |
core.plugins.after_uninstall |
handlePluginAfterUninstall |
plugin.uninstall |
Admin |
- |
core.plugins.after_update |
handlePluginAfterUpdate |
plugin.update |
Admin |
- |
Template (6훅)
| 훅 이름 |
Listener 메서드 |
Action (DB) |
LogType |
Loggable |
core.templates.after_install |
handleTemplateAfterInstall |
template.install |
Admin |
- |
core.templates.after_activate |
handleTemplateAfterActivate |
template.activate |
Admin |
- |
core.templates.after_deactivate |
handleTemplateAfterDeactivate |
template.deactivate |
Admin |
- |
core.templates.after_uninstall |
handleTemplateAfterUninstall |
template.uninstall |
Admin |
- |
core.templates.after_version_update |
handleTemplateAfterVersionUpdate |
template.version_update |
Admin |
- |
core.templates.after_refresh_layouts |
handleTemplateAfterRefreshLayouts |
template.refresh_layouts |
Admin |
- |
Extension 공통 (1훅)
템플릿·모듈·플러그인 세 타입이 같은 훅을 공유한다 (권한도 core.extensions.custom_assets.manage 하나다).
| 훅 이름 |
Listener 메서드 |
Action (DB) |
LogType |
Loggable |
core.custom_assets.after_change |
handleCustomAssetAfterChange |
custom_asset.{save|upload|delete} |
Admin |
운영자 CSS·JS 는 사이트 전 화면에서 실행되므로 변경 이력이 남아야 한다 |
Layout (2훅)
| 훅 이름 |
Listener 메서드 |
Action (DB) |
LogType |
Loggable |
core.layout.after_update |
handleLayoutAfterUpdate |
layout.update |
Admin |
- |
core.layout.after_version_restore |
handleLayoutAfterVersionRestore |
layout.version_restore |
Admin |
- |
Module Settings (2훅)
| 훅 이름 |
Listener 메서드 |
Action (DB) |
LogType |
Loggable |
core.module_settings.after_save |
handleModuleSettingsAfterSave |
module_settings.save |
Admin |
- |
core.module_settings.after_reset |
handleModuleSettingsAfterReset |
module_settings.reset |
Admin |
- |
Plugin Settings (2훅)
| 훅 이름 |
Listener 메서드 |
Action (DB) |
LogType |
Loggable |
core.plugin_settings.after_save |
handlePluginSettingsAfterSave |
plugin_settings.save |
Admin |
- |
core.plugin_settings.after_reset |
handlePluginSettingsAfterReset |
plugin_settings.reset |
Admin |
- |
3. 확장 모듈 훅
확장이 구독하는 활동 로그 훅 목록은 그 확장이 소유합니다(#601). 확장이 훅을 추가할 때
코어 문서를 고쳐야 하는 역방향 의존을 없애기 위해서이며, 코어에는 아래 총계와 링크만 남습니다.
코어 66훅 + 확장 132훅 = 총 198훅입니다.
확장에 새 활동 로그 항목을 추가할 때도 다국어 키는 코어가 SSoT 입니다 — action 라벨과
description 본문을 코어 lang/{ko,en}/activity_log.php 에 정의해야 하며, 모듈 lang 파일에
넣으면 해석되지 않습니다. 번들 일본어 팩도 같은 작업 단위에서 동기화합니다.
4. 스냅샷/변경감지 패턴
ActivityLog에서 수정(update) 작업의 변경 이력을 기록하려면 스냅샷 패턴을 사용합니다.
동작 흐름
코드 예시
ChangeDetector
파일: app/ActivityLog/ChangeDetector.php
- 모델의
$activityLogFields 속성에 정의된 필드만 비교
- 각 필드의
label_key (다국어 키)를 포함한 구조화된 변경 이력 생성
BackedEnum 자동 변환 지원
- 스냅샷이
null이면 null 반환 (변경 없음)
스냅샷은 Service 가 잡아 넘긴다
리스너는 before_* 훅을 구독해 스냅샷을 잡지 않습니다. Service 가 수정 직전에 스냅샷을
만들어 after_* 훅의 인자로 넘기고, 리스너는 그것을 ChangeDetector::detect() 에 그대로
전달합니다:
before_* 훅 자체는 발행되므로 다른 확장이 구독할 수 있습니다 — 다만 활동 로그 리스너의
구독 대상은 아닙니다. 확장별 구독 목록에서 before_* 가 보이지 않는 것은 누락이 아니라
이 구조 때문입니다.
5. 새 모듈에 ActivityLog 추가하기
Step 1: Listener 클래스 생성
Step 2: module.php에 Listener 등록
Step 3: 다국어 파일에 description_key 정의
Step 4: 모델에 $activityLogFields 정의 (ChangeDetector 사용 시)
Step 5: 테스트 작성
훅 네이밍 규칙
| 패턴 |
용도 |
Priority |
{module}.{entity}.before_update |
스냅샷 캡처 |
5 (높은 우선순위) |
{module}.{entity}.after_create |
생성 로그 |
20 |
{module}.{entity}.after_update |
수정 로그 (변경감지) |
20 |
{module}.{entity}.after_delete |
삭제 로그 |
20 |
{module}.{entity}.after_bulk_* |
일괄 작업 로그 |
20 |
{module}.{entity}.after_toggle_* |
상태 전환 로그 |
20 |
context 구조
| 키 |
타입 |
설명 |
필수 |
log_type |
ActivityLogType |
Admin 또는 User |
O |
loggable |
Model |
대상 모델 (polymorphic) |
- |
description_key |
string |
다국어 설명 키 |
O |
description_params |
array |
설명 파라미터 |
- |
properties |
array |
추가 속성 (JSON) |
- |
changes |
array|null |
ChangeDetector 결과 |
- |