auto 항상 reinstall 재설치 자동 설치 /always launch / start publish rebuild
ver2 isle data save back up / sync
mac version : Sync Isle ver2
# Data Survival Blueprint — macOS 버전
## 업데이트·재설치 후에도 데이터·웹 로그인 유지하기
> **목적:** macOS 앱에서 사용자의 로컬 데이터와 웹 로그인 상태를 최대한 안전하게 유지하는 구조를 설명한다.
> Flutter macOS 앱, 네이티브 macOS 앱, Electron류 데스크톱 앱에도 비슷한 방식으로 적용할 수 있다.
---
## 1. 한 줄 요약
macOS에서는 앱 업데이트만으로는 보통 사용자 데이터가 지워지지 않는다.
하지만 앱 삭제, 캐시 초기화, DB 손상, 강제 종료에 대비하려면 다음 3층 구조가 필요하다.
> **① 앱 내부 저장소 + ② Documents 백업 폴더 + ③ Checkpoint 파일**
---
## 2. macOS 데이터 생존 구조
| 상황 | 사용자 데이터 | 웹 로그인 | 복구 방식 |
| ------------- | ------------------ | ------------ | ------------------------- |
| 앱 업데이트 | 유지 가능 | 유지 가능 | 같은 Bundle ID와 같은 저장 경로 유지 |
| 앱 강제 종료 후 재실행 | 유지 가능 | 유지 가능 | Checkpoint로 보조 |
| 앱 삭제 후 재설치 | 앱 내부 데이터는 사라질 수 있음 | 보통 다시 로그인 필요 | Documents 백업 폴더에서 복구 |
| 다른 Mac으로 이동 | 자동 유지 안 됨 | 다시 로그인 필요 | 백업 JSON 파일로 수동 복원 |
---
## 3. macOS 전용 3계층 모델
```mermaid
flowchart TB
subgraph L1["Layer 1 — Primary Store"]
Hive["Hive boxes\nApplication Support / Documents"]
WebView["WebView Cookie Store\nOS-managed"]
end
subgraph L2["Layer 2 — Survival Backup"]
Backup["~/Documents/{AppName} Backup/current.json"]
Sync["notifyLocalDataChanged()\n800ms debounce"]
end
subgraph L3["Layer 3 — Checkpoint"]
Checkpoint["isle_state_checkpoint.b64\n25초 주기 저장"]
end
UI["UI / Stores"] --> Hive
UI --> WebView
Hive --> Sync --> Backup
Hive --> Checkpoint
Backup --> Bootstrap["앱 부팅 시 복구"]
Checkpoint --> Bootstrap
앱이 평소에 직접 읽고 쓰는 기본 저장소다.
macOS Flutter 앱에서는 보통 다음을 사용한다.
앱 업데이트 시 데이터가 유지되려면 다음 조건이 필요하다.
앱 내부 데이터가 비거나 손상되었을 때 복구하기 위한 외부 백업이다.
macOS 기본 백업 위치:
~/Documents/{AppName} Backup/current.json
예시:
~/Documents/Isle Backup/current.json
Store에서 데이터가 저장될 때마다 즉시 백업하지 말고, debounce를 둔다.
Store.save()
→ notifyLocalDataChanged()
→ 800ms debounce
→ current.json atomic write
백업 파일을 바로 덮어쓰지 않는다.
current.json.tmp 작성
→ 성공하면 current.json으로 rename
이렇게 해야 저장 중 앱이 죽어도 백업 파일이 망가지지 않는다.
Survival Backup이 실행되기 전에 앱이 강제 종료되거나, 일부 Hive box만 손상된 경우를 대비한다.
기본 파일:
Application Documents/isle_state_checkpoint.b64
저장 주기:
25초마다 1회
앱 종료 또는 paused 시 1회
Checkpoint는 백업의 주 저장소가 아니다. 크래시 대비용 임시 스냅샷이다.
runApp() 전에 아래 순서를 지킨다.
1. WidgetsFlutterBinding.ensureInitialized()
2. Hive.initFlutter()
3. 모든 Hive box open
4. 캐시성 플래그 복구
5. SurvivalBackupService.bootstrapOnLaunch()
6. CheckpointService.restoreFromCheckpointIfLocalEmpty()
7. CheckpointService.startPeriodicCheckpoint()
8. runApp()
중요한 점:
복구는 로컬 데이터가 비어 있을 때만 해야 한다.
이미 사용자의 정상 데이터가 있는데 백업 파일을 덮어씌우면 오히려 최신 데이터가 날아간다.
앱이 “새로 설치된 상태처럼 비어 있는지” 판단하는 함수가 필요하다.
예시 기준:
차단 목록 empty
스케줄 empty
라이브러리 empty
사용자 설정 empty
피드 데이터 empty
전부 비어 있으면:
localLooksFresh() == true
이때만 Survival Backup 또는 Checkpoint 복구를 시도한다.
반대로 하나라도 의미 있는 사용자 데이터가 있으면:
localLooksFresh() == false
이 경우에는 백업으로 덮어쓰지 않는다.
macOS WebView는 OS가 관리하는 쿠키 저장소를 사용한다. 같은 앱, 같은 Bundle ID, 같은 WebView 저장소를 유지하면 업데이트 후에도 로그인 상태가 유지될 수 있다.
| 규칙 | 이유 |
|---|---|
| 앱 시작 시 쿠키 삭제 금지 | 로그인 유지 |
| 화면 이동마다 WebView clearCache 금지 | 세션 유지 |
| 로그아웃 버튼에서만 쿠키 삭제 | 사용자 의도 존중 |
| User-Agent를 갑자기 바꾸지 않기 | 웹 서비스 보안 감지 회피 |
| 백업 JSON에 쿠키를 넣지 않기 | 보안 및 정책 리스크 방지 |
앱을 삭제하면 WebView 쿠키도 사라질 수 있다. 따라서 앱 재설치 후 웹 로그인은 사용자가 다시 해야 한다.
Survival Backup은 앱 데이터 복구용이고, 웹 로그인 쿠키 복구용이 아니다.
각 Store는 저장 후 반드시 변경 알림을 호출한다.
class ExampleStore {
static const _boxName = 'my_app_example';
static Box<String>? _box;
static Future<void> ensureOpen() async {
if (_box != null && _box!.isOpen) return;
_box = await Hive.openBox<String>(_boxName);
}
static Future<void> saveAll(List<ExampleModel> items) async {
await ensureOpen();
await _box!.put(
'items_v1',
jsonEncode(items.map((e) => e.toJson()).toList()),
);
notifyLocalDataChanged();
}
}
핵심:
Store 저장
→ notifyLocalDataChanged()
→ Survival Backup 동기화
이 호출이 빠지면 백업이 갱신되지 않는다.
snapshot_version 상수 만들기buildSnapshotMap() 구현current.json.tmp 작성 후 current.json으로 renamenotifyLocalDataChanged() debounce 500~1000ms 적용localLooksFresh() 구현buildSnapshotMap() 재사용macOS 설정 화면에는 이런 문구를 넣으면 좋다.
앱 업데이트만으로는 보통 데이터가 유지됩니다.
다만 앱 삭제, 디스크 정리, 데이터 손상에 대비하려면
Documents 폴더의 백업 파일을 유지해 주세요.
백업 폴더 안내:
기본 백업 위치:
~/Documents/Isle Backup/current.json
웹 로그인 안내:
YouTube, Instagram 등 웹 로그인은 앱 업데이트 후에는 유지될 수 있지만,
앱 삭제 후 재설치하면 다시 로그인해야 할 수 있습니다.
보안을 위해 쿠키는 백업 JSON에 포함하지 않습니다.
하지 말아야 할 것:
clearCache()를 매 실행마다 호출localLooksFresh() 없이 무조건 백업 복원notifyLocalDataChanged() 호출 누락~/Documents/Isle Backup/current.json 생성 확인macOS 앱의 데이터 생존 전략은 다음과 같다.
~/Documents/{AppName} Backup/current.json에 Survival Backup을 둔다.macOS 데이터 생존 = 앱 내부 저장소 + Documents 백업 + Checkpoint
업데이트 = 유지
삭제 후 재설치 = 백업에서 복구
웹 로그인 = 업데이트는 유지 가능, 재설치는 다시 로그인
쿠키는 백업하지 않음
복구는 localLooksFresh()일 때만
[auto 항상 reinstall 재설치 자동 설치 /always launch / start publish rebuild](<https://vivid-wave.notion.site/auto-reinstall-always-launch-start-publish-rebuild-35b6d6203eea804a8938def66494da76>)
[new app 새로운 앱할때 항상 바꿔야 할 것](<https://vivid-wave.notion.site/new-app-35c6d6203eea80b8be17c27cf9ae8cb6>)
[backup recover 성공 ! 메모 square](<https://vivid-wave.notion.site/backup-recover-square-3666d6203eea80fca98afb4af6bd1e3e>)