docs: 활동 로그 시스템 문서 업데이트

api.md에 GET /admin/logs 명세 추가, architecture.md에
logs 테이블/파일 추가, development.md에 로그 시스템 가이드 추가,
logs.md를 실제 구현 결과에 맞게 갱신.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
caadiq 2026-03-02 17:08:35 +09:00
parent 414b798914
commit aa6c05e6b5
4 changed files with 109 additions and 90 deletions

View file

@ -522,6 +522,56 @@ X 일정 저장
---
## 관리자 - 활동 로그 (인증 필요)
### GET /admin/logs
활동 로그 목록 조회
**Query Parameters:**
- `page` - 페이지 번호 (기본 1)
- `limit` - 페이지당 개수 (기본 50, 최대 100)
- `category` - 카테고리 필터 (콤마 구분: album, schedule, member, bot, category, dict, concert, sync)
- `actor` - 행위자 필터 (admin 또는 bot)
- `search` - summary 텍스트 검색
- `from` - 시작 날짜 (YYYY-MM-DD)
- `to` - 종료 날짜 (YYYY-MM-DD)
**응답:**
```json
{
"logs": [
{
"id": 1,
"actor": "admin",
"action": "create",
"category": "album",
"target_type": "album",
"target_id": 12,
"summary": "앨범 생성: Unlock My World",
"details": null,
"created_at": "2026-03-02 14:30:00"
}
],
"total": 150,
"page": 1,
"limit": 50,
"totalPages": 3
}
```
**actor 값:**
- `"admin"` - 관리자 수동 작업
- `"youtube-{id}"` - YouTube 봇 (예: youtube-3)
- `"x-{id}"` - X 봇 (예: x-1)
**action 값:**
- `create`, `update`, `delete`, `upload` - CRUD 작업
- `start`, `stop` - 봇 시작/정지
- `sync_complete` - 봇 동기화 완료
- `error` - 봇 동기화 에러
---
## 헬스 체크
### GET /health

View file

@ -21,7 +21,8 @@ fromis_9/
│ │ │ │ ├── youtube-bots.js # YouTube 봇 CRUD
│ │ │ │ ├── x-bots.js # X 봇 CRUD
│ │ │ │ ├── youtube.js # YouTube 일정 관리
│ │ │ │ └── x.js # X 일정 관리
│ │ │ │ ├── x.js # X 일정 관리
│ │ │ │ └── logs.js # 활동 로그 조회
│ │ │ ├── albums/
│ │ │ │ ├── index.js # 앨범 CRUD
│ │ │ │ ├── photos.js # 앨범 사진 관리
@ -46,6 +47,7 @@ fromis_9/
│ │ │ ├── cache.js # Redis 캐시 헬퍼 (SCAN 사용)
│ │ │ ├── date.js # 날짜 유틸 (KST 변환)
│ │ │ ├── error.js # 에러 응답 헬퍼
│ │ │ ├── log.js # 활동 로그 유틸 (fire-and-forget)
│ │ │ ├── logger.js # 로깅 유틸
│ │ │ └── transaction.js # DB 트랜잭션 래퍼
│ │ ├── app.js # Fastify 앱 설정
@ -69,6 +71,7 @@ fromis_9/
│ │ │ ├── categories.js
│ │ │ ├── stats.js
│ │ │ ├── bots.js
│ │ │ ├── logs.js
│ │ │ ├── auth.js
│ │ │ └── suggestions.js
│ │ │
@ -204,6 +207,8 @@ fromis_9/
│ │ │ │ │ ├── Albums.jsx
│ │ │ │ │ ├── AlbumForm.jsx
│ │ │ │ │ └── AlbumPhotos.jsx
│ │ │ │ ├── logs/
│ │ │ │ │ └── Logs.jsx
│ │ │ │ └── schedules/
│ │ │ │ ├── Schedules.jsx
│ │ │ │ ├── ScheduleForm.jsx
@ -286,7 +291,7 @@ fromis_9/
## 데이터베이스
### 테이블 목록 (27개)
### 테이블 목록 (28개)
#### 사용자/인증
- `admin_users` - 관리자 계정
@ -322,6 +327,9 @@ fromis_9/
- `bot_youtube` - YouTube 봇 설정 (채널 정보, 동기화 간격, 필터 등, video_id UNIQUE)
- `bot_x` - X 봇 설정 (username, 프로필, 동기화 간격, 텍스트 필터, 리트윗 포함, YouTube 추출)
#### 활동 로그
- `logs` - 관리자/봇 활동 로그 (actor, action, category, summary 등)
#### 이미지
- `images` - 이미지 메타데이터 (3개 해상도 URL)

