
- katsubox의 앨범, 공유 링크, 페이지, 댓글 메타데이터는 katsubox.db 파일 하나에만 있어서, 이 파일이 지워지면 복구할 방법이 없다.
- 앱이 스케줄러를 갖지 않는 대신 launchd가 매일 04:10에 백업 API를 호출하고, SQLite 온라인 백업으로 일관된 스냅샷을 만든다.
- 설치 후 6일 동안 5번 돌았고 10월 23일 하루가 비었는데, Mac이 그 시간에 꺼져 있었던 것이 확인됐다.
이 글은 katsubee·katsubox 소개 글에서 남겨 둔 개선점 가운데 katsubox의 DB 백업을 다룬 시리즈의 네 번째 글이다.
파일은 남아도 DB가 없으면 복구할 수 없다
katsubox는 파일을 데이터 폴더에 그대로 쌓는다. 폴더 구조가 곧 정보라서 파일만 보면 백업이 필요 없어 보인다. 문제는 그 옆에 있는 katsubox.db다. 앨범 구성, 공유 링크, 페이지의 제목과 설명, 방문자 댓글, 첨부, 파일 메모가 이 파일 하나에만 들어 있다.
이 파일이 지워지면 파일들은 멀쩡해도 앨범과 공유 링크, 댓글은 복구할 수 없다. 소개 글에서 개선점으로 꼽은 이유가 이것이다. 데이터 폴더는 정리 스크립트(prune-old.sh)가 오래된 파일을 지우기도 하는 곳이라, DB는 따로 지켜야 했다.
앱이 스케줄러를 돌리지 않는다
가장 먼저 정한 것은 누가 백업을 호출하느냐였다. 앱 안에 스케줄러를 넣을 수도 있었지만 katsubox는 컨테이너 한 개로 단순하게 돌리는 서비스라 그렇게 하지 않았다. 앱은 POST /api/maintenance/backup-db 하나만 열어 두고, 호출은 Mac의 launchd가 맡는다.
백업 스크립트(backup-db.sh)도 DB 파일을 직접 만지지 않는다. 컨테이너 밖에서 파일을 복사하면 앱 밖에서 쓰는 경로가 생겨서 경로 동기화가 깨질 수 있어서다. 스크립트는 curl로 API를 호출할 뿐이고, 비밀번호는 launchd에 환경변수가 없으므로 프로젝트의 .env에서 읽는다. plist에는 비밀번호를 넣지 않는다.
파일 복사 대신 SQLite 온라인 백업
스냅샷은 sqlite3의 온라인 백업 API로 만든다. DB가 WAL 모드로 돌고 있을 때 단순 파일 복사는 쓰기 도중의 상태를 복사할 위험이 있다. 온라인 백업은 일관된 복사본을 만들어 준다.
스냅샷은 데이터 폴더의 .backups에 타임스탬프 이름으로 쌓이고 기본 10개만 남긴다. 개수는 환경변수(KATSUBOX_DB_BACKUP_KEEP)로 바꾼다. 리브랜딩 전 이름인 katsudrop 스냅샷도 같은 로테이션 대상으로 센다.
매일 04:10, 그리고 지우기 전 자동 백업
launchd 설정은 매일 04:10에 스크립트를 실행하도록 되어 있다. 대시보드의 지금 백업 버튼도 같은 API를 쓰므로 수동과 자동의 경로가 하나다.
DB 정리 기능도 같은 스냅샷을 쓴다. 디스크에서 사라진 파일의 낡은 DB 행(메모, 댓글, 첨부, 앨범 연결)을 지우는 기능인데, 기본은 미리보기이고 지울 때는 먼저 DB를 스냅샷한다. 저장소 폴더가 비어 있으면 전부 낡은 행으로 오판할 수 있어서 그 저장소는 건너뛴다. 마운트가 풀린 날 정리 버튼을 눌러도 메타데이터가 날아가지 않게 하는 장치다.
실제로 돌았는지 확인했다
주간 보고에서는 이 자동화가 실제로 도는지 확인하지 못했다고 적혀 있었다. 가장 최근 백업 시각이 10월 20일 00:08이라 매일 04:10 설정과 맞지 않았기 때문이다. 이번에 .backups 폴더와 로그를 직접 열어 확인했다.
결론은 자동으로 돌고 있다
결론은 자동으로 돌고 있다. 파일 이름의 시각이 UTC라서 04:10 KST가 19:10으로 보였을 뿐이고, 파일 수정 시각은 10월 20일부터 25일까지 매일 04:10 KST다. 로그에는 성공 응답이 다섯 줄 남아 있고 오류 로그는 비어 있다. 10월 20일 00:08의 파일은 정기 실행이 아닌 수동 1회로 보인다.

