# SharedDoc Class

## Content

[SharedDoc](/spreadjs/api/v19/collaboration/js-collaboration-ot-client/classes/SharedDoc)는 공유 문서 인스턴스를 나타내며, 문서 스냅샷(`snapshot`)과 작업(`op`)을 관리하고, 연결(`Connection`)을 통해 서버와 데이터를 동기화하는 데 사용됩니다. 다중 사용자 작업의 일관성을 보장하기 위해 OT(Operational Transformation) 메커니즘을 지원합니다. 이 문서는 클라이언트 측에서 `SharedDoc`를 사용하는 방법을 다음 항목 중심으로 설명합니다.

* `SharedDoc` 초기화
* 문서 생성 및 삭제
* 문서 스냅샷 요청 및 업데이트
* 작업 제출, 수신 및 변환
* 이벤트 수신

## 초기화

[SharedDoc 초기화](/spreadjs/docs/v19/spreadjs-collaboration-server/collaboration-framework/js-collaboration-ot/initalizing-shareddoc)

## 속성

| 속성 이름 | 설명 | 타입 |
| ----- | --- | --- |
| `id` | 공유 문서의 고유 식별자를 반환합니다. | `string` (읽기 전용) |
| `version` | 현재 스냅샷의 버전 번호를 나타냅니다. | `number | undefined` (읽기 전용) |
| `type` | 스냅샷의 작업 타입(OT 타입)을 나타냅니다. | `OT_Type<S, T> | undefined` (읽기 전용) |
| `data` | 현재 스냅샷의 데이터를 나타냅니다. | `S | undefined` (읽기 전용) |
| `connection` | 공유 문서의 연결 객체를 반환합니다. | `Connection` (읽기 전용) |

## 메서드

### fetch

문서의 스냅샷 데이터를 가져오며, 결과는 `doc.data`에 저장됩니다.

```typescript
fetch(): Promise<void>
```

**반환값**

* `Promise<void>`: 스냅샷을 가져온 후 resolve되며, 가져온 스냅샷 데이터는 `doc.data`에 저장됩니다.

**예제**

```typescript
try {
    await doc.fetch();
    if (!doc.type) {
        return console.log('문서가 존재하지 않습니다');
    }
    console.log('문서 스냅샷', doc.data);
} catch (error) {
    if (error) {
        return console.error(error);
    }
}
```

### subscribe

문서의 스냅샷 데이터를 가져오고 이후의 업데이트를 수신합니다.

```typescript
subscribe(): Promise<void>
```

**반환값**

* `Promise<void>`: 스냅샷 구독이 완료되면 resolve되며, 구독된 스냅샷 데이터는 `doc.data`에 저장됩니다.

**예제**

```typescript
try {
    await doc.subscribe();
    if (!doc.type) {
        return console.log('문서가 존재하지 않습니다');
    }
    console.log('문서 스냅샷', doc.data);
    
    doc.on('op', (op, source) => {
        console.log('문서가 업데이트됨', op, source);
    });
} catch (error) {
    if (error) {
        return console.error(error);
    }
}
```

### submitOp

문서에 작업을 제출합니다.

```typescript
submitOp(component: T, options?: IOptions): Promise<void>
```

**매개변수**

* `component` (`T`): 작업(op) 컴포넌트
* `options` (`IOptions`): 작업 옵션(선택)

**반환값**

* `Promise<void>`: 작업 제출이 완료되면 resolve됩니다.

**예제**

```typescript
// 위치 1에 텍스트 'Hi' 삽입
await doc.submitOp({ pos: 1, text: 'Hi' }, { source: doc.connection.id });
console.log('작업이 제출되었습니다');
```

### create

새 문서를 생성합니다.

```typescript
create(data: S, type: string, options: IOptions): Promise<void>
```

**매개변수**

* `data` (`S`): 스냅샷을 초기화하는 데 사용할 데이터
* `type` (`string`): OT 타입의 URI
* `options` (`IOptions`): 작업 옵션

**반환값**

* `Promise<void>`: 문서 생성이 완료되면 resolve됩니다.

**예제**

```typescript
try {
    await doc.create('Hello', textType.uri, {});
    console.log('문서가 성공적으로 생성됨:', doc.data); // "Hello"
} catch (err) {
    console.error('생성 실패:', err);
}
```

### fetchHistorySnapshot

문서의 과거 스냅샷 데이터를 가져옵니다.

```typescript
fetchHistorySnapshot(options: IHistorySnapshotRequestOptions): Promise<ISnapshot<S>>
```

**매개변수**

* `options` (`IHistorySnapshotRequestOptions`): 과거 스냅샷 요청 옵션

**반환값**

* `Promise<ISnapshot<S>>`: 과거 스냅샷을 가져온 후 resolve됩니다.

**예제**

```typescript
const snapshot = await doc.fetchHistorySnapshot({ version: 6 }, textType.uri, {});
console.log('과거 스냅샷:', snapshot);
```

### del

문서를 삭제합니다.

```typescript
del(options: IOptions): Promise<void>
```

**매개변수**

* `options` (`IOptions`): 삭제 옵션

**반환값**

* `Promise<void>`: 문서 삭제가 완료되면 resolve됩니다.

### restore

문서를 특정 버전으로 복원합니다.

```typescript
restore(targetVersion: number, options?: IOptions): Promise<void>;
```

**매개변수**

* `targetVersion` (`number`): 복원할 대상 버전 번호
* `options` (`IOptions`): 복원 옵션

**반환값**

