0018. 계획 문서 클라우드 동기화는 해시 주소 저장 + 단일 포인터로 한다
- 상태: 제안
- 날짜: 2026-10-03
- 관련: 없음 (설계 논의만 있고 구현 전)
~/.belloga/plans 아래 requirements.md, design.md, tasks.md는 지금 기기 로컬에만 있다. 여러 기기에서 이어서 보고 쓰려면 클라우드에 저장하고 동기화하는 경로가 필요하다.
이 문서들은 다음 제약을 가진다.
- 한 사용자가 기기를 바꿔가며 쓴다. 여러 사람이 동시에 같은 문서를 고치는 공동 편집이 아니다.
- 대부분의 쓰기는 사람이 아니라 에이전트(하네스)가 한다. 그래서 같은 문서를 두 기기에서 같은 순간에 고칠 확률은 낮다.
- 다만 한 기기가 오프라인으로 작업한 사이 다른 기기가 먼저 동기화하는 경우는 남아, 충돌 가능성 자체를 없앨 수는 없다.
이 제약에서 저장·동기화 방식으로 세 가지를 검토했다: Cloud SQL에 전체 텍스트를 버전마다 쌓는 방식, 서버가 사용자별 git 저장소를 직접 운영하는 방식, Automerge/Yjs 같은 CRDT 라이브러리.
GCS에 문서 내용을 해시로 주소를 매겨 불변 객체로 저장하고, 가벼운 메타데이터 저장소(Cloud SQL 또는 Firestore)에는 문서별 “현재 해시” 하나만 둔다. 기기별 브랜치는 상시 유지하지 않는다.
- 동기화 쓰기는 “직전에 받아간 해시(base)“를 함께 보낸다.
base가 메타데이터의 현재 해시와 같으면 그대로 반영하고 포인터만 갱신한다. 대부분의 쓰기가 이 경로를 탄다.- 다르면(그 사이 다른 기기가 먼저 반영함) 원래 문서는 건드리지 않고, 보낸 내용을
main-conflict-{기기id}같은 별도 객체로 저장한 뒤 충돌로 응답한다. 사용자가 그때 가서 고른다. - 충돌 판정은 파일 전체 단위로 한다. 줄 단위 3-way merge는 하지 않는다.
- 동기화를 언제 트리거할지(파일 변경 감시 vs 명시적 저장 시점)는 이 문서에서 정하지 않는다. 별도로 다룬다.
근거 / 검토한 대안
섹션 제목: “근거 / 검토한 대안”- Cloud SQL에 저장마다 전체 텍스트를 새 row로 쌓는다. 구현은 쉽지만 내용이 거의 같아도 매번 통째로 쌓여 테이블이 비대해지고 백업·복제 비용이 커진다. 기각.
- 서버에 사용자별 bare git 저장소를 두고 isomorphic-git/nodegit으로 진짜 merge를 돌린다. 충돌을 파일 단위로만 다루기로 했으므로 git의 줄 단위 merge를 쓸 데가 없는데, 상태를 가진 서버(디스크 필요)를 운영하는 비용만 진다. 기각.
- Automerge/Yjs 같은 CRDT. 실시간 공동 편집이 핵심 가치인데, 이 문서들은 한 사용자가 기기를 바꿔가며 쓰는 용도라 그 가치를 쓸 데가 없다. 문서를 CRDT 문서 모델로 옮겨 담는 비용만 남는다. 기각.
- 채택안. 해시 주소 저장으로 내용 중복은 자동 제거되고, 평소 스키마는 “문서당 현재 해시 하나”로 끝나 구현과 추론이 가장 가볍다. 충돌은 드물게만 일어나는 예외 경로로 몰아둔다.
- 두 기기가 같은 문서를 고치고 거의 동시에 동기화하면, 늦게 도착한 쪽은 자동 반영되지 않고 충돌 객체로 남는다. 사용자가 직접 보고 골라야 한다.
- 사용자가 충돌 객체를 방치하면 고아 객체로 쌓인다. 정리 정책(예: N일 후 삭제)은 후속 과제로 남긴다.
- 충돌이 파일 단위라, 한 문서 안에서 사람이 고친 부분과 에이전트가 고친 부분이 섞여 있으면 충돌 시 문서 전체를 다시 맞춰야 한다. 문서를 더 작은 단위로 쪼개면 줄일 수 있지만 지금은 하지 않는다.
- 이 로직을 돌릴 백엔드 서비스 형태(Cloud Run, Cloud Functions 등)와 OAuth 로그인과의 연결은 별도로 설계해야 한다.