# ONEDiary가 먼저 휴대폰에 저장하는 이유

> Canonical URL: https://onediary.kr/ko/blog/offline-first-architecture/

[ONEDiary](/ko/)/[블로그](/ko/blog/)

개발 이야기

ONEDiary는 기록을 휴대폰에 먼저 저장해 인터넷 없이 쓰고 읽을 수 있습니다. 로그인 후 동기화는 선택 사항이며, 오프라인 모드는 다시 켤 때까지 동기화를 일시 중지합니다.

2026년 6월 12일2분 읽기Soosu Studio, Inc.

![로컬 저장과 오프라인 모드, 선택적 동기화를 표현한 ONEDiary 스타일 이미지](/images/onediary/blog-offline-first-720.jpg)

대부분의 일기 앱은 계정 화면에서 시작합니다. ONEDiary는 빈 페이지에서 시작합니다. 이것은 엔지니어링보다 먼저 내려진 제품 결정이지만, 저장 계층도 그 결정에 맞게 구성되어야 오래 유지할 수 있습니다. 그래서 이 부분은 가장 먼저 설계했고 가장 적게 바꿨습니다.

## 원칙: 기록은 네트워크를 기다리지 않는다

저장 계층이 지켜야 할 규칙은 하나입니다. 저장을 누르면 다른 일이 일어나기 전에 기록이 안전하게 보존되어야 합니다. 업로드 대기열에만 넣거나 요청이 진행되는 동안 낙관적으로 그리는 것이 아니라, 기기의 디스크에 로컬 트랜잭션으로 기록하고 그 자리에서 성공 또는 실패를 결정합니다.

이 글의 나머지 내용은 모두 이 원칙에서 나옵니다.

## Room이 기준 데이터다

ONEDiary는 기기의 **Room** 데이터베이스에 기록을 보관합니다. UI는 네트워크에서 읽지 않습니다. 화면은 Kotlin Flow를 통해 Room을 관찰하므로 타임라인, 달력, 검색이 모두 같은 로컬 테이블을 그리고 기록이 저장되는 순간 함께 갱신됩니다.

이 차이는 정확히 짚을 필요가 있습니다. 흔히 오프라인 지원은 서버를 기준으로 두고 기기에는 무효화될 수 있는 캐시를 둔 방식으로 만들어집니다. 피드에는 괜찮은 설계입니다. 하지만 일기에서는 맞지 않습니다. 내가 쓴 내용은 무엇의 캐시가 아니라 원본이고, 사본이 아예 없을 수도 있기 때문입니다.

-   **읽기**는 언제나 Room에서 옵니다. 연결 상태에 따라 로딩되는 화면이 없습니다.
-   **쓰기**는 Room에 커밋되고, 별도 계층이 기기 밖으로 보낼 내용이 있는지 결정합니다.
-   **충돌**은 로컬 데이터를 기준으로 해결하며, 쓰기를 막는 방식으로 해결하지 않습니다.

## Firestore는 집이 아니라 미러다

로그인하고 **데이터 동기화**를 켜면 ONEDiary는 로그인한 기기들이 수렴하도록 기록을 Firestore에 미러링합니다. 문장의 순서가 중요합니다. 로그인은 선택 사항이고, 동기화는 별도의 스위치이며, 미러는 로컬 데이터베이스에서 파생됩니다.

따라서 동기화 계층은 느리거나 실패하거나 재시도할 수 있고, 그 과정이 기록 경험에 드러나지 않아도 됩니다. 업로드 실패는 백그라운드 재시도일 뿐입니다. 기록이 사라지거나 저장 버튼이 막히는 일은 없습니다.

계정을 삭제해도 일기는 삭제되지 않습니다

계정 삭제는 서버에 동기화된 사본을 제거하고 동기화를 끕니다. 기기에 있는 기록은 그대로 남습니다. 이 비대칭은 의도된 것입니다. 서버 상태는 파생 상태이고, 파생 상태가 폐기 가능한 쪽이어야 하기 때문입니다.

## 오프라인 모드는 실제로 무엇을 하나

