Skip to Content

Frame DB 복구

AI 요청 프롬프트

https://docs.axelabs.ai/ops/runbook/db-recovery 따라 frame DB 복구 진행해줘. 진행: 1. 현재 사고 진단 — 사용자 보고 증상으로 페이지 "시나리오 분류" 표의 5 시나리오 중 분기 식별 (migration / 사용자 실수 / macmini 손실 / silent corruption / postgres crash) 2. 즉시 대응 — frame container stop (사용자 추가 쓰기 차단) + restic 최신 snapshot 확인 3. 시나리오별 복구 절차 실행, 매 step 결과 받고 다음. destructive (drop database / restore from backup) 직전 사용자 확인 4. 함정 발생 시 페이지 본문 따라 우회 (Phase 5 stub `axe restore` 부재 → restic 직접 / silent corruption 의 부분 복원 범위 / migration rollback) 5. 정합성 검사 통과 (`integrity-check`) + frame 재기동 + (선택) /ops/known-gaps 사고 원인 한 줄

본인 AI session = Claude Code / Cursor / ChatGPT 데스크탑 / Claude.app / 기타.

페이지 본문 = 사람이 직접 read 도 가능, AI 도 참고. AI 가 본 페이지 fetch 후 위 진행 순서대로 사용자와 step-by-step interactive 풀어나감.

frame 의 PostgreSQL 데이터가 손상되었을 때 복구 절차.

시나리오 분류

사건즉시 대응복구 경로
Migration 사고 (alembic 적용 후 정합성 깨짐)모든 frame container stoplocal backup (Tier A)
사용자 실수 (잘못된 분개 대량 등록)해당 entity 만 freezereverse_journal × 다수 OR 백업
macmini 전체 손실 (도난·화재)새 macmini 셋업ring (Tier B) 또는 cold SSD (Tier C)
Silent corruption (검증 실패)정합성 검사 결과 분석부분 복원
Postgres 자체 crashdocker restart frame-postgres거의 자동 복구

시나리오 1 — Migration 사고

새 migration 적용 후 정합성 검사 실패:

ssh axe-macmini "docker exec frame-mcp-blue python -m frame.cli integrity-check --entity axec" # → FAIL: balance mismatch in journal X

즉시

# 1. 모든 frame container stop (사용자 추가 쓰기 차단) ssh axe-macmini "cd /Users/axe/frame && docker compose stop frame-mcp-blue frame-mcp-green" # 2. Backup 최근 snapshot 확인 ssh axe-macmini " restic -r /Users/axe/.axe/backups/local snapshots \ --password-file <(security find-generic-password -w -s axe.backup.restic.local) " # 어제 03:00 KST snapshot 찾기

복구

# 3. 어제 backup 으로 frame-postgres 복원 # `axe restore` 는 Phase 5 stub 상태 → 현재는 restic 직접 호출: ssh axe-macmini " restic -r /Users/axe/.axe/backups/local \ --password-file <(security find-generic-password -w -s axe.backup.restic.local -a axe-cli) \ restore <snapshot_id> --target /tmp/restore --include 'frame-postgres/*' " # 그 후 docker exec frame-postgres pg_restore 또는 dump replay # 정식 `axe restore` 자동화는 Phase 5 (D) 작업 항목 # 4. frame container restart (이전 코드 버전으로!) ssh axe-macmini "cd /Users/axe/frame && git checkout <previous-good-commit>" ssh axe-macmini " cd /Users/axe/frame && set -a && source .env.local && set +a && docker compose build frame-mcp-blue && docker compose up -d --force-recreate frame-mcp-blue frame-mcp-green " # 5. 정합성 재확인 ssh axe-macmini "docker exec frame-mcp-blue python -m frame.cli integrity-check --entity axec" # → OK

손실 분석

복원 후 손실 = 백업 시점 (어제 03:00) ~ container stop 시점 사이의 모든 쓰기.

# 손실된 audit_log 추출 (다른 백업 또는 in-memory) ssh axe-macmini "docker exec frame-postgres psql -U frame -d frame -c \" SELECT * FROM axec.audit_log WHERE ts > '2026-05-20 03:00:00+09:00' ORDER BY ts; \""

사용자에게 통지 + 수동 재입력 또는 잘못 적용된 migration 의 의도된 효과 분석.

시나리오 2 — 사용자 실수

회계사가 실수로 잘못된 분개 50건 등록:

우선 — reverse_journal 시도

