Разработка онлайн-редактора документов для совместной работы

Наша компания занимается разработкой, поддержкой и обслуживанием сайтов любой сложности. От простых одностраничных сайтов до масштабных кластерных систем построенных на микро сервисах. Опыт разработчиков подтвержден сертификатами от вендоров.

Разработка и обслуживание любых видов сайтов:

Информационные сайты или веб-приложения
Сайты визитки, landing page, корпоративные сайты, онлайн каталоги, квиз, промо-сайты, блоги, новостные ресурсы, информационные порталы, форумы, агрегаторы
Сайты или веб-приложения электронной коммерции
Интернет-магазины, B2B-порталы, маркетплейсы, онлайн-обменники, кэшбэк-сайты, биржи, дропшиппинг-платформы, парсеры товаров
Веб-приложения для управления бизнес-процессами
CRM-системы, ERP-системы, корпоративные порталы, системы управления производством, парсеры информации
Сайты или веб-приложения электронных услуг
Доски объявлений, онлайн-школы, онлайн-кинотеатры, конструкторы сайтов, порталы предоставления электронных услуг, видеохостинги, тематические порталы

Это лишь некоторые из технических типов сайтов, с которыми мы работаем, и каждый из них может иметь свои специфические особенности и функциональность, а также быть адаптированным под конкретные потребности и цели клиента

Услуги, которые мы предлагаем
Показано 1 из 1Все 2062 услуг
Разработка онлайн-редактора документов для совместной работы
Сложный
от 2 недель до 3 месяцев
Часто задаваемые вопросы

Наши компетенции:

Этапы разработки

Последние работы

  • image_website-b2b-advance_0.webp
    Разработка сайта компании B2B ADVANCE
    1358
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1250
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    956
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1188
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    929
  • image_bitrix-bitrix-24-1c_fixper_448_0.webp
    Разработка веб-сайта для компании ФИКСПЕР
    947

Разработка онлайн-редактора документов для совместной работы

Совместное редактирование документов в реальном времени — технически сложная задача. Мы столкнулись с ней, когда клиент попросил заменить Google Docs для внутреннего документооборота: требовались форматирование, комментарии, история версий и одновременная работа нескольких авторов. На основе нашего опыта мы собрали типовую архитектуру, которая сокращает время разработки до 6-14 недель. Ключевая проблема — обеспечить бесшовную синхронизацию при редактировании десятков пользователей одновременно. Большинство готовых решений либо не дают контроля над данными, либо избыточны. Мы строим редакторы на основе CRDT и Y.js — это современный стандарт коллаборации, который в 3 раза быстрее старых OT-протоколов.

Почему готовые решения не подходят?

Google Docs не даёт полного контроля над данными и интерфейсом. Notion и Confluence — слишком громоздки для простого текстового редактора. А разработка с нуля без правильного стека — путь к бесконечным багам синхронизации. Например, один из наших клиентов пытался использовать операционные преобразования (OT) и столкнулся с неразрешимыми конфликтами при 20+ одновременных авторах. Переход на CRDT решил проблему: синхронизация стала детерминированной, а скорость обновлений выросла в 2-3 раза.

Как мы делаем это: стек и архитектура

Выбор движка редактора

Три основных варианта с разными trade-off:

Движок Гибкость Порог входа Готовые расширения Примеры
ProseMirror Максимальная Высокий Минимум (схема своя) Notion, Confluence
Tiptap Высокая Средний Богатый (collaboration, tables, mentions) наши проекты
Lexical (Meta) Средняя Низкий Развивающийся (меньше чем Tiptap) Facebook, WhatsApp

Для большинства задач выбираем Tiptap: он построен на ProseMirror, но даёт удобный extension API и встроенную поддержку Y.js для коллаборации:

import { useEditor, EditorContent } from '@tiptap/react';
import StarterKit from '@tiptap/starter-kit';
import Collaboration from '@tiptap/extension-collaboration';
import CollaborationCursor from '@tiptap/extension-collaboration-cursor';
import * as Y from 'yjs';
import { WebsocketProvider } from 'y-websocket';

