웹 애플리케이션 상태 저장 문제 해결: Flowgram.ai의 이중 엔진 솔루션 분석
웹 애플리케이션에서 사용자가 편집 중인 데이터가 갑자기 사라지는 문제에 시달리고 계신가요? 사용자가 절반만 완성한 다이어그램이 예기치 않게 새로고침 후 사라지는 경험을 하셨나요? 본 기사에서는 Flowgram.ai가 localStorage 기본 저장소와 HistoryStorage 전문 엔진의 이중 솔루션을 통해 프론트엔드 상태 저장 문제를 어떻게 해결하는지 심층적으로 분석합니다. 이 글을 통해 두 가지 저장 방식의 기술적 구현, 성능 비교 및 Flowgram.ai에서의 최적 활용법을 마스터할 수 있습니다.
상태 저장을 위한 두 가지 기술적 접근법
Flowgram.ai는 다양한 시나리오 요구사항에 대응하기 위해 두 가지 보완적인 상태 저장 솔루션을 설계한 계층형 저장 아키텍처를 채택했습니다:
1. 가벼운 저장소: localStorage 구현
LocalStorageService는 간단한 데이터 영속화에 적합한 기본 키-값 저장 기능을 제공합니다. 핵심 구현은 packages/canvas-engine/core/src/services/storage-service.ts에 위치하며, 주요 코드는 다음과 같습니다:
@injectable()
export class LocalStorageService implements StorageService {
private storage: LocalStorage;
private _prefix = '__gedit:';
setData<T>(key: string, data: T): void {
this.storage[this.prefix(key)] = JSON.stringify(data);
}
getData<T>(key: string, defaultValue?: T): T {
const result = this.storage[this.prefix(key)];
if (result === undefined) {
return defaultValue as any;
}
return JSON.parse(result);
}
@postConstruct()
protected init(): void {
if (typeof window !== 'undefined' && window.localStorage) {
this.storage = window.localStorage;
} else {
this.storage = {};
}
}
}
이 구현은 키 이름 충돌을 방지하기 위한 접두사 메커니즘을 통해 브라우저 환경과의 호환성을 처리하며, 서버 사이드 렌더링 시나리오에서도 안전하게 실행될 수 있도록 보장합니다.
2. 전문 엔진: HistoryStorage 아키텍처
복잡한 작업 기록의 경우, Flowgram.ai는 IndexedDB 기반의 HistoryStorage 엔진을 설계했습니다. 전체 구현은 packages/common/history-storage/ 디렉토리에 위치하며, 핵심 구성 요소는 다음과 같습니다:
- HistoryStorageManager: 기록과 작업의 저장 로직을 조정
- HistoryDatabase: Dexie 기반 IndexedDB 래퍼
- 타입 정의: 기록 데이터 구조의 표준화
HistoryStorage 심층 분석
데이터 모델 설계
HistoryStorage는 구조화된 데이터 모델을 채택하여 작업 기록을 HistoryRecord와 HistoryOperationRecord 두 가지 핵심 엔티티로 분리합니다. packages/common/history-storage/src/types.ts에 정의되어 있습니다:
export interface HistoryRecord {
uuid: string;
timestamp: number;
type: string;
resourceURI: string;
resourceJSON: string;
}
export interface HistoryOperationRecord {
uuid: string;
type: string;
timestamp: number;
label: string;
uri: string;
resourceURI: string;
description: string;
value: string;
historyId: string;
}
이 설계는 기록과 작업 세부 정보의 연관 저장을 구현하여 복잡한 되돌리기 및 실행 취소 작업을 지원합니다.
저장 흐름 제어
HistoryStorageManager는 기록 스택 변경 이벤트를 수신하여 자동 영속화를 구현합니다. packages/common/history-storage/src/history-storage-manager.ts의 핵심 로직은 다음과 같습니다:
this._toDispose.push(
this.historyManager.historyStack.onChange(event => {
if (event.type === HistoryStackChangeType.ADD) {
const [history, operations] = this.historyItemToRecord(event.service, event.value);
this.db.addHistoryRecord(history, operations).catch(console.error);
}
if ([HistoryStackChangeType.ADD_OPERATION, HistoryStackChangeType.UPDATE_OPERATION].includes(event.type)) {
// 스냅샷 업데이트 로직
this.db.updateHistoryByUUID(historyItem.id, {
resourceJSON: service.getSnapshot() || ''
}).catch(console.error);
}
})
);
데이터베이스 최적화 전략
HistoryDatabase는 여러 저장 최적화 메커니즘을 구현합니다:
- 용량 제어:
resourceStorageLimit를 통해 단일 리소스의 최대 기록 수를 제한 - 트랜잭션 지원: 기록과 작업의 원자성 저장 보장
- 인덱스 설계: 자주 사용되는 쿼리 필드에 인덱스 생성으로 성능 향상
핵심 구현은 packages/common/history-storage/src/history-database.ts의 addHistoryRecord 메서드에 있습니다:
async addHistoryRecord(history: HistoryRecord, operations: HistoryOperationRecord[]) {
return this.transaction('rw', this.history, this.operation, async () => {
const count = await this.history.where({ resourceURI: history.resourceURI }).count();
if (count >= this.resourceStorageLimit) {
// 제한을 초과할 경우 가장 오래된 기록 삭제
const limit = count - this.resourceStorageLimit;
const items = await this.history.where({ resourceURI: history.resourceURI }).limit(limit).toArray();
// 일괄 삭제 로직
}
return Promise.all([this.history.add(history), this.operation.bulkAdd(operations)]);
});
}
두 가지 솔루션의 기술적 비교
| 특성 | localStorage 솔루션 | HistoryStorage 솔루션 |
|---|---|---|
| 저장 용량 | 일반적으로 5MB | 이론적 무제한 (하드디스크 공간 제한) |
| 데이터 구조 | 간단한 키-값 쌍 | 구조화된 데이터 모델 |
| 쿼리 능력 | 키 조회만 지원 | 다중 조건 복잡 쿼리 지원 |
| 성능 | 소규모 데이터 효율적 | 대규모 데이터에서 더 우수 |
| 적용 시나리오 | 설정, 선호도 설정 | 작업 기록, 복잡 상태 |
| 구현 복잡도 | 간단 | 중간-높음 |
Flowgram.ai에서의 최적 활용법
1. 계층형 저장 전략
Flowgram.ai는 데이터 특성에 따라 적절한 저장 방식을 선택합니다:
- UI 상태 및 설정:
LocalStorageService를 사용하여 저장, 예: packages/plugins/free-container-plugin/src/sub-canvas/components/tips/global-store.ts의 팁 상태 기억 - 편집 기록 및 스냅샷:
HistoryStorage를 사용하여 복잡한 작업의 되돌리기 지원
2. 저장 보안 메커니즘
시스템은 다중 보안 메커니즘을 구현합니다:
- 데이터 자동 백업: 중요 작업 실시간 기록
- 버전 제어: 기록 상태의 정확한 복원 지원
- 예외 처리: 완전한 오류 캐치 및 로그 기록
3. 성능 최적화 제안
실제 사용 시 다음을 권장합니다:
- 자주 변경되는 대규모 상태에는 HistoryStorage 사용
- 간단한 설정 항목에는 localStorage 사용
- 더 이상 필요 없는 기록 데이터 주기적 정리
결론 및 확장
Flowgram.ai의 이중 엔진 저장 솔루션은 웹 애플리케이션 상태 저장 문제에 대한 완전한 해결책을 제공합니다. LocalStorageService는 간단한 시나리오 요구사항을 충족시키며, HistoryStorage 엔진은 복잡한 편집 시나리오에 전문적인 지원을 제공합니다. 개발자는 다음과 같은 방식으로 저장 기능을 확장할 수 있습니다:
- HistoryDatabase에 암호화 저장 지원 추가
- 클라우드 동기화 어댑터 구현
- 저장 전략 동적 전환 메커니즘 개발
전체 구현 코드는 다음을 참조하세요:
- 기본 저장소: packages/canvas-engine/core/src/services/storage-service.ts
- 기록 저장소: packages/common/history-storage/