Розробити веб-сайт, який функціонує як синхронний текстовий редактор. Документ можуть редагувати одночасно кілька користувачів, а зміни видно в режимі реального часу.
- Користувач відкриває документ → клієнт робить REST запит, отримує snapshot стану.
- Клієнт підключається по WebSocket → починає отримувати всі нові зміни.
- Коли користувач вносить зміни → вони відправляються на сервер (WebSocket повідомлення).
- Сервер перевіряє коректність декодування данних до CRDT-моделі і:
- розсилає їх всім іншим учасникам,
- зберігає зміни в таблиці
document_updates.
- Періодично або за подією (наприклад, закриття документа) сервер робить snapshot в
documents.content.
POST /documents/create→ створити документ.GET /documents/{id}→ повернути snapshot документа.
[! NOTE] snapshot зберігається в
documents.content(серіалізований CRDT). зміни зберігаються вdocument_updates.
- Підняти WebSocket endpoint
/ws/{document_id}. - Клієнт відправляє операції у форматі CRDT.
- Сервер зберігає зміни в таблиці 'document_updates' та розсилає іншим учасникам сессії.
[! NOTE] CRDT забезпечує унікальні ідентифікатори для кожного символу.
При видаленні символу сервер позначає його як «видалений», але зберігає ID для консистентності. Таким чином, конфліктів «чий символ залишився» не виникає.
- Зберігати документ у БД (модель CRDT).
- Зберігати зміни в
document_updates. - Періодично зберігати snapshot в
documents.content.
Таблиця documents для зберігання стану (snapshot).
CREATE TABLE documents (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
title TEXT NOT NULL,
content BYTEA NOT NULL,
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
Таблиця document_updates для зберігання логів змін.
CREATE TABLE document_updates (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
document_id UUID NOT NULL REFERENCES documents(id) ON DELETE CASCADE,
update BYTEA NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
[! NOTE] На початку редагування сервер піднімає модель CRDT зі snapshot + змін. Всі нові зміни записуються в БД та застосовуються через визначений час. Snapshot потрібен для швидкого завантаження, щоб не накопичувати багато змін.
- Якщо клієнт відключився, виконується reconnect, при якому відправляє ID документа та ініціалізує підключення знову.
- Якщо сервер падає, виконується reconnect, при якому CRDT відновлюється з snapshot та останніх змін.
[! NOTE] Такий підхід гарантує, що ніхто не втратить дані, навіть якщо сервер «впав» прямо в момент редагування.
-
Базовий бекенд
- Налаштувати сервер за допомогою
actix_web. - Додати необхідні ендпоінти.
- Налаштувати сервер за допомогою
-
База даних
- Створити БД з допомогою PostgreSQL.
- Створити міграції з таблицями
documents,document_updates. - Додати CRUD-операції для документів.
-
WebSocket шар
- Реалізувати підключення до
/ws/{document_id}.
- Реалізувати підключення до
-
CRDT модель
- Підключити бібліотеку CRDT.
- Налаштувати серіалізацію/десеріалізацію стану.
- Додати необхідні методи для застосування змін і їх відправки.
-
Frontend
- Інтерфейс з редактором (наприклад, CodeMirror з CRDT адаптером).
- Підключення по WebSocket і оновлення стану редактора.
-
Збереження стану
- При кожній зміні робити запис в
document_updates. - Snapshot в
documents.contentраз в N секунд або при закритті документа.
- При кожній зміні робити запис в
Rostyslav Kashper and Mariia Kaduk
GitHub: FantRS and MashaKaduk