- Phase 1,2,4,5 로컬 코드 작업 완료 반영 - 변경 이력 14건 추가 - 잔여 작업: 서버 배포 3건 (1.3, 3.1, 3.2) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
29 KiB
29 KiB
DB 백업 시스템 계획
작성일: 2026-01-30 목적: OS 레벨 백업(쉘 스크립트) + Laravel 모니터링 절충안으로 DB 백업 시스템 구축 기준 문서:
docs/architecture/system-overview.md,docs/specs/database-schema.md상태: 🔄 진행중
📍 현재 진행 상태
| 항목 | 내용 |
|---|---|
| 마지막 완료 작업 | Phase 5.4: 시스템 알림 Blade 페이지 + 라우트 등록 |
| 다음 작업 | Phase 1.3: 개발서버 스크립트 테스트 / Phase 3: 서버 배포 |
| 진행률 | 11/14 (79%) — 서버 작업 3건 잔여 |
| 마지막 업데이트 | 2026-01-31 |
1. 개요
1.1 배경
SAM 프로젝트의 개발서버(114.203.209.83)를 당분간 운영 환경처럼 사용할 예정이므로, 데이터 손실 방지를 위한 DB 백업 시스템이 필요하다. 운영서버에도 동일 구조로 적용할 수 있도록 설계한다.
대상 데이터베이스:
sam— 메인 비즈니스 데이터 (개발서버),samdb(로컬 Docker)sam_stat— 통계 데이터 (재집계 가능하나 함께 백업)
1.2 기준 원칙
┌─────────────────────────────────────────────────────────────────┐
│ 🎯 핵심 원칙 │
├─────────────────────────────────────────────────────────────────┤
│ 1. 백업은 OS 레벨(crontab)에서 실행 — 앱 장애와 무관하게 동작 │
│ 2. 모니터링은 Laravel에서 — 기존 stat_alerts 인프라 활용 │
│ 3. 환경 이식성 — backup.conf만 수정하면 운영서버에서도 동작 │
└─────────────────────────────────────────────────────────────────┘
1.3 변경 승인 정책
| 분류 | 예시 | 승인 |
|---|---|---|
| ✅ 즉시 가능 | 스크립트 파일 생성, .conf 파일 생성, 문서 수정 | 불필요 |
| ⚠️ 컨펌 필요 | StatMonitorService 수정, 스케줄러 등록, crontab 등록 | 필수 |
| 🔴 금지 | 기존 테이블 구조 변경, 기존 스케줄 시간 변경 | 별도 협의 |
1.4 준수 규칙
docs/quickstart/quick-start.md- 빠른 시작 가이드docs/standards/quality-checklist.md- 품질 체크리스트docs/standards/api-rules.md- API 개발 규칙 (Service-First)
1.5 환경 정보
개발서버 (배포 대상)
SSH: hskwon@114.203.209.83
API 경로: /home/webservice/api
MNG 경로: /home/webservice/mng
MySQL: 8.0.44
DB 사용자: codebridge / code**bridge
DB명: sam (메인), sam_stat (통계)
※ 로컬 Docker에서는 samdb (메인)
Git remote: /data/GIT/samproject/sam-api (bare repo, post-receive hook으로 auto-deploy)
MNG remote: /data/GIT/samproject/sam-mng
로컬 (코드 작업)
프로젝트 루트: /Users/kent/Works/@KD_SAM/SAM/
API: api/ (Laravel 12, PHP 8.4)
MNG: mng/ (Laravel 12, Plain Blade + HTMX + Tailwind)
Docker: docker/ (docker-compose.yml)
로컬 DB: samdb (메인), sam_stat (통계), samuser/sampass
배포 프로세스
로컬에서 코드 작성
→ git add + git commit
→ git push origin develop (api)
→ 개발서버 post-receive hook이 자동 pull + migrate
→ MNG도 동일 (git push → auto-deploy)
1.6 기존 코드 참조 (필수 읽기)
새 세션에서 작업 시작 전 반드시 읽어야 할 기존 코드:
| 파일 | 이유 | Phase |
|---|---|---|
api/app/Services/Stats/StatMonitorService.php |
recordBackupFailure() 추가 대상 | 2, 4 |
api/app/Models/Stats/BaseStatModel.php |
sam_stat 연결 패턴 ($connection = 'sam_stat') | 5 |
api/app/Models/Stats/StatAlert.php |
알림 모델 구조 (MNG용 모델 생성 참조) | 5 |
api/routes/console.php |
기존 스케줄러 패턴 (Schedule::command 형식) | 2 |
mng/app/Http/Controllers/AuditLogController.php |
MNG 컨트롤러 패턴 (필터+페이지네이션) | 5 |
mng/routes/web.php |
MNG 라우트 등록 패턴 | 5 |
stat_alerts 테이블 스키마
-- sam_stat 데이터베이스
CREATE TABLE stat_alerts (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
tenant_id INT UNSIGNED NOT NULL,
alert_type VARCHAR(50) NOT NULL, -- aggregation_failure, missing_data, data_mismatch, backup_failure
domain VARCHAR(50) NOT NULL, -- sales, finance, production, backup, system 등
severity ENUM('info','warning','critical') NOT NULL,
title VARCHAR(200) NOT NULL,
message TEXT,
current_value DECIMAL(15,2) NULL,
threshold_value DECIMAL(15,2) NULL,
is_read TINYINT(1) DEFAULT 0,
is_resolved TINYINT(1) DEFAULT 0,
resolved_at TIMESTAMP NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
BaseStatModel 패턴 (API)
// api/app/Models/Stats/BaseStatModel.php
abstract class BaseStatModel extends Model {
protected $connection = 'sam_stat';
protected $guarded = ['id'];
}
// api/app/Models/Stats/StatAlert.php
class StatAlert extends BaseStatModel {
protected $table = 'stat_alerts';
public $timestamps = false;
protected $casts = [
'current_value' => 'decimal:2',
'threshold_value' => 'decimal:2',
'is_read' => 'boolean',
'is_resolved' => 'boolean',
'resolved_at' => 'datetime',
'created_at' => 'datetime',
];
}
StatMonitorService 현재 메서드
// api/app/Services/Stats/StatMonitorService.php
class StatMonitorService {
public function recordAggregationFailure(int $tenantId, string $domain, string $jobType, string $errorMessage): void
public function recordMissingData(int $tenantId, string $domain, string $date): void
public function recordMismatch(int $tenantId, string $domain, string $label, float|int $expected, float|int $actual): void
public function resolveAlerts(int $tenantId, string $domain, string $alertType): int
}
// 모든 메서드는 try/catch로 감싸져 있음 (실패해도 비즈니스 로직 차단 안 함)
routes/console.php 스케줄 등록 패턴
// 기존 패턴 — 이 형식을 따라야 함
Schedule::command('db:backup-check')
->dailyAt('05:00')
->appendOutputTo(storage_path('logs/scheduler.log'))
->onSuccess(function () {
\Illuminate\Support\Facades\Log::info('✅ db:backup-check 스케줄러 실행 성공', ['time' => now()]);
})
->onFailure(function () {
\Illuminate\Support\Facades\Log::error('❌ db:backup-check 스케줄러 실행 실패', ['time' => now()]);
});
MNG 컨트롤러 패턴
// mng/app/Http/Controllers/AuditLogController.php (참조 패턴)
class AuditLogController extends Controller {
public function index(Request $request): View {
$query = Model::query()->orderByDesc('created_at');
// 필터 적용 (if $request->filled('xxx'))
// 페이지네이션: $query->paginate(50)->withQueryString()
return view('...', compact(...));
}
}
MNG 라우트 등록 패턴
// mng/routes/web.php (기존 패턴)
Route::prefix('audit-logs')->name('audit-logs.')->group(function () {
Route::get('/', [AuditLogController::class, 'index'])->name('index');
Route::get('/{id}', [AuditLogController::class, 'show'])->name('show');
});
// 새로 추가할 패턴
Route::prefix('system/alerts')->name('system.alerts.')->group(function () {
Route::get('/', [SystemAlertController::class, 'index'])->name('index');
Route::post('/{id}/read', [SystemAlertController::class, 'markAsRead'])->name('read');
Route::post('/{id}/resolve', [SystemAlertController::class, 'resolve'])->name('resolve');
Route::post('/read-all', [SystemAlertController::class, 'markAllAsRead'])->name('read-all');
});
MNG 주의사항 (CLAUDE.md 기반)
- MNG에서 마이그레이션 파일 생성 금지 (API에서만 관리)
- MNG에서 모델 작성은 허용 (API의 테이블 사용)
- HTMX 사용: 읽음/해결 버튼은 hx-post로 처리
- 사이드바 메뉴 추가 시: MngMenuSeeder 수정 + db:seed 실행 필요
2. 대상 범위
2.1 Phase 1: 백업 스크립트 (A안 — OS 레벨)
| # | 작업 항목 | 상태 | 비고 |
|---|---|---|---|
| 1.1 | backup.conf 설정 파일 생성 | ✅ | DB 접속정보, 경로, 보관기간 |
| 1.2 | sam-db-backup.sh 스크립트 생성 | ✅ | mysqldump + gzip + 보관관리 |
| 1.3 | 개발서버에서 스크립트 테스트 | ⏳ | 수동 실행 후 백업 파일 확인 (서버 접속 필요) |
2.2 Phase 2: Laravel 모니터링 (B안 — 앱 레벨)
| # | 작업 항목 | 상태 | 비고 |
|---|---|---|---|
| 2.1 | StatMonitorService에 recordBackupFailure() 추가 | ✅ | 기존 서비스 확장 |
| 2.2 | BackupCheckCommand 생성 | ✅ | db:backup-check 커맨드 |
| 2.3 | routes/console.php에 스케줄 등록 | ✅ | 매일 05:00 실행 |
2.3 Phase 3: 서버 배포 & 테스트
| # | 작업 항목 | 상태 | 비고 |
|---|---|---|---|
| 3.1 | 개발서버 crontab 등록 | ⏳ | 백업 스크립트 + schedule:run 확인 (서버 접속 필요) |
| 3.2 | 통합 테스트 (백업→모니터링) | ⏳ | 전체 플로우 검증 (서버 접속 필요) |
2.4 Phase 4: Slack 알림
| # | 작업 항목 | 상태 | 비고 |
|---|---|---|---|
| 4.1 | SlackNotificationService 생성 | ✅ | 웹훅 기반 알림 발송 서비스 |
| 4.2 | BackupCheckCommand에 Slack 알림 연동 | ✅ | 백업 실패 시 Slack 즉시 통보 |
| 4.3 | StatMonitorService에 Slack 알림 연동 | ✅ | 집계 실패/정합성 불일치 시 통보 (critical만) |
| 4.4 | 개발서버 테스트 | ⏳ | 실제 Slack 채널에 테스트 메시지 전송 (Phase 3과 함께) |
2.5 Phase 5: MNG 관리자 패널 — 시스템 알림 페이지
| # | 작업 항목 | 상태 | 비고 |
|---|---|---|---|
| 5.1 | MNG에 sam_stat DB 연결 추가 | ✅ | config/database.php + .env |
| 5.2 | StatAlert 모델 생성 (MNG용) | ✅ | sam_stat 연결, 읽기 전용 |
| 5.3 | SystemAlertController 생성 | ✅ | 목록 조회, 읽음 처리, 해결 처리 |
| 5.4 | 시스템 알림 Blade 페이지 생성 | ✅ | 필터링, 페이지네이션, 상태관리 + 라우트 등록 |
3. 작업 절차
3.1 아키텍처 개요
[OS 레벨 — crontab] [앱 레벨 — Laravel API]
04:30 sam-db-backup.sh 05:00 db:backup-check
├── mysqldump sam → gzip ├── 오늘 백업 파일 존재?
├── mysqldump sam_stat → gzip ├── 파일 크기 최소값 충족?
├── 오래된 백업 삭제 (보관정책) ├── 마지막 백업 25시간 이내?
└── 상태 파일 기록 ├── 실패 시 stat_alerts 기록
(.backup_status) │ (domain=backup, severity=critical)
└── 실패 시 Slack 웹훅 전송
↓
SlackNotificationService
├── 백업 실패 알림
├── 집계 실패 알림
└── 정합성 불일치 알림
[MNG 관리자 패널]
mng.sam.kr/system/alerts
├── stat_alerts 목록 조회 (sam_stat DB)
├── 필터: 도메인, 심각도, 읽음/미읽음
├── 읽음 처리
└── 해결 처리
3.2 스케줄 시간표 (최종)
02:00 stat:aggregate-daily (Laravel)
03:00 stat:aggregate-monthly (Laravel, 월 1일만)
03:00 api-log:prune (Laravel)
03:10 audit:prune (Laravel)
03:20 sanctum:prune-expired (Laravel)
03:30 storage:cleanup-temp (Laravel)
03:40 storage:cleanup-trash (Laravel)
03:50 storage:cleanup-links (Laravel)
04:00 storage:record-usage (Laravel)
04:30 sam-db-backup.sh (crontab — OS 레벨)
05:00 db:backup-check (Laravel)
09:00 stat:check-kpi-alerts (Laravel)
3.3 디렉토리 구조
/data/backup/mysql/
├── daily/
│ ├── 2026-01-30/
│ │ ├── sam_20260130_0430.sql.gz
│ │ └── sam_stat_20260130_0430.sql.gz
│ ├── 2026-01-29/
│ └── ... (7일 보관)
├── weekly/
│ ├── sam_20260126_week.sql.gz
│ └── ... (4주 보관)
└── logs/
└── backup.log
3.4 프로젝트 내 파일 구조
api/
├── scripts/
│ └── backup/
│ ├── sam-db-backup.sh # 백업 스크립트
│ └── backup.conf.example # 설정 파일 예시 (Git 추적)
├── app/
│ ├── Console/Commands/
│ │ └── BackupCheckCommand.php # 모니터링 커맨드
│ └── Services/
│ ├── Stats/
│ │ └── StatMonitorService.php # recordBackupFailure() 추가
│ └── SlackNotificationService.php # Slack 웹훅 알림 서비스
└── routes/
└── console.php # 스케줄 등록 추가
mng/
├── app/
│ ├── Http/Controllers/
│ │ └── System/
│ │ └── SystemAlertController.php # 시스템 알림 컨트롤러
│ └── Models/
│ └── Stats/
│ └── StatAlert.php # 알림 모델 (sam_stat 연결)
├── config/
│ └── database.php # sam_stat 연결 추가
├── resources/views/
│ └── system/
│ └── alerts/
│ └── index.blade.php # 시스템 알림 목록 페이지
└── routes/
└── web.php # /system/alerts 라우트 추가
4. 상세 작업 내용
4.1 Phase 1: 백업 스크립트
1.1 backup.conf.example
설정 파일 (서버에 backup.conf로 복사 후 수정):
# DB 접속 정보
DB_HOST=127.0.0.1
DB_PORT=3306
DB_USER=codebridge
DB_PASS="code**bridge"
# 백업 대상 DB (공백 구분)
DATABASES="sam sam_stat"
# 백업 저장 경로
BACKUP_BASE_DIR=/data/backup/mysql
# 보관 정책
DAILY_RETENTION_DAYS=7
WEEKLY_RETENTION_DAYS=28
# 로그
LOG_FILE=/data/backup/mysql/logs/backup.log
# 상태 파일 (Laravel 모니터링용)
STATUS_FILE=/data/backup/mysql/.backup_status
1.2 sam-db-backup.sh 주요 로직
1. backup.conf 로드
2. 날짜 디렉토리 생성 (daily/YYYY-MM-DD/)
3. 각 DB별 mysqldump 실행
- --single-transaction (InnoDB 무중단)
- --routines --triggers (프로시저/트리거 포함)
- | gzip 압축
4. 일요일이면 weekly/ 디렉토리에도 복사
5. 오래된 백업 삭제
- daily: DAILY_RETENTION_DAYS일 초과 삭제
- weekly: WEEKLY_RETENTION_DAYS일 초과 삭제
6. 상태 파일 기록 (성공/실패, 파일 크기, 시간)
7. 로그 기록
1.3 상태 파일 형식 (.backup_status)
{
"last_run": "2026-01-30T04:30:00+09:00",
"status": "success",
"databases": {
"sam": {"file": "sam_20260130_0430.sql.gz", "size_bytes": 52428800},
"sam_stat": {"file": "sam_stat_20260130_0430.sql.gz", "size_bytes": 1048576}
},
"errors": []
}
4.2 Phase 2: Laravel 모니터링
2.1 StatMonitorService 확장
// 추가 메서드
public function recordBackupFailure(int $tenantId, string $title, string $message): void
// domain: 'backup', alert_type: 'backup_failure', severity: 'critical'
참고: 백업은 테넌트 무관(시스템 레벨)이므로 tenantId=0 사용
2.2 BackupCheckCommand
시그니처: db:backup-check
옵션: --path= (백업 경로 오버라이드)
체크 항목:
1. .backup_status 파일 존재 여부
2. last_run이 25시간 이내인지
3. status가 "success"인지
4. 각 DB 백업 파일 크기가 최소값 이상인지
- sam: 1MB 이상
- sam_stat: 100KB 이상
결과:
- 모든 체크 통과: "✅ 백업 상태 정상" 출력
- 하나라도 실패: stat_alerts에 기록 + "❌ 백업 이상 감지" 출력
2.3 환경 설정
# .env 추가
BACKUP_PATH=/data/backup/mysql
BACKUP_STATUS_FILE=/data/backup/mysql/.backup_status
BACKUP_MIN_SIZE_SAM=1048576
BACKUP_MIN_SIZE_STAT=102400
4.3 Phase 4: Slack 알림
4.1 SlackNotificationService
위치: api/app/Services/SlackNotificationService.php
기능:
- Slack Incoming Webhook을 통한 메시지 전송
- 기존 LOG_SLACK_WEBHOOK_URL 환경변수 활용
- 별도 SLACK_ALERT_WEBHOOK_URL 추가 (알림 전용 채널 분리 가능)
메서드:
- sendAlert(string $title, string $message, string $severity): void
└── severity에 따른 색상: critical=red, warning=orange, info=blue
- sendBackupAlert(string $title, string $message): void
- sendStatAlert(string $title, string $message, string $domain): void
메시지 포맷 (Slack Block Kit):
┌──────────────────────────────────────┐
│ 🚨 [SAM 백업 실패] │
│ │
│ 서버: 개발서버 (114.203.209.83) │
│ 시간: 2026-01-30 05:00:00 │
│ 상세: sam DB 백업 파일 미발견 │
│ │
│ 환경: development │
└──────────────────────────────────────┘
4.2 BackupCheckCommand Slack 연동
기존 흐름:
체크 실패 → stat_alerts 기록 → 로그 출력
변경 후:
체크 실패 → stat_alerts 기록 → Slack 알림 전송 → 로그 출력
4.3 StatMonitorService Slack 연동
기존 흐름:
집계 실패/정합성 불일치 → stat_alerts 기록
변경 후:
집계 실패/정합성 불일치 → stat_alerts 기록 → Slack 알림 전송
(severity가 critical인 경우에만 Slack 전송)
4.4 환경 설정
# .env 추가
SLACK_ALERT_WEBHOOK_URL= # 알림 전용 채널 (미설정 시 LOG_SLACK_WEBHOOK_URL 사용)
SLACK_ALERT_ENABLED=true # Slack 알림 활성화 여부
SLACK_ALERT_SERVER_NAME=개발서버 # 메시지에 표시할 서버명
4.4 Phase 5: MNG 관리자 패널
5.1 MNG에 sam_stat DB 연결 추가
// mng/config/database.php - connections 배열에 추가
'sam_stat' => [
'driver' => 'mysql',
'host' => env('STAT_DB_HOST', env('DB_HOST', '127.0.0.1')),
'port' => env('STAT_DB_PORT', env('DB_PORT', '3306')),
'database' => env('STAT_DB_DATABASE', 'sam_stat'),
'username' => env('STAT_DB_USERNAME', env('DB_USERNAME')),
'password' => env('STAT_DB_PASSWORD', env('DB_PASSWORD')),
// ... 기본 설정
],
# mng/.env 추가
STAT_DB_HOST=127.0.0.1
STAT_DB_PORT=3306
STAT_DB_DATABASE=sam_stat
STAT_DB_USERNAME=samuser
STAT_DB_PASSWORD=sampass
5.2 StatAlert 모델 (MNG용)
// mng/app/Models/Stats/StatAlert.php
// - connection: sam_stat
// - 읽기 전용 (조회 + 상태 변경만)
// - fillable: is_read, is_resolved, resolved_at
5.3 SystemAlertController
라우트: /system/alerts
미들웨어: auth, hq.member, password.changed
기능:
GET /system/alerts — 알림 목록 (필터/페이지네이션)
POST /system/alerts/{id}/read — 읽음 처리
POST /system/alerts/{id}/resolve — 해결 처리
POST /system/alerts/read-all — 전체 읽음 처리
필터 파라미터:
- domain: backup, sales, finance, production, system 등
- severity: info, warning, critical
- status: all, unread, unresolved
- date_from, date_to
5.4 알림 목록 Blade 페이지
페이지: mng/resources/views/system/alerts/index.blade.php
레이아웃: 기존 MNG 레이아웃 (사이드바 + 헤더)
UI 구성:
┌─────────────────────────────────────────────────────────┐
│ 시스템 알림 [전체 읽음]│
├─────────────────────────────────────────────────────────┤
│ 필터: [도메인 ▼] [심각도 ▼] [상태 ▼] [날짜 범위] │
├─────────────────────────────────────────────────────────┤
│ 🔴 [backup] 백업 실패 — sam DB 백업 파일 미발견 │
│ 2026-01-30 05:00 │ 미읽음 │ 미해결 │ [읽음] [해결] │
├─────────────────────────────────────────────────────────┤
│ 🟡 [sales] 2026-01-29 데이터 누락 │
│ 2026-01-30 02:05 │ 읽음 │ 미해결 │ [해결] │
├─────────────────────────────────────────────────────────┤
│ 🔴 [finance] deposit_amount 정합성 불일치 │
│ 2026-01-29 02:10 │ 읽음 │ 해결됨 │ │
├─────────────────────────────────────────────────────────┤
│ < 1 2 3 ... > │
└─────────────────────────────────────────────────────────┘
심각도 색상: critical=빨강, warning=노랑, info=파랑
HTMX 활용: 읽음/해결 버튼 클릭 시 페이지 리로드 없이 상태 변경
5. 컨펌 대기 목록
| # | 항목 | 변경 내용 | 영향 범위 | 상태 |
|---|---|---|---|---|
| 1 | StatMonitorService 수정 | recordBackupFailure() 메서드 추가 + Slack 연동 | api/Services | ✅ 완료 |
| 2 | routes/console.php 수정 | db:backup-check 스케줄 등록 (05:00) | api/스케줄러 | ✅ 완료 |
| 3 | crontab 등록 | 개발서버에 sam-db-backup.sh 등록 (04:30) | 서버 | ⏳ 서버 배포 시 |
| 4 | SlackNotificationService 생성 | Slack 웹훅 알림 서비스 신규 | api/Services | ✅ 완료 |
| 5 | StatMonitorService Slack 연동 | critical 알림 시 Slack 전송 | api/Services | ✅ 완료 |
| 6 | MNG database.php 수정 | sam_stat 연결 추가 | mng/config | ✅ 완료 |
| 7 | MNG web.php 수정 | /system/alerts 라우트 추가 | mng/routes | ✅ 완료 |
6. 변경 이력
| 날짜 | 항목 | 변경 내용 | 파일 | 승인 |
|---|---|---|---|---|
| 2026-01-30 | - | 문서 초안 작성 | - | - |
| 2026-01-31 | Phase 1.1 | backup.conf.example 생성 | api/scripts/backup/backup.conf.example | ✅ |
| 2026-01-31 | Phase 1.2 | sam-db-backup.sh 스크립트 생성 | api/scripts/backup/sam-db-backup.sh | ✅ |
| 2026-01-31 | Phase 2.1 | recordBackupFailure() 추가 | api/app/Services/Stats/StatMonitorService.php | ✅ |
| 2026-01-31 | Phase 2.2 | BackupCheckCommand 생성 | api/app/Console/Commands/BackupCheckCommand.php | ✅ |
| 2026-01-31 | Phase 2.3 | db:backup-check 스케줄 등록 | api/routes/console.php | ✅ |
| 2026-01-31 | Phase 4.1 | SlackNotificationService 생성 | api/app/Services/SlackNotificationService.php | ✅ |
| 2026-01-31 | Phase 4.2 | BackupCheckCommand Slack 연동 | api/app/Console/Commands/BackupCheckCommand.php | ✅ |
| 2026-01-31 | Phase 4.3 | StatMonitorService Slack 연동 | api/app/Services/Stats/StatMonitorService.php | ✅ |
| 2026-01-31 | Phase 4.3 | .env.example 환경변수 추가 | api/.env.example | ✅ |
| 2026-01-31 | Phase 5.1 | sam_stat DB 연결 추가 | mng/config/database.php | ✅ |
| 2026-01-31 | Phase 5.2 | StatAlert 모델 생성 (MNG) | mng/app/Models/Stats/StatAlert.php | ✅ |
| 2026-01-31 | Phase 5.3 | SystemAlertController 생성 | mng/app/Http/Controllers/System/SystemAlertController.php | ✅ |
| 2026-01-31 | Phase 5.4 | 시스템 알림 Blade + 라우트 | mng/resources/views/system/alerts/index.blade.php, mng/routes/web.php | ✅ |
7. 참고 문서
- 빠른 시작:
docs/quickstart/quick-start.md - 품질 체크리스트:
docs/standards/quality-checklist.md - 시스템 아키텍처:
docs/architecture/system-overview.md - DB 스키마:
docs/specs/database-schema.md - 기존 스케줄러:
api/routes/console.php - StatMonitorService:
api/app/Services/Stats/StatMonitorService.php - StatAlert 모델:
api/app/Models/Stats/StatAlert.php - sam_stat 설계:
docs/plans/sam-stat-database-design-plan.md - MNG 라우트:
mng/routes/web.php - MNG 레이아웃:
mng/resources/views/layouts/ - Slack 웹훅:
api/.env→LOG_SLACK_WEBHOOK_URL
8. 세션 및 메모리 관리 정책 (Serena Optimized)
8.1 세션 시작 시 (Load Strategy)
read_memory("db-backup-state")
read_memory("db-backup-snapshot")
read_memory("db-backup-active-symbols")
8.2 작업 중 관리 (Context Defense)
| 컨텍스트 잔량 | Action | 내용 |
|---|---|---|
| 30% 이하 | Snapshot | write_memory("db-backup-snapshot", "코드변경+논의요약") |
| 20% 이하 | Context Purge | write_memory("db-backup-active-symbols", "주요 수정 파일/함수") |
| 10% 이하 | Stop & Save | 최종 상태 저장 후 세션 교체 권고 |
8.3 Serena 메모리 구조
db-backup-state: { phase, progress, next_step, last_decision }db-backup-snapshot: 현재까지의 논의 및 코드 변경점 요약db-backup-active-symbols: 현재 수정 중인 파일/심볼 리스트
9. 검증 결과
작업 완료 후 이 섹션에 검증 결과 추가
9.1 테스트 케이스
| 입력값 | 예상 결과 | 실제 결과 | 상태 |
|---|---|---|---|
| sam-db-backup.sh 수동 실행 | daily/ 디렉토리에 .sql.gz 2개 생성 | ⏳ | |
| .backup_status 확인 | JSON 형식, status=success | ⏳ | |
| db:backup-check 실행 (백업 정상) | "백업 상태 정상" 출력 | ⏳ | |
| db:backup-check 실행 (백업 없음) | stat_alerts 기록 + Slack 알림 전송 | ⏳ | |
| 8일 후 daily/ 확인 | 7일 초과 백업 자동 삭제 | ⏳ | |
| Slack 테스트 메시지 전송 | 지정 채널에 메시지 수신 확인 | ⏳ | |
| MNG /system/alerts 접속 | 알림 목록 표시, 필터 동작 | ⏳ | |
| MNG 읽음/해결 처리 | 상태 변경 후 DB 반영 확인 | ⏳ |
9.2 성공 기준 달성 현황
| 기준 | 달성 | 비고 |
|---|---|---|
| sam + sam_stat 백업 파일 생성 | ⏳ | |
| gzip 압축 적용 | ⏳ | |
| 보관 정책 (일간 7일, 주간 4주) 동작 | ⏳ | |
| Laravel 모니터링으로 백업 상태 확인 | ⏳ | |
| 실패 시 stat_alerts 기록 | ⏳ | |
| 실패 시 Slack 알림 전송 | ⏳ | |
| MNG에서 알림 목록 조회 가능 | ⏳ | |
| MNG에서 읽음/해결 처리 가능 | ⏳ | |
| 운영서버 이식성 (backup.conf + .env 수정만으로 동작) | ⏳ |
10. 자기완결성 점검 결과
10.1 체크리스트 검증
| # | 검증 항목 | 상태 | 비고 |
|---|---|---|---|
| 1 | 작업 목적이 명확한가? | ✅ | 1.1 배경에 명시 |
| 2 | 성공 기준이 정의되어 있는가? | ✅ | 9.2 성공 기준 9개 |
| 3 | 작업 범위가 구체적인가? | ✅ | 5 Phase, 14 항목 |
| 4 | 의존성이 명시되어 있는가? | ✅ | 기존 stat_alerts 인프라 활용 |
| 5 | 참고 파일 경로가 정확한가? | ✅ | 섹션 7에 명시 |
| 6 | 단계별 절차가 실행 가능한가? | ✅ | 섹션 4 상세 내용 |
| 7 | 검증 방법이 명시되어 있는가? | ✅ | 섹션 9 테스트 케이스 |
| 8 | 모호한 표현이 없는가? | ✅ | 크기/시간/경로 모두 구체적 |
10.2 새 세션 시뮬레이션 테스트
| 질문 | 답변 가능 | 참조 섹션 |
|---|---|---|
| Q1. 이 작업의 목적은 무엇인가? | ✅ | 1.1 배경 |
| Q2. 어디서부터 시작해야 하는가? | ✅ | 2.1 Phase 1 |
| Q3. 어떤 파일을 수정해야 하는가? | ✅ | 3.4 파일 구조 |
| Q4. 작업 완료 확인 방법은? | ✅ | 9. 검증 결과 |
| Q5. 막혔을 때 참고 문서는? | ✅ | 7. 참고 문서 |
결과: 5/5 통과 → ✅ 자기완결성 확보
이 문서는 /sc:plan 스킬로 생성되었습니다.