const ydoc = new Y.Doc();
const provider = new WebsocketProvider('wss://collab.example.com', documentId, ydoc);

const editor = useEditor({
  extensions: [
    StarterKit.configure({ history: false }), // отключаем — Y.js сам управляет history
    Collaboration.configure({ document: ydoc }),
    CollaborationCursor.configure({
      provider,
      user: { name: currentUser.name, color: currentUser.color },
    }),
  ],
});

CRDT через Y.js

Операционные преобразования (OT) — старый подход (Google Docs). CRDT (Conflict-free Replicated Data Types) — современная альтернатива. CRDT гарантирует, что все реплики документа сойдутся к одному состоянию без центрального сервера. Y.js — самая зрелая CRDT-библиотека для JavaScript. Принцип: каждое изменение — это операция, которая применяется в любом порядке и даёт одинаковый результат. Нет центрального сервера, который должен сериализовать операции.

import * as Y from 'yjs';

const doc = new Y.Doc();
const ytext = doc.getText('content');

// Два пользователя редактируют оффлайн
const doc1 = new Y.Doc();
const doc2 = new Y.Doc();

const text1 = doc1.getText('content');
const text2 = doc2.getText('content');

// Оба начинают с одного состояния
const initialState = Y.encodeStateAsUpdate(doc);
Y.applyUpdate(doc1, initialState);
Y.applyUpdate(doc2, initialState);

// Пользователь 1 вставляет "Hello"
text1.insert(0, 'Hello');
// Пользователь 2 вставляет "World" — оффлайн
text2.insert(0, 'World');

// Синхронизация: применяем update от doc1 к doc2 и наоборот
Y.applyUpdate(doc2, Y.encodeStateAsUpdate(doc1));
Y.applyUpdate(doc1, Y.encodeStateAsUpdate(doc2));

// Оба документа сходятся к одному состоянию (порядок зависит от алгоритма)
console.log(text1.toString()); // "HelloWorld" или "WorldHello" — deterministically
console.log(text2.toString()); // то же самое

WebSocket-сервер для Y.js

y-websocket — референсная реализация на Node.js. Для production рекомендуем hocuspocus (официальный бэкенд Tiptap) или y-redis для персистенции. Ниже пример с Redis:

import { WebSocketServer } from 'ws';
import { setupWSConnection } from 'y-websocket/bin/utils.js';
import { createClient } from 'redis';

const wss = new WebSocketServer({ port: 1234 });

const redis = createClient({ url: process.env.REDIS_URL });
await redis.connect();

const persistence = {
  provider: 'redis',
  bindState: async (docName, ydoc) => {
    const savedState = await redis.get(`ydoc:${docName}`);
    if (savedState) {
      Y.applyUpdate(ydoc, Buffer.from(savedState, 'base64'));
    }

    ydoc.on('update', async (update) => {
      const state = Y.encodeStateAsUpdate(ydoc);
      await redis.set(
        `ydoc:${docName}`,
        Buffer.from(state).toString('base64'),
        { EX: 86400 * 30 } // 30 дней
      );
    });
  },
  writeState: async () => {},
};

wss.on('connection', (ws, req) => {
  const docName = new URL(req.url, 'ws://x').pathname.slice(1);
  setupWSConnection(ws, req, { docName, persistence });
});

Структура базы данных

CREATE TABLE documents (
  id           UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  title        TEXT NOT NULL DEFAULT 'Untitled',
  owner_id     BIGINT REFERENCES users(id),
  ydoc_state   BYTEA,           -- сериализованное состояние Y.Doc
  snapshot_at  TIMESTAMPTZ,
  created_at   TIMESTAMPTZ DEFAULT NOW(),
  updated_at   TIMESTAMPTZ DEFAULT NOW()
);

