From f1fdc9525638536b2b25dcf8c30aed5df5a4b112 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B6=8C=ED=98=81=EC=84=B1?= Date: Sat, 31 Jan 2026 08:33:42 +0900 Subject: [PATCH] =?UTF-8?q?docs:=20DB=20=EB=B0=B1=EC=97=85=20=EC=8B=9C?= =?UTF-8?q?=EC=8A=A4=ED=85=9C=20=EA=B3=84=ED=9A=8D=20=EB=AC=B8=EC=84=9C=20?= =?UTF-8?q?=EC=A7=84=ED=96=89=20=EC=83=81=ED=83=9C=20=EC=97=85=EB=8D=B0?= =?UTF-8?q?=EC=9D=B4=ED=8A=B8=20(79%)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Phase 1,2,4,5 로컬 코드 작업 완료 반영 - 변경 이력 14건 추가 - 잔여 작업: 서버 배포 3건 (1.3, 3.1, 3.2) Co-Authored-By: Claude Opus 4.5 --- plans/db-backup-system-plan.md | 745 +++++++++++++++++++++++++++++++++ 1 file changed, 745 insertions(+) create mode 100644 plans/db-backup-system-plan.md diff --git a/plans/db-backup-system-plan.md b/plans/db-backup-system-plan.md new file mode 100644 index 0000000..3598abc --- /dev/null +++ b/plans/db-backup-system-plan.md @@ -0,0 +1,745 @@ +# 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/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 스킬로 생성되었습니다.* \ No newline at end of file