# Operation (Op)

## Content

**Operation(Op)**은 클라이언트와 서버 간 통신의 핵심 개념입니다. 클라이언트는 문서에 대한 변경 사항을 설명하기 위해 Op를 제출하고, 서버는 이 Op를 처리·저장·동기화합니다. 이 문서에서는 다음 내용을 소개합니다.

* Op의 정의
* 클라이언트와 서버 간 Op의 차이
* 서버 측 추가 필드의 역할

## 정의

Op는 문서 상태에 대한 **단일 변경 사항**을 설명합니다. 일반적인 작업은 다음과 같습니다.

* **문서 콘텐츠 삽입 또는 수정**: 예를 들어, 문서의 특정 위치에 텍스트를 삽입
* **문서 생성**: 새 문서 초기화
* **문서 삭제**: 기존 문서 제거

Op의 정의는 클라이언트와 서버에서 다릅니다.

* **클라이언트 측 Op**: 삽입 위치와 텍스트 내용처럼 작업의 구체적인 콘텐츠를 설명
* **서버 측 Op**: 클라이언트 측 Op에 `src`, `seq`, `v`와 같은 추가 메타데이터를 포함하여 확장하며, 이는 작업의 고유 식별, 버전 관리, 불안정한 네트워크 환경에서의 중복 제출 감지에 사용됨

## 차이점

### 클라이언트 측 Op

클라이언트 측 Op는 사용자의 문서 수정 내용을 직접적으로 설명하며, 일반적으로 작업의 구체적인 콘텐츠만 포함합니다. 아래는 Op의 예시입니다.

>type=note
> 다음 예제의 Op는 설명을 단순화한 것입니다. 실제 환경에서는 문서 타입, 작업 복잡도, 구현 방식에 따라 Op의 구조와 내용이 달라질 수 있습니다.

**예제 1: 텍스트 삽입**
문서의 특정 위치에 텍스트를 삽입합니다.

```typescript
sharedDoc.submitOp({ pos: 1, text: 'hello' })
```

* `pos: 1`: 문서의 1번 위치에 콘텐츠를 삽입함을 의미
* `text: 'hello'`: 삽입되는 텍스트 내용이 "hello"임을 의미

**예제 2: 문서 생성**
새 문서를 초기화합니다.

```typescript
sharedDoc.create('Hi!', textType.uri);
```

* `'Hi!'`: 새 문서의 초기 콘텐츠
* `textType.uri`: 문서의 OT 타입(예: 텍스트 타입)

**예제 3: 문서 삭제**

```typescript
sharedDoc.del();
```

### 서버 측 Op

서버는 클라이언트로부터 Op를 수신한 후, 다음과 같은 메타데이터 필드를 추가하여 Op를 확장합니다.

* **src**: 작업의 **출처 식별자**로, 일반적으로 클라이언트를 구분하기 위한 고유 ID
* **seq**: 해당 클라이언트가 제출한 작업의 **시퀀스 번호**로, 작업 제출 순서를 나타냄 (`src`와 `seq`의 조합은 작업의 고유 식별자가 됨)
* **v**: 작업이 적용될 당시의 문서 **버전 번호**로, 버전 관리 및 충돌 해결에 사용됨

이 메타데이터 필드의 역할은 다음과 같습니다.

* **고유 식별**: `src`와 `seq`를 사용하여 불안정한 네트워크 환경에서의 중복 제출을 감지하고 동일 작업의 중복 적용을 방지
* **버전 관리**: `v`를 사용하여 작업이 올바른 순서로 적용되도록 보장하고, 동시 수정으로 인한 충돌을 처리

다음은 클라이언트 측 Op에 대응하여 서버에서 수신된 Op의 예시입니다.

**예제 1: 문서 생성(서버 측)**
클라이언트에서 제출된 문서 생성 작업은 서버에서 다음과 같이 나타납니다.

```typescript
documentServices.use('submit', async (context, next) => {
    console.log(context.request.op);
    // 출력: { src: '51pX43yjKUiMmSoHAAAB', seq: 1, v: 0, create: { type: 'text-type', data: 'Hi!' } }
    await next();
});
```

* `create: { type: 'text-type', data: 'Hi!' }`: 문서 생성을 위한 원본 작업 내용
* `src: '51pX43yjKUiMmSoHAAAB'`: 클라이언트의 고유 식별자
* `seq: 1`: 해당 클라이언트의 첫 번째 작업
* `v: 0`: 작업 적용 시점의 문서 버전 번호

**예제 2: 텍스트 삽입(서버 측)**
클라이언트에서 제출된 텍스트 삽입 작업은 서버에서 다음과 같이 나타납니다.

```typescript
documentServices.use('submit', async (context, next) => {
    console.log(context.request.op);
    // 출력: { src: '51pX43yjKUiMmSoHAAAB', seq: 2, v: 1, op: { pos: 1, text: 'hello'} }
    await next();
});
```

* `op: { pos: 1, text: 'hello' }`: 클라이언트가 제출한 원본 작업 내용
* `src`, `seq`, `v`: 앞선 예제와 동일하며, 식별 및 버전 관리에 사용됨

**예제 3: 문서 삭제(서버 측)**
클라이언트에서 제출된 문서 삭제 작업은 서버에서 다음과 같이 나타납니다.

```typescript
documentServices.use('submit', async (context, next) => {
    console.log(context.request.op);
    // 출력: { src: '51pX43yjKUiMmSoHAAAB', seq: 3, v: 2, del: true }
    await next();
});
```

* `del: true`: 문서 삭제를 의미하는 원본 작업 내용
* `src`, `seq`, `v`: 앞선 예제와 동일하며, 식별 및 버전 관리에 사용됨