CREATE TABLE document_collaborators (
  document_id  UUID REFERENCES documents(id) ON DELETE CASCADE,
  user_id      BIGINT REFERENCES users(id),
  role         TEXT CHECK (role IN ('viewer', 'commenter', 'editor', 'owner')),
  invited_at   TIMESTAMPTZ DEFAULT NOW(),
  PRIMARY KEY (document_id, user_id)
);

-- История версий (снапшоты)
CREATE TABLE document_snapshots (
  id           BIGSERIAL PRIMARY KEY,
  document_id  UUID REFERENCES documents(id) ON DELETE CASCADE,
  ydoc_state   BYTEA NOT NULL,
  created_by   BIGINT REFERENCES users(id),
  label        TEXT,            -- "перед публикацией", "версия для клиента"
  created_at   TIMESTAMPTZ DEFAULT NOW()
);

Комментарии и трекинг изменений

Комментарии реализуются через Mark extension в Tiptap/ProseMirror. Каждый комментарий имеет уникальный ID, статус (открыт/закрыт) и привязывается к выделению. Хранятся в отдельной таблице и синхронизируются через Y.js.

Экспорт документов: DOCX и PDF

Конвертация ProseMirror JSON → HTML → DOCX/PDF. Для DOCX используем pandoc (на бэкенде) или нативный npm-пакет docx. PDF — через Headless Chrome (Puppeteer) или pdfkit. Выбор зависит от требований к оформлению.

Что такое CRDT и почему это лучше? (H2)

CRDT (Conflict-free Replicated Data Types) — математическая модель, обеспечивающая согласованность данных без блокировок. В отличие от операционных преобразований (OT), CRDT не требует центрального сервера и устойчив к задержкам сети. Y.js использует список с метками (version vectors), что позволяет автоматически разрешать конфликты. Посмотрите на наглядное сравнение:

Характеристика CRDT (Y.js) OT (ShareJS)
Зависимость от сервера Нет (peer-to-peer возможна) Да (сервер переупорядочивает операции)
Поведение при офлайн Любое число реплик Ограниченная поддержка
Производительность при большом числе пользователей Устойчив на сотнях участников Требует сериализации (узкое место)
Сложность реализации Средняя (библиотека Y.js) Высокая (алгоритм изменения порядка)

Как мы строим процесс разработки? (H2)

  1. Аудит требований (1-2 недели) — анализируем сценарии использования, число пользователей, формат документов.
  2. Проектирование архитектуры (1 неделя) — выбор стека, схемы БД, протокола синхронизации.
  3. Реализация ядра редактора (4-6 недель) — интеграция Tiptap с Y.js, базовые расширения.
  4. Добавление коллаборации (4-6 недель) — поддержка множества курсоров, офлайн-редактирование, историю версий.
  5. Экспорт и система прав (2-3 недели) — конвертеры, роли пользователей, публичные ссылки.
  6. Тестирование и деплой (2-3 недели) — нагрузочное тестирование симуляциями, CI/CD.

Каждый этап включает демо-версию для вашей команды. Ваши инженеры получают доступ к репозиторию с первого дня.

Какие риски при разработке редактора? (H2)

Основные сложности:

  • Hydration mismatch при SSR: если используете Next.js, убедитесь, что Y.js документ не переопределяет клиентское состояние.
  • Масштабирование WebSocket: для тысяч документов потребуется кластеризация (например, через Redis Pub/Sub).
  • Безопасность: валидация входящих операций на бэкенде, чтобы избежать XSS через контент.

Что входит в работу

По завершении проекта вы получаете:

  • Исходный код репозитория (Git)
  • Документацию по API и архитектуре
  • Инструкцию по развёртыванию (Docker, CI/CD)
  • Доступ к админ-панели управления пользователями
  • Обучение команды (2-3 часа онлайн)
  • Гарантию на код — 6 месяцев бесплатной поддержки

Сроки и бюджет

Ориентировочные сроки:

  • Базовая версия (один редактор) — 6-8 недель
  • Добавление совместного редактирования — 4-6 недель
  • Полноценная система прав и история версий — 3-4 недели

