공동 편집 통합

Univer 편집기를 공동 편집 서비스에 연결해 사용자들이 같은 문서를 편집하도록 합니다.

공동 편집은 브라우저 편집기를 공유 문서 서비스에 연결합니다. 예를 들어 두 사용자가 같은 스프레드시트를 열면 한 브라우저의 수정 내용이 다른 브라우저에도 나타납니다.

서버 통합으로 백엔드를 준비한 뒤 아래의 편집기와 문서 로드를 설정하세요. 협업 빠른 시작의 Server와 Web 코드를 함께 참고하세요.

100%

기존 편집기 연결

기존 Web SDK 편집기는 유지하세요. 빠른 시작의 브라우저 설정에 따라 공동 편집 플러그인을 추가하고 문서 로드, 변경 제출, WebSocket 주소를 설정하세요. 브라우저와 서버 패키지 버전을 호환되게 유지하세요.

예제의 고정 사용자와 기본 권한은 시연용입니다. 실제 요청에는 로그인 자격 증명을 포함하여 백엔드가 신원과 문서 접근을 검증하도록 하세요. 라이선스는 라이선스 설정을 참고하세요.

같은 문서 생성 및 열기

생성과 열기는 별개 작업입니다.

  1. 사용자가 문서를 생성하면 백엔드가 저장하고 ID를 반환합니다.
  2. 브라우저가 해당 ID를 로드합니다. 다시 열거나 다른 사용자와 공유할 때도 같은 ID를 사용합니다.

API의 unitId가 이 문서 ID입니다. 방문할 때마다 새로운 로컬 빈 문서를 만들지 마세요.

문서를 로드하기 전에 현재 사용자를 설정하세요. 현재 사용자는 공동 편집의 신원과 로컬 오프라인 캐시의 소유자를 결정합니다. 설정 방법은 신원 확인과 권한 부여를 참고하세요.

예를 들어 Sheets와 공동 편집 플러그인 등록 후 서버 스프레드시트를 로드합니다.

TypeScript
import { UserManagerService } from '@univerjs/core'import '@univerjs-pro/collaboration-client/facade'univer.__getInjector().get(UserManagerService).setCurrentUser({ userID, name, avatar })const workbook = await univerAPI.getCollaboration().loadSheetAsync('your-document-id')if (!workbook) throw new Error('Document could not be loaded')

제품별 로드는 Sheets, Docs, Slides, Boards, Bases, PDFs 가이드를 참고하세요. 제품과 대상 백엔드 릴리스의 지원 여부를 확인하세요.

동기화, 저장 및 권한 확인

일반 창과 시크릿 창처럼 독립된 두 브라우저 세션에서 같은 문서를 여세요. 한쪽에서 수정하고 다른 쪽을 확인하세요. 새로 고침, 재연결, 서버 재시작 후에도 내용을 검증하세요.

편집자, 보기 전용 사용자, 권한이 없는 사용자로 테스트하세요. 읽기 전용 UI 설정은 페이지 상호작용만 제어하며, 서버는 여전히 허용되지 않은 읽기와 변경을 거부해야 합니다.

문서는 로드되지만 수정이 동기화되지 않으면 WebSocket 연결을 확인하세요. 재시작 후 내용이 사라지면 백엔드 저장소를 확인하세요. 설정은 서버 통합을 참고하세요.

파일 교환, 댓글 또는 기록 추가

가져온 파일을 공동 편집하려면 변환된 데이터로 공동 편집 문서를 생성하세요. 파일 교환 통합을 참고하세요. 댓글과 기록에는 각각 플러그인, 서비스, 권한이 필요합니다. Office 확장 모듈을 따르세요.

기록 패널 설정은 Sheets, Docs, Slides, Boards, Bases를 참고하세요. PDFs의 현재 범위는 PDFs 기록에서 확인하세요.

동기화 상태와 재전송

공동 편집 Facade를 가져온 뒤 구독하세요. CollaborationStatusChanged는 구독 시 이미 공동 편집 중인 문서의 현재 상태를 알리고 이후 동일 상태를 연속으로 중복 알리지 않습니다. hasWritePending(unitId)는 전송 대기, 확인 대기, 오프라인 변경을 포함합니다. ID를 생략하면 포커스된 문서를 확인합니다. 연결되었다고 저장이 완료된 것은 아닙니다.

TypeScript
import '@univerjs-pro/collaboration-client/facade'const collaboration = univerAPI.getCollaboration()const statusSubscription = univerAPI.addEvent(univerAPI.Event.CollaborationStatusChanged, (event) => {  console.info(event.unitId, event.status, collaboration.hasWritePending(event.unitId))})const resendSubscription = univerAPI.addEvent(univerAPI.Event.CollaborationChangesetResend, (event) => {  console.info(event.unitId, event.reason, event.attempt, event.unsyncedMutationCount, event.nextDelayMs)})

CollaborationChangesetResend는 첫 제출이 아닌 재전송 시 발생합니다. 이유는 ack_timeout, request_failed, license_editing_connections_exceeded, should_retry, reconnect입니다. attempt, elapsedMs, unsyncedMutationCount, nextDelayMs로 저장/재시도 상태를 표시할 수 있습니다. 편집기를 제거할 때 구독을 해제하세요.

