# 빠른 시작

> 두 브라우저에서 공동 편집을 실행한 뒤 최소 Client, Transport, Endpoint, Service, Adapter 구성을 애플리케이션으로 옮깁니다.

- Human documentation: [https://docs.univer.ai/ko-KR/server/collaboration/quick-start](https://docs.univer.ai/ko-KR/server/collaboration/quick-start)

- Agent Markdown: [https://docs.univer.ai/ko-KR/server/collaboration/quick-start.md](https://docs.univer.ai/ko-KR/server/collaboration/quick-start.md)

- Requested language: `ko-KR`

- Content language: `ko-KR`

- Documentation version: `1.0.4`

- Source: [collaboration/quick-start.ko-KR.mdx](https://github.com/dream-num/documentation/blob/dev/content/server/collaboration/quick-start.ko-KR.mdx)

---

이 페이지는 두 경로로 진행합니다. 먼저 공식 예제를 실행하여 두 브라우저에서 전체 공동 편집 흐름을 검증합니다. 그다음 최소 Server와 Web 구성을 읽고 자신의 Univer 애플리케이션에 적용합니다.

시작 전에 [환경 및 버전 요구 사항](https://docs.univer.ai/ko-KR/server/requirements.md)을 충족하세요. 모든 `@univerjs/*`와 `@univerjs-pro/*` 패키지는 같은 호환 릴리스 집합으로 고정해야 합니다.

## 경로 1: 공식 예제 실행

### 실행 전 준비

저장소는 **Node.js 24+**, **pnpm 10.32.1**을 요구합니다. `node --version`, `pnpm --version`을 확인하고 잠금 파일을 유지하세요. 모든 `pnpm example:*` 명령은 저장소 루트에서 실행합니다. 이 명령은 프런트엔드와 서버 빌드 및 타입 검사 후 서버를 시작하며 핫 리로드 서버가 아닙니다. 소스를 수정하면 중지 후 다시 실행하세요.

클라이언트 라이선스가 있다면 **빌드 전에** 셸에서 `UNIVER_LICENSE`를 설정하세요. `vite.config.ts`가 브라우저 번들에 삽입합니다. 이미 빌드된 서버를 시작할 때만 설정하면 반영되지 않습니다. [라이선스 설정](https://docs.univer.ai/ko-KR/server/license.md)을 참고하세요.

SQLite 예제는 설치 시 `better-sqlite3`를 빌드하므로 `node-gyp`, Python, C/C++ 도구가 필요합니다. `node-gyp: command not found`가 나오면 개발 환경에 `node-gyp`를 설치하고 예제 실행에 사용할 동일한 Node.js 버전으로 의존성을 다시 설치하세요.

```bash
git clone https://github.com/dream-num/univer-collaboration-examples.git
cd univer-collaboration-examples
pnpm install --frozen-lockfile
pnpm example:quick-start
```

다음을 여세요.

```text
http://127.0.0.1:3010/?unit=quick-start-sheet&type=2
```

### 실시간 공동 편집 확인

1. 한 브라우저 창에서 전체 URL을 여세요.
2. 다른 브라우저 프로필이나 시크릿 창에서도 여세요.
3. 어느 쪽 Sheet에서든 셀을 변경하세요.
4. 다른 브라우저에 같은 변경이 나타나는지 확인하세요.

서버가 두 온라인 Session을 생성하도록 독립된 브라우저 컨텍스트를 사용하세요. 같은 페이지에서 변경을 보는 것만으로 Room, ACK, 브로드캐스트 경로를 검증할 수는 없습니다.

### 성공으로 확인되는 내용

```text
Univer Collaboration Client
  → Node Transport
  → UniverCollabEndpoint
  → UniverCollabService
  → MemoryDatabaseAdapter
```

두 브라우저의 동기화는 HTTP로 Unit을 로드하고 일회용 Session Ticket으로 WebSocket Session을 연 다음 같은 Room에 참여했음을 의미합니다. Service는 OT를 수행하고 새 리비전을 확정해 Adapter로 저장하며 Endpoint는 이를 다른 구성원에게 전파합니다.

## 경로 2: 애플리케이션에 통합

다음 코드는 Server와 Web의 최소 구성을 보여 줍니다. 전체 애플리케이션 구조는 공식 빠른 시작을 참고하세요.

* [server/main.ts](https://github.com/dream-num/univer-collaboration-examples/blob/main/examples/quick-start/server/main.ts)
* [web/main.ts](https://github.com/dream-num/univer-collaboration-examples/blob/main/examples/quick-start/web/main.ts)
* [package.json](https://github.com/dream-num/univer-collaboration-examples/blob/main/examples/quick-start/package.json)

기존 Univer Web 애플리케이션이 있으면 Runtime, 프리셋, UI를 유지하고 아래 Collaboration Client 설정과 Server만 추가하세요. 빈 프로젝트라면 빠른 시작 디렉터리의 `index.html`, `vite.config.ts`, 스타일을 애플리케이션 틀로 복사하세요.

### 실행 가능한 파일을 기준으로 이전

`examples/quick-start`를 복사하고 `package.json`, `index.html`, `vite.config.ts`, `web/styles.css`, `web/main.ts`, `server/main.ts`를 유지하세요. Express는 작업 디렉터리 기준으로 `dist/web`을 읽으므로 예제 디렉터리에서 build와 start를 실행합니다. Vite 라이선스 정의와 `#app` 높이도 유지하세요. 아래 코드는 조립 과정을 설명하며 완전한 프로젝트는 이 파일들에서 시작합니다.

예제 페이지와 `/universer-api`는 같은 출처를 사용합니다. 별도 프런트엔드를 사용하면 HTTP와 WebSocket Upgrade를 프록시하거나 클라이언트의 다섯 URL을 함께 변경하세요. `unit`은 백엔드가 만든 ID와 같아야 하고 `type=2`는 Sheets입니다. URL 매개변수만으로 문서를 만들지는 않습니다.

### 1. 호환되는 동일 버전 패키지 집합 설치

서버에는 Transport, Endpoint, Service, Database Adapter 하나가 필요하고 브라우저에는 Collaboration Client가 필요합니다. 필요한 패키지를 설치한 뒤 모든 Univer 패키지를 정확히 같은 버전으로 고정하세요.

```bash
pnpm add \
  @univerjs-pro/collaboration@1.0.0 \
  @univerjs-pro/collaboration-client@1.0.0 \
  @univerjs-pro/collaboration-client-ui@1.0.0 \
  @univerjs-pro/collaboration-database-memory@1.0.0 \
  @univerjs-pro/collaboration-endpoint@1.0.0 \
  @univerjs-pro/collaboration-service@1.0.0 \
  @univerjs-pro/collaboration-transport-node@1.0.0 \
  @univerjs-pro/license@1.0.0 \
  @univerjs/core@1.0.0 \
  @univerjs/preset-sheets-core@1.0.0 \
  @univerjs/presets@1.0.0 \
  @univerjs/protocol@1.0.0 \
  express react react-dom rxjs
```

현재 패키지 구성과 정확한 버전은 실행 가능한 공식 예제의 매니페스트를 기준으로 합니다.

### 2. Service, Endpoint, 초기 Unit 생성

`UniverCollabService`는 확정 상태를 관리하는 공동 편집 핵심입니다. Endpoint는 브라우저 프로토콜을 Service에 연결하고 Memory Adapter는 스냅샷, 변경 집합, 리비전을 임시 저장합니다.

```ts
import { createServer } from "node:http";
import express from "express";
import type { IWorkbookData } from "@univerjs/core";
import { LocaleType } from "@univerjs/core";
import { MemoryDatabaseAdapter } from "@univerjs-pro/collaboration-database-memory";
import { UniverCollabEndpoint } from "@univerjs-pro/collaboration-endpoint";
import { UniverCollabService } from "@univerjs-pro/collaboration-service";
import { createNodeTransport } from "@univerjs-pro/collaboration-transport-node";
import { ErrorCode, UniverType } from "@univerjs/protocol";

const UNIT_ID = "quick-start-sheet";
const unitData: IWorkbookData = {
  id: UNIT_ID,
  rev: 1,
  name: "Quick Start Sheet",
  appVersion: "",
  locale: LocaleType.EN_US,
  sheetOrder: ["sheet-1"],
  sheets: {
    "sheet-1": {
      id: "sheet-1",
      name: "Sheet 1",
      rowCount: 100,
      columnCount: 26,
      cellData: {},
    },
  },
  styles: {},
  resources: [],
};

const database = new MemoryDatabaseAdapter();
const service = new UniverCollabService({ dbAdapter: database });
const endpoint = new UniverCollabEndpoint(service);
const transport = createNodeTransport();

transport.use(async (context, next) => {
  context.userID = "demo-user";
  await next();
});
transport.register(endpoint);

await service.createUnitFromData(
  { type: UniverType.UNIVER_SHEET, data: unitData },
  { userID: "demo-user" },
);
```

고정 `demo-user`는 신뢰할 수 있는 신원이 Transport에서 Endpoint와 Service로 전달되는 예입니다. 운영 애플리케이션은 `transport.use()` 안에서 쿠키, Bearer 토큰 또는 세션을 검증한 후 안정적인 업무용 `userID`를 설정해야 합니다.

### 3. 권한 부여, HTTP, WebSocket 진입점 연결

현재 Collaboration Client는 권한 부여 프로토콜을 조회합니다. 빠른 시작은 해당 경로에서 항상 `allowed: true`를 반환하고 Transport를 애플리케이션의 HTTP 서버에 연결합니다.

```ts
const app = express();

app.post("/universer-api/authz/-/object/-/batch_allowed", express.json(), (request, response) => {
  const body = request.body as {
    requests: Array<{ unitID: string; objectID: string; actions: unknown[] }>;
  };
  response.json({
    error: { code: ErrorCode.OK, message: "" },
    objectActions: body.requests.map((item) => ({
      unitID: item.unitID,
      objectID: item.objectID,
      actions: item.actions.map((action) => ({ action, allowed: true })),
    })),
  });
});

app.use(express.static("dist/web"));

const server = createServer(app);
transport.attach(server);
server.listen(3010, "127.0.0.1");
```

항상 허용하는 설정은 학습용 단순화이며 보안 경계가 아닙니다. 실제 애플리케이션은 HTTP 읽기, 실시간 JOIN, 변경 집합 제출, Unit 수명 주기 작업을 보호해야 합니다. 전체 범위는 [신원 및 권한 부여](https://docs.univer.ai/ko-KR/server/collaboration/identity-and-authorization.md)를 참고하세요.

### 4. 브라우저 Runtime에 Collaboration Client 등록

일반 Web SDK와 프리셋을 유지한 채 공동 편집 플러그인과 프로토콜 URL을 추가하세요.

```ts
import { LocaleType, LogLevel } from "@univerjs/core";
import { UniverCollaborationPlugin } from "@univerjs-pro/collaboration";
import { UniverCollaborationClientPlugin } from "@univerjs-pro/collaboration-client";
import CollaborationClientEnUS from "@univerjs-pro/collaboration-client/locale/en-US";
import {
  BrowserCollaborationSocketService,
  UniverCollaborationClientUIPlugin,
} from "@univerjs-pro/collaboration-client-ui";
import CollaborationClientUIEnUS from "@univerjs-pro/collaboration-client-ui/locale/en-US";
import { UniverLicensePlugin } from "@univerjs-pro/license";
import { UniverSheetsCorePreset } from "@univerjs/preset-sheets-core";
import UniverPresetSheetsCoreEnUS from "@univerjs/preset-sheets-core/locales/en-US";
import { createUniver, defaultTheme, mergeLocales } from "@univerjs/presets";
import "@univerjs/preset-sheets-core/lib/index.css";
import "@univerjs-pro/collaboration-client-ui/lib/index.css";

const httpProtocol = location.protocol === "https:" ? "https" : "http";
const wsProtocol = location.protocol === "https:" ? "wss" : "ws";
const baseURL = `${httpProtocol}://${location.host}/universer-api`;

createUniver({
  locale: LocaleType.EN_US,
  locales: {
    [LocaleType.EN_US]: mergeLocales(
      UniverPresetSheetsCoreEnUS,
      CollaborationClientEnUS,
      CollaborationClientUIEnUS,
    ),
  },
  theme: defaultTheme,
  logLevel: LogLevel.WARN,
  collaboration: true,
  presets: [UniverSheetsCorePreset({ container: "app" })],
  plugins: [
    [UniverLicensePlugin, { license: import.meta.env.UNIVER_LICENSE || undefined }],
    UniverCollaborationPlugin,
    [
      UniverCollaborationClientPlugin,
      {
        socketService: BrowserCollaborationSocketService,
        sendChangesetTimeout: 200,
        authzUrl: `${baseURL}/authz`,
        snapshotServerUrl: `${baseURL}/snapshot`,
        collabSubmitChangesetUrl: `${baseURL}/comb`,
        collabWebSocketUrl: `${wsProtocol}://${location.host}/universer-api/comb/connect`,
        wsSessionTicketUrl: `${baseURL}/user/session-ticket`,
      },
    ],
    UniverCollaborationClientUIPlugin,
  ],
});
```

페이지에는 `id="app"` 요소가 필요하며 쿼리 매개변수로 Unit을 선택합니다.

```text
/?unit=quick-start-sheet&type=2
```

### 5. 학습용 설정을 애플리케이션 기능으로 교체

| 학습용 설정         | 교체 대상                                        |
| -------------- | -------------------------------------------- |
| 고정 `demo-user` | 애플리케이션 인증 Middleware 및 안정적인 사용자 ID           |
| 항상 허용하는 권한 검사  | 읽기, JOIN, 제출, 수명 주기를 포괄하는 서버 ACL             |
| 고정 Unit        | `createUnitFromData()`를 호출하는 생성 API 및 제품 레코드 |
| Memory Adapter | SQLite 또는 계약 테스트를 통과한 사용자 지정 영구 저장 Adapter   |

다음으로 [데이터베이스 어댑터](https://docs.univer.ai/ko-KR/server/collaboration/database-adapters.md)와 [신원 및 권한 부여](https://docs.univer.ai/ko-KR/server/collaboration/identity-and-authorization.md)를 완성하세요. 필요에 따라 [History, Thread Comment, Worktree, Exchange](https://docs.univer.ai/ko-KR/server/collaboration/extensions.md)를 추가하세요. 모든 실행 가능한 구성은 [예제 목록](https://docs.univer.ai/ko-KR/server/collaboration/examples.md)을 참고하세요.

## 첫 실행 문제 해결

| 증상           | 확인                                                                                 |
| ------------ | ---------------------------------------------------------------------------------- |
| 설치·빌드 실패     | Node.js 24+, 지정 pnpm, 동일 Univer 버전                                                 |
| 3010 사용 중    | 이전 예제 중지 또는 `PORT=3011` 설정 후 두 브라우저 URL 변경                                         |
| 빈 화면·리소스 누락  | 빌드 완료, 예제 디렉터리에서 시작, `#app` 높이                                                     |
| 편집 동기화 실패    | 같은 전체 URL, snapshot과 session-ticket 성공, `/universer-api/comb/connect` WebSocket 연결 |
| 재시작 후 데이터 소실 | Quick Start는 메모리 저장이므로 SQLite 예제로 진행                                               |