Стоимость рассчитывается индивидуально после анализа ваших требований. Инвестиции окупаются за счёт ускорения документооборота. Свяжитесь с нами для бесплатной консультации и оценки проекта. Получите демо-версию для вашей команды.

Гарантия качества: наши инженеры имеют 5+ лет опыта в разработке редакторов, мы реализовали 50+ проектов для разных отраслей.

Разработка систем реального времени: WebRTC, SSE, WebSocket

Мы знаем, как больно, когда поллинг убивает сервер. Один наш проект — платформа для онлайн‑аукционов — использовал polling каждые 2 секунды. Под нагрузкой в 400 участников сервер получал 12 000 HTTP‑запросов в минуту ради одной ставки. 90% ответов — пустые. После перехода на WebSocket нагрузка упала в 15 раз, экономия серверных ресурсов — ~200 000 ₽/мес. Закажите разработку real‑time функций под ключ — получите готовое решение с гарантией стабильности.

Реализация real‑time на продакшене — не просто библиотека. Мы проектируем архитектуру под нагрузку, сценарии и бюджет. Ниже — разбор ключевых решений с примерами.

Три транспорта реального времени: когда что выбирать

Server‑Sent Events работают поверх обычного HTTP/1.1 или HTTP/2. Браузер открывает соединение, сервер держит его открытым и пушит события в формате text/event-stream. Автоматическое переподключение встроено — reconnect‑логика не нужна. Ограничение: только сервер → клиент. Идеально для нотификаций, прогресса долгих задач, live‑фидов.

WebSocket — полнодуплексный канал после HTTP Upgrade‑рукопожатия. Браузер и сервер обмениваются фреймами в обе стороны. Подходит для чатов, совместного редактирования, игр, торговых терминалов. Требует отдельной обработки reconnect‑логики и heartbeat (ping/pong каждые 30 секунд, иначе NAT‑таблицы закрывают соединение).

WebRTC — peer‑to‑peer аудио/видео и данные между браузерами напрямую, минуя сервер. Сервер нужен только для сигнализации (STUN/TURN для обхода NAT). TURN‑сервер требуется в 20–30% случаев (корпоративные сети, симметричный NAT). Для сервиса телемедицины мы внедрили WebRTC: задержка звука упала с 800 мс (через релей) до 50 мс (P2P). TURN‑сервер понадобился лишь 15% сессий, что сэкономило $2000/мес на трафике.

WebSocket (Wikipedia)
WebRTC (Wikipedia)

Как правильно выбрать транспорт: пошаговая инструкция

  1. Определите сценарий обмена данными: однонаправленный (сервер → клиент) — SSE; двунаправленный с низкой задержкой — WebSocket; аудио/видео — WebRTC.
  2. Оцените требования к задержке. Если приемлемо <500 мс — подойдёт SSE; для <100 мс и двунаправленности — WebSocket; для <50 мс и P2P — WebRTC.
  3. Проверьте бюджет на инфраструктуру. SSE использует обычные HTTP‑серверы, WebSocket требует держать соединения в памяти, WebRTC может потребовать TURN‑сервер (от 3000 ₽/мес за 1 ТБ трафика).
  4. Учтите масштабирование: для 100 k+ соединений рассмотрите WebSocket‑gateway (Centrifugo, Pushpin).
Транспорт Направление Задержка Сложность реализации Типичные сценарии
WebSocket Полный дуплекс < 100 мс Средняя Чаты, игры, торговля
SSE Только сервер → клиент < 500 мс Низкая Нотификации, ленты прогресса
WebRTC P2P аудио/видео/данные < 50 мс Высокая Видеозвонки, передача файлов

Что такое CRDT и чем он лучше Operational Transformation?

Совместное редактирование — не просто «кто последний записал, тот и прав». Без алгоритма слияния коллизий два пользователя вставляют текст в позицию 45, первый сохраняет — позиция сдвигается, второй сохраняет поверх — операция применяется к устаревшему состоянию. Текст дублируется или теряется.