request_failed는 네트워크 오류나 HTTP 408, 429, 5xx 등 재시도 가능한 요청 실패를 뜻합니다. license_editing_connections_exceeded는 라이선스가 허용하는 편집 연결이 모두 사용 중이어서 서버가 재전송을 요청했음을 뜻합니다.

일괄 전송 지연과 확인 제한 시간은 다릅니다. 플러그인 기본값은 sendChangesetTimeout: 2000, changesetAckTimeout: 20000, maxChangesetAckTimeout: 120000(밀리초)입니다. 제출 요청에도 확인 제한 시간이 적용되며 미확인 변경은 최대값까지 지수 백오프로 재전송됩니다. 뒤의 두 값을 같게 하면 간격이 일정합니다.

TypeScript
import { UniverCollaborationClientPlugin } from '@univerjs-pro/collaboration-client'import { BrowserCollaborationSocketService } from '@univerjs-pro/collaboration-client-ui'univer.registerPlugin(UniverCollaborationClientPlugin, {  socketService: BrowserCollaborationSocketService,  sendChangesetTimeout: 200,  changesetAckTimeout: 20_000,  maxChangesetAckTimeout: 120_000,})

기존 클라이언트 등록에 옵션을 추가하고 socket 및 엔드포인트를 유지하세요. Sheets와 Docs 공동 편집 프리셋은 일괄 전송 지연 200 ms를 사용하고 확인 제한 시간 옵션을 노출하지 않습니다. 시간을 변경하려면 플러그인 모드를 사용하세요.

애플리케이션에서 충돌 처리

CollaborationConflict는 문서가 충돌 상태가 된 후 오프라인 캐시 정리를 시도한 다음 한 번 발생합니다. 문서 로드 전에 구독하세요. reason은 transform_failed, apply_failed, changeset_rejected, license_unit_type_rejected, permission_rejected, remote_revert이며 가능한 경우 message와 revert가 세부 정보를 제공합니다.

license_unit_type_rejected는 서버 라이선스가 해당 문서 유형의 공동 편집을 지원하지 않음을 뜻합니다.

TypeScript
import type { IEventParamConfig } from '@univerjs/core/facade'import '@univerjs-pro/collaboration-client/facade'const conflicts = new Map<string, IEventParamConfig['CollaborationConflict']>()const conflictSubscription = univerAPI.addEvent(univerAPI.Event.CollaborationConflict, (event) => {  conflicts.set(event.unitId, event)})

예제는 복구 화면을 위해 이벤트를 보관합니다. Map은 메모리에만 존재합니다. 새로고침 전에 앱에서 localChanges를 저장하거나 내보내세요. 정리된 캐시는 나중에 복구할 수 없으므로 이벤트에서 보관해야 합니다. awaitingChangeset은 이미 서버에 적용되었을 수 있으므로 그대로 재실행하지 마세요.

cacheCleared: false이면 새로고침 시 이전 캐시가 재실행되므로 먼저 정리 문제를 해결하세요. 캐시 정리는 미동기화 변경이 저장되었다는 뜻이 아닙니다. permission_rejected는 권한도 해결해야 하며 새로고침이 권한을 부여하지 않습니다.

기본 UI는 이유별 알림을 표시하고 캐시 정리 성공 후 새로고침, 실패 시 재시도를 제공합니다. 앱이 복구 흐름을 관리하려면 기존 초기화에 enableDefaultConflictUI: false를 설정하고 이벤트를 처리하세요.

TypeScript
import { UniverCollaborationClientUIPlugin } from '@univerjs-pro/collaboration-client-ui'univer.registerPlugin(UniverCollaborationClientUIPlugin, { enableDefaultConflictUI: false })

공동 편집 프리셋을 기존 createUniver({ presets: [...] })에서 편집기 프리셋과 조합하고 엔드포인트 및 기록 설정을 유지하세요. 이벤트 매개변수와 클라이언트 설정을 참고하세요.

서버 거부 이유와 라이선스 알림

서버가 수정을 거부하면 CollaborationConflict.message에 서버가 제공한 이유가 담깁니다. 복구는 번역된 메시지를 파싱하지 말고 reason으로 분기하세요. license_unit_type_rejected는 문서 유형을 허용하는 서버 라이선스가 필요합니다. license_editing_connections_exceeded는 재전송 신호이며 변경은 미확인 상태로 재시도됩니다. hasWritePending(unitId)가 false가 되거나 앱이 수정을 보관할 때까지 편집기를 열어 두세요.

기본 UI는 편집 연결 용량 초과를 알리며, 최초 전송 후 20초 이상 지난 재전송에서는 저장 시간 초과도 알립니다. 문서가 확인 대기 상태를 벗어나거나 폐기되면 알림이 제거됩니다. 도메인 거부에도 별도 알림이 있습니다. enableDefaultConflictUI: false는 충돌 복구 알림만 끄며 대기·도메인 알림은 끄지 않습니다.

이 가이드는 어떠셨나요?

© 2026 DreamNum Co., Ltd.