View file

@ -283,6 +283,34 @@ queryClient.invalidateQueries();
---
## 활동 로그 시스템
관리자/봇의 모든 활동을 `logs` 테이블에 기록하고 관리자 페이지에서 조회.
### 로그 기록 방법
```js
import { logActivity } from '../utils/log.js';
// fire-and-forget: 로그 실패가 비즈니스 로직에 영향 주지 않음
logActivity(db, {
actor: 'admin', // "admin" 또는 봇 ID ("youtube-3", "x-1")
action: 'create', // create, update, delete, upload, start, stop, sync_complete, error
category: 'album', // album, schedule, member, bot, category, dict, concert, sync
targetType: 'album', // 대상 타입 (optional)
targetId: 12, // 대상 DB ID (optional)
summary: '앨범 생성: 제목', // 한 줄 요약
details: { key: 'value' }, // 추가 정보 JSON (optional)
});
```
### 로그 대상
- **관리자 라우트**: 앨범/일정/멤버/봇/카테고리/사전/콘서트 CRUD
- **봇 스케줄러**: 동기화 완료(addedCount > 0), 동기화 에러
- **봇 서비스**: YouTube 영상 추가, X 트윗 추가
---
## 유용한 명령어
```bash

View file

@ -9,10 +9,10 @@
## DB 테이블
### `activity_logs`
### `logs`
```sql
CREATE TABLE activity_logs (
CREATE TABLE logs (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
actor VARCHAR(50) NOT NULL, -- "admin" 또는 봇 ID ("youtube-3", "x-1" 등)
action VARCHAR(50) NOT NULL, -- create, update, delete, start, stop, sync_complete, error 등
@ -33,7 +33,7 @@ CREATE TABLE activity_logs (
| 컬럼 | 설명 | 예시 |
|------|------|------|
| `actor` | 행위자 | `"admin"`, `"youtube-3"`, `"x-1"`, `"meilisearch"` |
| `action` | 행동 유형 | `create`, `update`, `delete`, `upload`, `start`, `stop`, `sync_complete`, `error`, `reorder` |
| `action` | 행동 유형 | `create`, `update`, `delete`, `upload`, `start`, `stop`, `sync_complete`, `error` |
| `category` | 대분류 | `album`, `schedule`, `member`, `bot`, `category`, `dict`, `concert`, `sync` |
| `target_type` | 대상 타입 | `youtube_schedule`, `x_schedule`, `album`, `photo`, `teaser`, `member`, `youtube_bot`, `x_bot`, `category`, `concert` |
| `target_id` | 대상 DB ID | 해당 레코드의 PK |
@ -46,10 +46,12 @@ CREATE TABLE activity_logs (
### 로그 유틸리티
**파일:** `backend/src/utils/activityLog.js`
**파일:** `backend/src/utils/log.js`
```javascript
logActivity(db, { actor, action, category, targetType, targetId, summary, details })
import { logActivity } from '../utils/log.js';
logActivity(db, { actor, action, category, targetType, targetId, summary, details });
```
- fire-and-forget: 로그 실패가 비즈니스 로직에 영향 주지 않도록 try/catch 감싸기
@ -57,7 +59,7 @@ logActivity(db, { actor, action, category, targetType, targetId, summary, detail
### API 엔드포인트
**GET /api/admin/activity-logs** — 로그 목록 조회 (인증 필수)
**GET /api/admin/logs** — 로그 목록 조회 (인증 필수)
| 파라미터 | 타입 | 기본값 | 설명 |
|----------|------|--------|------|
@ -69,29 +71,6 @@ logActivity(db, { actor, action, category, targetType, targetId, summary, detail
| `from` | string | - | 시작 날짜 (YYYY-MM-DD) |
| `to` | string | - | 종료 날짜 (YYYY-MM-DD) |
**응답:**
```json
{
"logs": [
{
"id": 1,
"actor": "admin",
"action": "create",
"category": "schedule",
"target_type": "youtube_schedule",
"target_id": 456,
"summary": "YouTube 일정 생성: fromis_9 영상 제목",
"details": { "videoId": "abc123", "channelName": "채널명" },
"created_at": "2026-03-01T14:30:00"
}
],
"total": 1234,
"page": 1,
"limit": 50,
"totalPages": 25
}
```
### 로그 삽입 대상
#### 관리자 수동 작업
@ -108,7 +87,7 @@ logActivity(db, { actor, action, category, targetType, targetId, summary, detail
| `routes/albums/photos.js` | 사진 업로드/삭제 |
| `routes/albums/teasers.js` | 티저 삭제 |
| `routes/members/index.js` | 멤버 수정 |
| `routes/schedules/index.js` | 일정 삭제, 카테고리 CRUD, 순서변경 |
| `routes/schedules/index.js` | 일정 삭제, 카테고리 CRUD |
| `routes/schedules/suggestions.js` | 사전 저장 |
#### 봇 자동 작업
@ -125,73 +104,27 @@ logActivity(db, { actor, action, category, targetType, targetId, summary, detail
## 프론트엔드 구현
### 파일 구조
| 파일 | 내용 |
|------|------|
| `frontend/src/api/admin/logs.js` | API 클라이언트 |
| `frontend/src/pages/pc/admin/logs/Logs.jsx` | 로그 페이지 컴포넌트 |
### 로그 페이지
**경로:** `/admin/logs`
**UI 구성:**
- 필터 바: 카테고리 칩, 행위자 드롭다운, 기간 선택, 텍스트 검색
- 로그 테이블: 시간, 행위자(아이콘), 액션 뱃지(색상별), summary
- 페이지네이션
- 필터 바: 카테고리 칩, 행위자 드롭다운(애니메이션), 기간 선택(커스텀 DatePicker), 텍스트 검색(300ms 디바운스)
- 로그 테이블: 시간, 행위자(아이콘), 액션 뱃지(색상별), 카테고리, summary
- 서버 사이드 페이지네이션 (keepPreviousData로 깜빡임 방지)
**액션 뱃지 색상:**
| 액션 | 색상 |
|------|------|
| create / upload | 초록 |
| update / reorder | 파랑 |
| delete | 빨강 |
| update | 파랑 |
| delete / error | 빨강 |
| sync_complete | 보라 |
| error | 빨강 |
| start / stop | 노랑 |
### 대시보드 메뉴
대시보드 menuItems에 활동 로그 항목 추가 (ScrollText 아이콘)
---
## 수정 파일 목록
### 신규 생성 (4개)
| 파일 | 내용 |
|------|------|
| `backend/src/utils/activityLog.js` | logActivity 유틸리티 함수 |
| `backend/src/routes/admin/activity-logs.js` | API 엔드포인트 |
| `frontend/src/api/admin/activityLogs.js` | API 클라이언트 |
| `frontend/src/pages/pc/admin/logs/ActivityLogs.jsx` | 로그 페이지 컴포넌트 |
### 수정 (백엔드 15개 + 프론트엔드 3개)
| 파일 | 변경 |
|------|------|
| `backend/src/routes/index.js` | 라우트 등록 |
| `backend/src/routes/admin/youtube.js` | logActivity 호출 |
| `backend/src/routes/admin/x.js` | logActivity 호출 |
| `backend/src/routes/admin/concert.js` | logActivity 호출 |
| `backend/src/routes/admin/youtube-bots.js` | logActivity 호출 |
| `backend/src/routes/admin/x-bots.js` | logActivity 호출 |
| `backend/src/routes/admin/bots.js` | logActivity 호출 |
| `backend/src/routes/albums/index.js` | logActivity 호출 |
| `backend/src/routes/albums/photos.js` | logActivity 호출 |
| `backend/src/routes/albums/teasers.js` | logActivity 호출 |
| `backend/src/routes/members/index.js` | logActivity 호출 |
| `backend/src/routes/schedules/index.js` | logActivity 호출 |
| `backend/src/routes/schedules/suggestions.js` | logActivity 호출 |
| `backend/src/plugins/scheduler.js` | 동기화 로그 |
| `backend/src/services/youtube/index.js` | 영상 추가 로그 |
| `backend/src/services/x/index.js` | 트윗 추가 로그 |
| `frontend/src/api/admin/index.js` | export 추가 |
| `frontend/src/routes/pc/admin/index.jsx` | 라우트 등록 |
| `frontend/src/pages/pc/admin/dashboard/Dashboard.jsx` | 메뉴 추가 |
---
## 구현 순서
1. DB 테이블 생성
2. 백엔드: logActivity 유틸리티 + API 엔드포인트 + 라우트 등록
3. 백엔드: 각 라우트/서비스에 logActivity 호출 추가
4. 프론트엔드: API 클라이언트 + 로그 페이지 + 라우트/대시보드 연결
5. 서버 재빌드 + 테스트
6. 문서 업데이트