- 개발팀 전용 폴더 dev/ 생성 (standards, guides, quickstart, changes, deploys, data, history, dev_plans 이동) - 프론트엔드 전용 폴더 frontend/ 생성 (api/ → frontend/api-specs/) - 기획팀 폴더 requests/ 생성 - plans/ → dev/dev_plans/ 이름 변경 - README.md 신규 (사람용 안내), INDEX.md 재작성 (Claude Code용) - resources.md 신규 (노션 링크용, assets/brochure 이관 예정) - CURRENT_WORKS.md 삭제, TODO.md → dev/ 이동 - 전체 참조 경로 업데이트 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
745 lines
29 KiB
Markdown
745 lines
29 KiB
Markdown
# 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 테이블 스키마
|
|
|
|
```sql
|
|
-- 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)
|
|
|
|
```php
|
|
// 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 현재 메서드
|
|
|
|
```php
|
|
// 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 스케줄 등록 패턴
|
|
|
|
```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 컨트롤러 패턴
|
|
|
|
```php
|
|
// 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 라우트 등록 패턴
|
|
|
|
```php
|
|
// 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`로 복사 후 수정):
|
|
|
|
```bash
|
|
# 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)
|
|
|
|
```json
|
|
{
|
|
"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 확장
|
|
|
|
```php
|
|
// 추가 메서드
|
|
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
|
|
# .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
|
|
# .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 연결 추가
|
|
|
|
```php
|
|
// 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')),
|
|
// ... 기본 설정
|
|
],
|
|
```
|
|
|
|
```env
|
|
# 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용)
|
|
|
|
```php
|
|
// 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/dev_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)
|
|
```javascript
|
|
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 스킬로 생성되었습니다.* |