Skip to content

Latest commit

 

History

History
192 lines (127 loc) · 4.82 KB

File metadata and controls

192 lines (127 loc) · 4.82 KB

Cowrite


Description

A real-time collaborative text editor built with FastAPI, WebSockets, and Redis, allowing multiple users to edit the same document simultaneously while staying synchronized with live presence and typing indicators.


Tech Stack

Python FastAPI Pydantic Postgres Celery RabbitMQ Sentry Redis Resend Docker


Core Features

  • Real-time collaborative editing
  • Live user presence
  • Typing indicators
  • Automatic synchronization of document changes
  • Redis-powered pub/sub for low-latency updates
  • WebSocket-based communication

Concepts Covered

  • Real-time event broadcasting: Events are published to all users in a room and requires no polling.
  • Pub/Sub Systems: A redis pub/sub channel is used as the medium for event publishing. This solves the multi-instance limitations by ensuring all users in a room have access to events irrespective of the instance connected to.
  • Presence and Typing indicators: Broadcast presence and typing events in real-time.
  • Event Ordering: Operation events are assigned a number to maintain sequential order.
  • Operational Transformation: Applied to preserve all modifications from conflicting operations by merging writes from multiple users.

Prerequisites

Before running Notix locally, make sure you have:

  • Python 3.12 or newer
  • Docker and Docker Compose
  • uv (recommended for dependency management)
  • access to a PostgreSQL instance, Redis, RabbitMQ, and Resend credentials

Installation

Running With Docker Compose

The repository includes a full local stack for the API, worker, PostgreSQL, Redis, and RabbitMQ.

Start all services

docker compose up --build

This will launch:

Stop services

docker compose down

Running Locally Without Docker

1. Clone the repository and switch to directory

git clone https://github.com/<your-username>/cowrite.git

cd cowrite

2. Install dependencies

uv sync

3. Environment Configuration

cp .env.example .env

4. Apply database migrations

uv run alembic upgrade head

5. Start the application

uv run uvicorn app.main:app --reload --host 0.0.0.0 --port 8000

WebSocket Usage

Testing with Postman

Postman can be used to test the WebSocket endpoint.

  • Open Postman.
  • Create a new WebSocket Request.
  • Connect to the application's WebSocket URL.
  • Once connected, clients exchange JSON messages over the WebSocket.

Example:

ws://localhost:8000/api/v1/ws/?token={bearer_token}

After connecting:

  • Send a ping message every 10 seconds to remain connected.
  • Send typing events while testing.
  • Send document editing events to verify synchronization.
  • Observe broadcasts from other connected clients.

Presence (Important)

Every connected client must send a ping event every 10 seconds. The server refreshes the user's Redis presence key whenever a ping is received.

If the client stops sending pings:

  • The Redis presence key expires.
  • The user is considered offline.
  • The server removes the user from the room.

Example:

{ "event": "ping", "doc_id": "abc" }

It is recommended to implement this as a repeating timer on the client that sends a ping every 10 seconds for the lifetime of the connection.


Typing Events

Cowrite uses typing events to provide live typing indicators. Every keystroke should send a typing event.

Example:

{ "event": "typing", "doc_id": "abc" }

Clients do not need to manually send a typing stopped event. When no typing event has been received for 3 seconds, the server automatically broadcasts that the user has stopped typing.


Testing

Run the test suite with:

uv run pytest

Run in verbose mode:

uv run pytest -v