* `Promise<void>`: 문서 복원이 완료되면 resolve됩니다.

**예제**

```typescript
await doc.restore(10); 
console.log('문서가 성공적으로 복원됨:', doc.data); // 버전 10의 데이터
```

### hardRollback

스냅샷 데이터를 최신 버전으로 강제로 롤백합니다.

```typescript
hardRollback(): Promise<void>
```

**반환값**

* `Promise<void>`: 롤백이 완료되면 resolve됩니다.

### destroy

인스턴스를 제거하고 모든 리소스를 해제합니다.

```typescript
destroy(): void
```

## 이벤트

`SharedDoc`는 `on`, `once`, `off` 메서드를 통해 다음 이벤트를 지원합니다.

| 이벤트 이름 | 설명 | 매개변수 |
| ------ | --- | ---- |
| `error` | 오류가 발생했을 때 트리거됩니다. | `err`: `OTError` 객체 |
| `load` | 스냅샷을 가져오거나 구독한 후 트리거됩니다. | 없음 |
| `create` | 문서가 생성될 때 트리거됩니다. | `source`: 작업 출처 |
| `beforeOp` | 작업이 적용되기 전에 트리거됩니다. | `op`: 작업 데이터, `source`: 출처 |
| `op` | 작업이 적용된 후 트리거됩니다. | `op`: 작업 데이터, `source`: 출처 |
| `del` | 문서가 삭제될 때 트리거됩니다. | `data`: 삭제 전 데이터, `source`: 출처 |
| `restore` | 문서가 복원될 때 트리거됩니다. | `version`: 복원된 버전, `source`: 출처 |
| `hardRollback` | 강제 롤백 중에 트리거됩니다. | 없음 |

### on

이벤트 리스너를 등록합니다.

```typescript
on<NAME extends keyof ISharedDocEvents<S, T>>(name: NAME, f: ISharedDocEvents<S, T>[NAME]): ISharedDocEvents<S, T>[NAME];
```

**매개변수**

* `name` (`NAME`): 이벤트 이름 (`ISharedDocEvents<S, T>` 인터페이스의 키)
* `f` (`ISharedDocEvents<S, T>[NAME]`): 이벤트 처리 함수

**반환값**

* `ISharedDocEvents<S, T>[NAME]`: 등록된 이벤트 처리 함수

**예제**

```typescript
doc.on('op', (op, source) => {
    if (source !== doc.connection.id) {
        console.log('서버로부터 작업 수신:', op);
    }
});
```

### once

한 번만 실행되는 이벤트 리스너를 등록합니다.

```typescript
once<NAME extends keyof ISharedDocEvents<S, T>>(name: NAME, f: ISharedDocEvents<S, T>[NAME]): void;
```

**매개변수**

* `name` (`NAME`): 이벤트 이름
* `f` (`ISharedDocEvents<S, T>[NAME]`): 이벤트 처리 함수

**예제**

```typescript
doc.once('op', (op, source) => {
    console.log('op', op, source);
});
```

### off

특정 이벤트 리스너를 제거합니다.

```plaintext
off<NAME extends keyof ISharedDocEvents<S, T>>(name: NAME, f: ISharedDocEvents<S, T>[NAME]): void;
```

**매개변수**

* `name` (`NAME`): 이벤트 이름
* `f` (`ISharedDocEvents<S, T>[NAME]`): 제거할 이벤트 처리 함수

## UI 컴포넌트와의 연동

다음 그림은 동시 작업 처리 과정을 보여줍니다.
![sharedoc_class.6c68f4.png](https://gcdocumentsitekrblob.blob.core.windows.net/document-site-files/images/36b63360-fb01-457c-a448-c3ce32aaf454/sharedoc_class.6c68f4-20260107.d387ea.png)

```typescript
// UI 컴포넌트 초기화. xxx.uiComponent는 가상의 예시이며,
// 실제로는 Quill 등의 실제 UI 컴포넌트로 대체해야 합니다.
const uiComponent = new xxx.uiComponent();

// 문서 구독
doc.subscribe().then(async () => {
    // 문서가 존재하지 않으면 생성
    if (!doc.type) {
        try {
            await doc.create('Hello', textType.uri, {});
            console.log('성공적으로 생성됨:', doc.data);
        } catch (error) {
            console.error('생성 실패:', error);
            return;
        }
    }

    uiComponent.setText(doc.data);

    // 작업 수신
    doc.on('op', (op, source) => {
        if (source === doc.connection.id) {
            return;
        }
        console.log('작업 수신:', op, '현재 데이터:', doc.data);

        uiComponent.applyOp(op.pos, op.text); // 점진적 업데이트 권장
        // 또는 uiComponent.setText(doc.data); // 전체 업데이트
    });

    // 복원 이벤트 수신 시 UI 동기화
    doc.on('restore', (targetVersion) => {
        console.log(`문서가 버전 ${targetVersion}으로 복원됨`);
        uiComponent.setText(doc.data); // 스냅샷과 일치하도록 전체 업데이트
    });

    // UI에서 발생한 작업을 서버로 제출
    uiComponent.on('op', async (op) => {
        await doc.submitOp(op, { source: doc.connection.id });
    });
});
```

실시간 동시 작업 텍스트 편집기를 직접 만들어 보세요:
[튜토리얼: 실시간 동시 작업 텍스트 편집기](/spreadjs/docs/v19/spreadjs-collaboration-server/collaboration-framework/js-collaboration-ot/tutorial-real-time-collaborative-text-editor)