개요 — 무엇을 하나
백업 스케줄 보드(/backup/board)는 등록된 백업 계획(infr_backup_job)의 일정 · 저장 위치 · 다음 실행 시각 · 최근 성공 이력을 한 화면에서 조망하는 읽기 전용 시각화입니다. "무엇을, 언제, 어디에" 백업하는지와 "밀리지 않았는지"를 즉시 확인하는 것이 목적입니다.
- 데이터 조립은
App\Services\Backup\BackupBoardService가 담당하고, 결과는 15초 캐시됩니다(infr:bk:board). - 백업 계획을 만들거나 수정하는 관리 화면은 아닙니다 — 생성/편집은 백업 스크립트와 스크립트 빌더에서 하고, 이 보드는 결과를 표시만 합니다.
- 예외로 보관소(볼트) CRUD 는 이 보드의 컨트롤러(
BoardController)가 소유합니다(스크립트 페이지의 보관소 관리 모달이 이 엔드포인트를 호출). - "다음 실행", "지연", "마지막 성공 N일 전" 같은 넛지는 별도 저장 없이
last_run_at+schedule(N U 문법)로 파생 계산합니다.
언제 �나
- 아침 운영 점검 — 어젯밤 백업이 다 성공했는지, 오늘 곧 돌 계획이 무엇인지 확인.
- 밀린 백업 색출 — "곧 실행"·"최근 실패" KPI 와 카드의 넛지(빨강/노랑)로 손봐야 할 계획을 바로 찾음.
- 3-2-1 배치 점검 — 프로젝트 → 소스 호스트 → 보관소 흐름과 오프사이트 사본 유무를 눈으로 확인.
- 특정 대상의 복구지점 이력 훑기 — 카드의 최근 성공 칩/
+N→ 전체 실행 이력 모달. - 보관소(볼트) 관리 — 저장 대상 추가·용량·오프사이트 플래그 수정.
화면 구성
상단은 히어로(타임존 배지 + 새로고침)와 KPI 스트립, 본문은 2-페인 보드입니다.
KPI 스트립 (클릭형 필터 포함)
| 타일 | 키 | 정의 |
|---|---|---|
| 백업 계획 | kpi.jobs |
전체 계획(job 카드) 수. 클릭 = 활성 필터 끄기(전체 보기) |
| 활성 | kpi.active |
status = active 인 계획 수. 클릭 = 활성만 보기 |
| 곧 실행 | kpi.due_soon |
활성 계획 중 다음 실행이 지금부터 60분 이내인 수 |
| 최근 실패 | kpi.failed |
last_status = failed 인 계획 수(0 이 아니면 빨강) |
| 보호 용량 | kpi.protected_bytes |
계획별 마지막 성공 실행의 bytes 합 |
| 보관소 | kpi.vaults |
등록된 보관소(볼트) 수 |
KPI 페이로드에는 프로젝트 커버리지(
coverage_pct= 백업이 하나라도 걸린 프로젝트 ÷ 전체 프로젝트 %)도 포함되지만, 헤더 스트립에는 위 6개 타일만 노출됩니다. 커버리지는 배치 지도 서사(어느 프로젝트가 보호되는가)에서 쓰입니다.
좌측 — 세로 월간(일 = 카드)
날짜별 카드 리스트(월 이동 ‹ › · [오늘]). 각 날짜 카드는 그 날 실행된 run 을 상태 도트(최대 6개) 와 건수 배지로 요약합니다. 날짜를 클릭하면:
- 오브젝트 모드에서는 그 날에 실행된 백업만 보는 날짜 필터 칩이 켜집니다(칩 클릭으로 해제).
- 달력 모드에서는 해당 날짜로 드릴다운합니다.
우측 — 오브젝트 | 달력 토글
오브젝트 모드(기본): 대상(계획)별 카드 그리드. 카드 구성:
- 헤더 = 소스 유형 아이콘 · 계획명 · 프로젝트 배지 · 마지막 상태 배지.
- 흐름 =
소스 라벨 → 보관소 라벨(보관소 미지정이면 "보관소 미지정"). - 최근 성공 칩 = 최신 성공 10건(월/일) +
+N(전체 성공 수 초과분) → 클릭 시 실행 이력 모달. - 다음 실행 = 파생된 다음 시각 + 주기 문자열, 지연 시 강조.
- 넛지 = "한 번도 성공 못 함" 또는 "마지막 성공 N일 전 — 백업이 밀렸습니다".
활성만 스위치로 활성 계획만 필터할 수 있고, KPI 의 계획/활성 타일과 동기화됩니다.
달력 모드: menuro 스타일 월/주/일 격자에 run 을 플롯. 월간은 셀당 이벤트 칩 3개 + +N, 주간은 요일 컬럼, 일간은 시각 그룹 아젠다. 칩 클릭 → 해당 계획 이력 모달.
실행 이력 모달
카드/칩에서 열립니다. 대상별 전체 실행을 최신순 페이지네이션(20건/페이지) 으로 표시: 시각 · 상태 · 유형 · 용량 · 소요 · 아티팩트(파일명, 전체 경로는 tooltip) · 서버 IP.
사용법
상태를 빠르게 읽기
- KPI 에서 최근 실패 · 곧 실행을 먼저 봅니다.
활성만을 켜 운영 중인 계획만 남깁니다.- 넛지가 붙은 카드(빨강=crit, 노랑=warn)를 손봅니다 — 스크립트 배치나 자격 파일, 러너 등록을 점검.
- 특정 대상이 의심되면 최근 성공 칩 → 이력 모달로 실패 메시지·소요·아티팩트를 확인.
보관소(볼트) 추가·수정
보관소는 여러 계획이 공유하는 이름 붙은 저장 대상입니다. 저장 폼 필드:
| 필드 | 설명 |
|---|---|
| 이름 | 표시명(비우면 "보관소") |
| 유형 | local · rsync · ssh · s3 · nfs · other |
| 호스트(원격) | 원격 대상 호스트(로컬이면 비움) |
| 경로/URI | 저장 루트 경로 또는 URI |
| 거주 인스턴스 | infr_instance 연계(instance_id) |
| 스토리지 자산 | infr_storage 연계(storage_id) |
| 용량 | capacity_bytes(미입력 가능) |
| 자격 참조 | cred_ref — env:PREFIX/vault 참조만, 비밀 인라인 금지 |
| 오프사이트 | 3-2-1 규칙의 "원격지 사본" 여부 |
| 상태 | active · full · offline · retired |
| 메모 | 자유 메모 |
3-2-1 규칙 — 데이터 사본을 3벌 만들어 서로 다른 매체 2종에 두고, 그중 1벌은 오프사이트(다른 건물·리전·클라우드)에 둡니다. 이 보관소가 원격지에 있으면
오프사이트를 체크하세요.
사용 중인 보관소는 삭제되지 않습니다. 어떤 계획이라도 이 보관소를
target_id로 참조하면 삭제 요청은409+ "이 보관소를 N개 작업이 사용 중" 으로 거부됩니다 — 먼저 계획의 보관소를 재지정하세요.
저장 방식(엔드포인트)
| 메서드 · 경로 | 이름 | 용도 |
|---|---|---|
GET /backup/board |
backup.board |
페이지(초기 부트스트랩) |
GET /backup/board/live |
backup.board.live |
보드 JSON 재조회 |
GET /backup/board/calendar?from=&to= |
backup.board.calendar |
달력 run 피드(Y-m-d 범위, 92일 초과 시 절단) |
GET /backup/board/history?job_id=&page= |
backup.board.history |
대상별 실행 이력(20건/페이지) |
POST /backup/board/target-save |
backup.board.target_save |
보관소 생성/수정(감사) |
POST /backup/board/target-delete |
backup.board.target_delete |
보관소 삭제(사용 중이면 409) |
데이터 소스
전부 신규 infr_ 테이블이며 좁은 창으로만 조회합니다(레거시 테이블 미변경).
| 테이블 | 역할 | 조회 범위 |
|---|---|---|
infr_backup_job |
백업 계획(소스·보관소·주기·상태) | 전체(id DESC) |
infr_backup_run |
실행 이력 = 복구지점(시계열) | 스파크/카드용 최근 30일 · 전체기간 성공 카운트는 단일 grouped count · 달력은 [from,to](≤92일) · 이력 모달은 대상별 페이지네이션 |
infr_backup_target |
보관소(볼트) 정의 | 전체(seq, name) |
infr_project |
프로젝트(배치 지도·커버리지) | id/name/url |
infr_instance |
소스/거주 인스턴스 라벨 | id/name/alias/ssh_host/ip |
파생 계산 규칙
- 다음 실행:
next_run_at우선, 없으면ScheduleGrammar::nextRun(schedule, last_run_at ?: start_at).schedule은 "N U" 문법 —U ∈ M(분)·H(시)·D(일)·W(주), 예6 H(6시간마다),1 D(하루마다). - 지연(overdue): 다음 실행이 현재보다 과거.
- 곧 실행(due_soon): 활성 + 다음 실행이
[지금, 지금+60분]. - 넛지(stale/crit): 활성 계획만. 마지막 성공 이후 경과일
days ≥ max(3, 인터벌일 × 2)면 warn,days ≥ 인터벌일 × 4면 crit. 성공 이력이 아예 없으면never(warn). - 보호 용량: 계획별 마지막 성공 run 의
bytes합. - 성공률(ok_rate): 창 내
done ÷ 전체 × 100.
권한
- 라우트 그룹은
infr.level:2— 레벨 2 이상(staff=5, admin=10) 만 백업 영역 접근. 데모(demo=1)는 차단됩니다. - 보드 조회(index/live/calendar/history)는 위 그룹 통과만으로 열람 가능.
- 보관소 쓰기(target-save/target-delete)는 세션
infr_user_level ≥ 2를 다시 확인하고, 실패 시403(권한 없음)을 반환합니다. - 보관소 저장·삭제는
infr_audit_log에 기록됩니다(backup.target.save/backup.target.delete). 자세한 레벨 체계는 RBAC 레벨을 참고하세요.
문제해결 · FAQ
Q. 계획이 하나도 안 보입니다.
아직 등록된 백업 계획이 없는 상태입니다. 스크립트 빌더에서 프로젝트를 선택해 계획을 만들고, 백업 스크립트 페이지에서 스크립트를 완성한 뒤 on 으로 켜세요.
Q. 카드에 "한 번도 성공하지 못했습니다" 넛지가 떠요.
러너가 실행한 적이 없거나 성공 run 이 없습니다. 대상 호스트에 스크립트가 배치되었는지, 백업 러너(infr_backup_runner.cjs)가 pm2 에 등록되었는지, 계획이 is_run = on 인지 확인하세요.
Q. "마지막 성공 N일 전 — 밀렸습니다" 는 어떻게 판단하나요? 스케줄 인터벌의 2배(최소 3일)를 넘으면 warn, 4배를 넘으면 crit 입니다. 예: 하루 주기라면 2일 넘게 성공이 없을 때 경보.
Q. 보관소를 지우려는데 409 가 납니다. 그 보관소를 사용 중인 계획이 있습니다. 먼저 해당 계획들의 보관소를 다른 곳으로 재지정한 뒤 삭제하세요.
Q. 값이 최신이 아닌 것 같습니다. 보드는 15초 캐시됩니다. 새로고침 버튼을 누르거나 잠시 후 다시 확인하세요. 보관소 저장/삭제 후에는 캐시가 자동 무효화됩니다.
Q. 달력에서 아주 넓은 범위가 안 나와요.
슬로우 쿼리 방어로 달력 from~to 범위는 92일로 절단됩니다. 더 과거는 대상별 이력 모달로 보세요.
관련 항목
- 백업 스크립트 — 등록된 스크립트 그리드·
is_run토글(계획 관리 진입점) - 스크립트 빌더 — 프로젝트에서 계획 초안 프리필 → 스크립트/crontab 생성
- 복구 & 검증 — 복구지점 인출·복원 명령·무결성 검증
- 백업 보관소 — 볼트 상세(용량·오프사이트·3-2-1)
- 백업 리포터 — 러너 → 리포트 콜백으로
infr_backup_run적재 - 프로젝트 — 배치 지도·커버리지의 프로젝트 소스