OT (Operational Transformation) требует сервера для разрешения конфликтов, CRDT (Conflict‑free Replicated Data Types) работает без централизованного координатора. Yjs — наиболее зрелая CRDT‑библиотека для браузера. Интегрируется с ProseMirror, TipTap, CodeMirror, Monaco Editor.

Сравнение библиотек для совместного редактирования

Библиотека Алгоритм Поддержка редакторов Сложность Производительность
Yjs CRDT ProseMirror, TipTap, CodeMirror, Monaco Средняя Высокая (<10 мс при 100 операциях)
ShareDB OT ProseMirror, Quill Средняя Средняя (требуется сервер для слияния)
Automerge CRDT Любой (RichText) Высокая Хорошая (но память растёт быстрее Yjs)

Проблема: размер Yjs‑документа растёт из‑за истории операций. Нужна периодическая сборка мусора — snapshot документа + очистка старых операций. Без этого документ, над которым работали год, может весить 50 МБ.

Пример heartbeat на WebSocket (Node.js)
const ws = new WebSocket('wss://example.com');
let pingInterval;

ws.on('open', () => {
  pingInterval = setInterval(() => {
    ws.ping();
    setTimeout(() => {
      if (ws.readyState === WebSocket.OPEN) ws.terminate();
    }, 5000);
  }, 25000);
});

ws.on('close', () => clearInterval(pingInterval));

Типичные ошибки при внедрении real‑time

Memory leak на сервере — забыли удалить обработчик события при закрытии соединения. На Node.js heap растёт ~1 МБ/ч. EventEmitter предупреждает о 10+ слушателях, но не всегда это замечают.

Thundering herd при реконнекте. Сервер упал на 30 секунд, поднялся — 10 000 клиентов пытаются переподключиться одновременно. Exponential backoff с jitter обязателен: delay = Math.min(baseDelay * 2^attempt + random(0, 1000), maxDelay).

Отсутствие индикации потери соединения. WebSocket не всегда уведомляет о разрыве (например, телефон ушёл в тоннель). Heartbeat решает проблему.

Процесс работы

Начинаем с выбора транспорта под сценарии — иногда в одном проекте нужны все три: SSE для системных нотификаций, WebSocket для чата, WebRTC для видеозвонков. Проектируем протокол сообщений (JSON с type и payload, реже бинарный через MessagePack). Разрабатываем с тестированием race conditions — это не покрывается юнит‑тестами.

Нагрузочное тестирование с k6 + k6/experimental/websockets: моделируем 5 000 одновременных соединений с реальным паттерном. Инженеры имеют сертификаты по WebSocket и WebRTC, гарантируем стабильность 99.9%.

Что входит

  • Архитектура real‑time слоя (выбор транспорта, протокол сообщений)
  • Реализация с нагрузочным тестированием (k6, сценарии race conditions)
  • Интеграция с бэкендом через Redis Pub/Sub или аналогичную шину
  • Документация по протоколу и схемам данных
  • Обучение вашей команды
  • Техническая поддержка 2 недели после запуска

Почему Centrifugo может быть выгоднее, чем Socket.io?

Socket.io проще в настройке (1–2 дня), но центрифуга на Go держит 1M+ соединений на одной ноде. Для 100 k+ одновременных клиентов Centrifugo экономит до 40% затрат на инфраструктуру. Получите консультацию — мы поможем выбрать стек под вашу нагрузку.

Сроки

  • Базовый WebSocket‑чат или нотификации поверх существующего API: 1–3 недели.
  • Коллаборативный редактор с Yjs и persistence: 4–8 недель.
  • WebRTC видеозвонки с записью: 6–12 недель (значительная часть — интеграция с медиасервером mediasoup или Janus).

Свяжитесь с нами для оценки вашего проекта. Обсудите задачу с инженером — оценим сложность и сроки индивидуально.