10월 23일 백업이 빠진 이유
다만 10월 23일 04:10 백업은 없다. 성공 로그도 오류 로그도 남지 않았는데, 원인은 Mac이 꺼져 있었던 것이다. 시스템의 재부팅 기록에 따르면 10월 23일 02:36에 종료돼 같은 날 20:38에 다시 켜졌다. 그 사이에 있는 04:10 작업은 실행될 수 없었다.
같은 날 새벽 작업도 빠졌다
같은 날 새벽의 다른 작업도 함께 빠졌다. 03:30의 RAG 로우데이터 수집과 04:00의 일반 질의 수집 파일도 10월 23일 하루만 없다. 서로 다른 서비스의 작업 세 개가 같은 날 빠진 이유가 이것이다. 종료된 이유는 기록에서 확인하지 못했다. 문서의 한계 항목에도 Mac이 꺼져 있거나 로그아웃 상태면 돌지 않는다고 적혀 있었고, 이번에 실제로 그 일이 일어났다.
백업 크기가 달라진 이유
정기 백업 파일은 10월 20일 88KB에서 21일부터 168KB로 늘었다. 같은 주에 페이지, 댓글, 공유 링크 관련 테이블에 데이터가 쌓이기 시작한 시기와 겹치지만, 늘어난 이유를 파일 내용으로 확인하지는 않았다.


현재 폴더에는 스냅샷 7개가 있다. 정기 5개, 수동 1개, 리브랜딩 전 katsudrop 이름의 1개다. 상한 10개에는 아직 여유가 있어서 오래된 것을 지우는 로테이션은 한 번도 돌지 않았다. 하루 한 번이면 약 열흘치를 들고 있는 셈이라, 더 오래된 시점으로 돌아가야 하는 사고에는 부족하다.
복원 절차는 아직 문서에 없다
백업은 복원할 수 있어야 의미가 있다. 저장소 문서에는 대시보드에서 백업을 만드는 방법과 launchd 설치 방법이 있지만 스냅샷으로 DB를 되돌리는 절차는 없다. 온라인 백업으로 만든 파일이라 앱을 멈춘 뒤 DB 자리에 놓으면 될 것으로 짐작하지만, 실제로 해 본 적이 없다.
복원 리허설이 없는 백업은 가정에 가깝다. 그래서 복원을 한 번 해 보고 그 순서를 문서로 남기는 일을 개선 목록 맨 앞에 두었다.
남은 개선점
지금 구조에는 약점이 둘 있다. 첫째는 놓친 백업을 알아채거나 메우는 방법이 없다는 점이다. 10월 23일 공백도 파일 목록을 열어 보고서야 알았다. launchd는 꺼져 있던 동안 지나간 시각을 나중에 보충해 주지 않으므로, 부팅할 때 한 번 더 실행하는 설정(RunAtLoad)을 추가하는 방법을 검토할 예정이다. 최근 백업 시각은 대시보드 응답에 이미 들어 있으니, 시각이 하루 넘게 지났을 때 알리는 쪽이 가장 작은 수정이다.
둘째는 백업이 같은 Mac의 같은 디스크에 있다는 점이다. 이 구조는 DB 파일을 실수로 지우거나 망가뜨리는 사고에는 대비하지만 디스크 고장에는 대비하지 못한다. 데이터 폴더가 이미 Parallels 공유 폴더와 FTP 경로를 지나므로, 스냅샷을 다른 위치로 한 벌 더 복사하는 방법을 검토할 예정이다. 복원 절차를 실제로 한 번 해 본 기록이 없다는 점도 같이 점검 목록에 올렸다.
'개발이야기' 카테고리의 다른 글
| RAG 임베딩 검색 품질 개선기, 리랭킹은 후보 회수 뒤에야 효과가 났다 (1) | 2026.10.27 |
|---|---|
| 환각 방지 프롬프트, 효과는 입증 못 했다 (0) | 2026.10.27 |
| katsubee 답변 품질 측정, 골든셋과 한계 (0) | 2026.10.26 |
| katsubee·katsubox 소개, 직접 구축한 AI 채팅 (0) | 2026.10.26 |