# Claude Code 에서 Frame:list_journals entity_id=axec, start_date=2026-05-20, status=posted # 잘못된 journal_id 목록 확인 후 for jid in [...]: Frame:reverse_journal entity_id=axec, journal_id=jid, memo="실수 역분"

reverse_journal 은 새 journal 생성 (append-only). audit_log 에 모두 기록.

대량 (50건+) — 백업 복원

50건 넘으면 reverse 절차도 부담. 백업 복원이 더 깔끔:

# 1. 사용자의 다른 활동 멈추기 (claude.ai connector 비활성 요청) # 2. 가장 가까운 valid backup 복원 — table-level restore 자동화 TBD # 현재는 dump 전체 복원 후 손상 table 만 selective merge # (정식 도구화 = Phase 5 D 항목)

table-level 복원이 가능한지 확인 필요 — restic 자체는 file-level 만 → pg_dump 의 selective restore 필요. 향후 도구화 검토.

시나리오 3 — macmini 전체 손실

가장 심각. 새 macmini 에 처음부터 셋업.

절차

# 1. 새 macmini 준비 # - macOS 클린 install # - Tailscale 가입 + 운영자 key 등록 # - Docker Desktop install # - axe CLI install: bash <(curl -sSL https://docs.axelabs.ai/install/axe-cli.sh) # 2. customers.yaml 의 entry 그대로 사용 # (운영자 머신에서 push) # 3. 가장 신선한 백업 복원 (restic 직접 호출) # ring peer (realchoice macmini) 측에서 pull: ssh axe-macmini " restic -r sftp:[email protected]:/Users/realchoice/peer-backups/axe \ --password-file <(security find-generic-password -w -s axe.backup.restic.local -a axe-cli) \ restore latest --target /tmp/restore " # 또는 cold SSD 마운트 후 ssh axe-macmini " restic -r /Volumes/axe-cold-1/restic-repo \ --password-file <(종이메모) \ restore latest --target /tmp/restore " # 4. frame onboard (axe CLI 의 `--skip-azure` 플래그 는 향후 추가 예정; # 현재는 onboard 가 Azure 측 변경 자체를 하지 않으므로 일반 onboard 그대로) axe onboard axe --apply # 5. Microsoft 측 — redirect_uri 변경 불필요 (axe.axelabs.ai 도메인 그대로) # 6. 검증 axe health axe ssh axe-macmini "docker exec frame-mcp-blue python -m frame.cli integrity-check --entity axec" ssh axe-macmini "docker exec frame-mcp-blue python -m frame.cli integrity-check --entity axev" # 7. 직원 통지 "frame 시스템 복구 완료. claude.ai 의 connector 는 그대로 작동합니다."

시나리오 4 — Silent Corruption

매일 자동 integrity-check 가 잡아냄. 발견 즉시:

  1. 어느 entity, 어느 검사가 실패했는지 확인
  2. 가장 가까운 valid snapshot 찾기 (전날 또는 그 이전)
  3. table-level 또는 entity-level 복원
  4. 사용자에게 통지 (해당 기간 데이터 재입력 필요할 수도)

Restore Drill (분기별)

매 분기 (Jan/Apr/Jul/Oct 15) 자동 drill 이 실행:

  1. 임시 staging 컨테이너 (frame-mcp-drill) 에 어제 backup 복원
  2. integrity-check 4개 모두 통과 여부
  3. 결과 → 운영자 Slack

drill 실패 = backup 자체 문제 (압축 손상, password 오류 등). 즉시 원인 분석.

함정

함정결과회피
손상 발견 후 frame 미정지 → 추가 쓰기 누적손실 확대즉시 docker compose stop
ring peer 의 backup 도 손상되었을 가능성양쪽 손상cold SSD 도 보유
복원 후 정합성 검사 안 함잠재 손상 미발견integrity-check 필수
pg_dump 의 schema-per-entity 옵션 누락복원 시 entity schema 사라짐restic 의 raw file 복원 (PGDATA volume)

⚠️ 현재 도구 상태

axe restore --customer ... --tier ... --target ... --table ... --apply 식의 통합 CLI 는 Phase 5 (D) 작업 항목 — 현재 stub 상태. 본 runbook 의 실제 복구는 위에서처럼 restic 직접 호출.

자동화 완성 후 본 runbook 의 명령어 갱신 예정 — 그때까지 운영자는 restic CLI 직접 + docker exec 조합 사용.

Last updated on