**오프라인 모드**라는 설정은 동기화 상태를 숨기는 UI 토글처럼 보이기 쉽지만 그렇지 않습니다. 켜면 Firestore 동기화를 멈추고, 대기 중인 변경 내용을 다시 시작할 때까지 기기에 보관합니다.

연결되어 있다는 것과 연결을 사용하고 싶다는 것은 다른 질문이고, 두 번째 답은 사용자만 정할 수 있기 때문에 존재하는 기능입니다. 비싼 로밍 요금, 아직 미러링하고 싶지 않은 기록, 잠시 네트워크를 조용히 두고 싶은 상황 모두 로그아웃하거나 동기화 설정을 잃지 않고 멈출 이유가 됩니다.

다시 끄면 대기 중인 변경 내용이 백그라운드에서 처리됩니다. 그동안 버려지는 내용은 없습니다.

## 기본값이 설계를 말해 준다

새로 설치한 앱이 가질 수 있는 세 가지 상태를 나열해 보면 설계의 순서가 보입니다.

1.  새로 설치한 상태계정 없음, 동기화 없음, AI 접근 없음. 기록하고 읽고 검색하고 사진을 첨부하고 달력을 볼 수 있습니다. 앱은 이 상태로 제공되며 많은 사용자는 계속 이 상태로 사용합니다.
2.  로그인 후 데이터 동기화 켜짐로그인한 기기 사이에서 기록이 수렴합니다. 언제든 끄거나 오프라인 모드로 잠시 멈출 수 있습니다.
3.  AI 접근 허용별도의 명시적인 권한입니다. 허용한 뒤에만 리포트와 일기 채팅이 기록을 읽을 수 있습니다. 동기화를 켜도 AI 접근은 켜지지 않습니다.

이 중 어느 것도 설정이라는 이름을 쓴 업셀이 아닙니다. 사용자가 결정하기 전에는 모두 꺼져 있고, 켰던 화면에서 다시 되돌릴 수 있습니다.

## 우리에게 따르는 비용

솔직히 말하면 로컬 우선 구조는 일이 줄어드는 것이 아니라 늘어나는 선택입니다. 확인할 수 없는 기기에 사는 스키마의 마이그레이션을 관리해야 하고, 잘못된 행을 서버 스크립트로 고칠 수도 없습니다. 받지 않는 데이터를 기기 간 전체 텍스트 검색하는 일처럼 중앙 데이터베이스라면 쉬운 기능도 더 어렵거나 아예 선택지에서 빠집니다.

되돌릴 수 없는 것을 지키는 앱이라면 그 비용을 지불할 가치가 있다고 생각합니다. 다만 비용은 실제로 존재하고, 모든 릴리스에서 지불해야 합니다.

## 직접 사용해 보세요.

Google Play에서 무료로 받을 수 있습니다. Android 10 이상에서 계정 없이 기록을 시작하세요.

[Google Play에서 무료로 사용](https://play.google.com/store/apps/details?id=com.soosu.onediary)

## 계속 읽기

[**하루 이모지 하나로 쓰는 감정 일기**ONEDiary의 감정 이모지를 가벼운 무드 트래커로 쓰는 방법을 소개합니다. 기록마다 감정 하나와 이유 한 줄을 남기고, 리포트 탭에서 패턴을 읽어 보세요.](/ko/blog/mood-tracking-with-one-emoji/) [**일기 앱을 고르기 전에 물어볼 10가지 질문**오프라인 기록, 사진, 검색, 인사이트, 리포트, 개인정보 설정, 알림이라는 관점에서 일기 앱을 고를 때 확인할 10가지 질문을 ONEDiary와 함께 살펴봅니다.](/ko/blog/10-questions-before-choosing-a-diary-app/) [**매일 쓰는 일기가 실제로 주는 것**매일 쓰는 일기가 시간이 지나며 가치 있어지는 이유를 설명합니다. 평범한 날을 보존하고 패턴을 보여 주며 습관을 유지하게 하는 알림과 회고 기능을 다룹니다.](/ko/blog/why-write-every-day/)
