Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

37 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Real-Time Collaborative AI-Powered Document Editor

A full-stack collaborative document editing platform featuring CRDT-based real-time synchronization, AI-powered writing assistance, role-based access control, and production-oriented observability.

Node.js TypeScript MongoDB React License


Table of Contents


Overview

This project is a full-stack collaborative document editing platform that allows multiple users to edit the same document simultaneously in real time, while leveraging AI-powered writing assistance for grammar correction, tone enhancement, and summarization.

It is inspired by architecture patterns found in products such as Google Docs, Notion, and Coda — conflict-free real-time sync, granular permission models, streaming AI responses, and production-ready observability.

Core capabilities:

  • Real-time collaborative editing using Yjs CRDTs over WebSockets
  • Rich text editing powered by Quill
  • AI-assisted writing using the Google Gemini API, with both standard and SSE-streamed responses
  • JWT-based authentication with secure, HTTP-only cookies
  • Granular role-based document permissions (Owner / Editor / Viewer)
  • Secure document sharing via share links and direct implementation by owner of document
  • Centralized logging (Winston, Morgan) and metrics (Prometheus)
  • Cloud-native deployment: Vercel (frontend) + Render (backend) + MongoDB Atlas (database)

Architecture

flowchart TB
    subgraph Client["client/src — React + TypeScript"]
        Pages[pages/ — Dashboard, Editor, Login, Signup, Share]
        Components[components/ui + layouts]
        SvcApi[services/api.ts]
        SvcSocket[services/socket.ts]
        SvcCollab[services/collaboration.ts]
        SvcAI[services/ai.ts]
        AuthCtx[context/AuthContext.tsx]
    end

    subgraph Edge["Vercel Edge"]
        CDN[Static Asset Delivery]
    end

    subgraph Backend["server/src — Node.js / Express / TypeScript"]
        RouteAuth[routes/auth.ts]
        RouteDoc[routes/doc.ts]
        RouteAI[routes/ai.ts]
        CtrlAuth[controllers/auth.ts]
        CtrlDoc[controllers/doc.ts]
        CtrlAI[controllers/ai.ts]
        SvcDoc[services/document.service.ts]
        SvcGemini[services/ai.service.ts]
        Mid[middleware/ — auth, rateLimiter, sanitize, validater, error]
        ModelLayer[model/ — User.ts, Document.ts]
        Socket[socketHandler.ts]
        MetricsMw[metrics/metrics.ts + middleware/metricsmiddleware.ts]
        Logger[utils/logger.ts]
        YjsUtils[utils/yjsUtils.ts]
    end

    subgraph External["External Services"]
        Gemini[Google Gemini API]
        Mongo[(MongoDB Atlas)]
    end

    subgraph Observability["Monitoring"]
        Winston[Winston Logs]
        MorganLog[Morgan Access Logs]
        Prom[Prometheus /metrics]
    end

    Pages --> SvcApi
    Pages --> SvcAI
    SvcCollab <--> SvcSocket
    SvcSocket <--> Socket
    SvcApi -->|REST| RouteAuth
    SvcApi -->|REST| RouteDoc
    SvcAI -->|REST / SSE| RouteAI
    AuthCtx --> SvcApi

    CDN --> Pages

    RouteAuth --> Mid --> CtrlAuth --> ModelLayer
    RouteDoc --> Mid --> CtrlDoc --> SvcDoc --> ModelLayer
    RouteAI --> Mid --> CtrlAI --> SvcGemini --> Gemini
    Socket --> SvcDoc
    Socket --> YjsUtils
    ModelLayer --> Mongo

    CtrlAuth --> Logger
    CtrlDoc --> Logger
    RouteAuth --> MetricsMw
    RouteDoc --> MetricsMw
    RouteAI --> MetricsMw

    Logger --> Winston
    RouteAuth --> MorganLog
    MetricsMw --> Prom
Loading

Deployment Topology

Layer Provider Notes
Frontend Vercel Static React build, edge CDN delivery
Backend API + WebSocket Render Long-lived process for WS connections
Database MongoDB Atlas Managed, replicated cluster
AI Provider Google Gemini API Streaming + standard completions
Logs Winston (app), Morgan (HTTP) Shipped to stdout / log aggregator
Metrics Prometheus Scrape endpoint exposed by backend

Feature Breakdown

Authentication & Authorization

  • User registration and login
  • JWT-based authentication with secure HTTP-only cookies
  • Persistent sessions and a "current user" endpoint
  • Protected route middleware
  • Logout with cookie invalidation

Document Management

  • Create, read, update, and delete documents
  • Document sharing via secure share links
  • Owner / Editor / Viewer permission model enforced throughout the backend

Real-Time Collaboration

  • Multi-user concurrent editing with conflict-free synchronization (CRDTs, not operational transforms)
  • Live presence awareness and connected-user tracking
  • Real-time cursor synchronization via the Awareness Protocol
  • Room-based collaboration with shared Y.Doc instances
  • Automatic merge resolution and memory cleanup for inactive rooms

Rich Text Editing

  • React + Quill editor
  • Live collaboration bindings (QuillBinding)
  • AI-assisted editing actions inline
  • Auto-save and manual save

AI Writing Assistant

  • Grammar correction — grammar, punctuation, clarity
  • Text enhancement — readability, tone, structure
  • Summarization — concise summaries and key-point extraction
  • Streaming generation via Server-Sent Events for progressive, token-by-token rendering

Technology Stack

Backend

Category Technology
Runtime Node.js
Framework Express
Language TypeScript
Database MongoDB + Mongoose
Auth JWT, bcrypt
Real-time WebSocket (ws), Yjs
AI Google Gemini API
Logging Winston, Morgan
Metrics Prometheus client

Frontend

Category Technology
Framework React + TypeScript (Vite)
UI Components shadcn/ui (Button, Dialog, Field, Input, Label, Separator)
HTTP Client Axios (services/api.ts)
Editor Quill
Real-time Yjs, WebSocket client (services/socket.ts, services/collaboration.ts)
Routing React Router (routes/RequireAuth.tsx)
Auth State React Context (context/AuthContext.tsx)

Folder Structure

collab-editor/
├── client/                          # React + TypeScript frontend (Vite)
│   ├── src/
│   │   ├── components/
│   │   │   ├── ui/                  # shadcn/ui primitives
│   │   │   │   ├── button.tsx
│   │   │   │   ├── deleteshare.tsx
│   │   │   │   ├── dialog.tsx
│   │   │   │   ├── field.tsx
│   │   │   │   ├── input.tsx
│   │   │   │   ├── label.tsx
│   │   │   │   ├── separator.tsx
│   │   │   │   └── sharedialogue.tsx
│   │   │   └── New.tsx
│   │   ├── context/
│   │   │   └── AuthContext.tsx
│   │   ├── layouts/
│   │   │   ├── Footer.tsx
│   │   │   └── Navbar.tsx
│   │   ├── lib/
│   │   │   └── utils.ts
│   │   ├── pages/
│   │   │   ├── DashboardPage.tsx
│   │   │   ├── EditorPage.tsx
│   │   │   ├── LoginPage.tsx
│   │   │   ├── SharePage.tsx
│   │   │   └── SignupPage.tsx
│   │   ├── routes/
│   │   │   └── RequireAuth.tsx
│   │   ├── services/
│   │   │   ├── ai.ts
│   │   │   ├── api.ts
│   │   │   ├── collaboration.ts
│   │   │   └── socket.ts
│   │   ├── App.tsx
│   │   ├── main.tsx
│   │   ├── theme.tsx
│   │   └── index.css
│   ├── index.html
│   ├── package.json
│   ├── vite.config.ts
│   ├── vercel.json
│   └── tsconfig.json
│
├── server/                          # Node.js + Express + TypeScript backend
│   ├── src/
│   │   ├── config/
│   │   │   ├── db.ts                # MongoDB connection
│   │   │   └── env.ts               # Environment variable loading
│   │   ├── controllers/
│   │   │   ├── ai.ts
│   │   │   ├── auth.ts
│   │   │   └── doc.ts
│   │   ├── metrics/
│   │   │   └── metrics.ts           # Prometheus metric definitions
│   │   ├── middleware/
│   │   │   ├── ai.ts                # AI-route-specific guards
│   │   │   ├── auth.ts              # JWT verification
│   │   │   ├── error.ts             # Centralized error handler
│   │   │   ├── metricsmiddleware.ts # Request metrics collection
│   │   │   ├── notFound.ts
│   │   │   ├── rateLimiter.ts
│   │   │   ├── sanitize.ts
│   │   │   └── validater.ts
│   │   ├── model/
│   │   │   ├── Document.ts
│   │   │   └── User.ts
│   │   ├── routes/
│   │   │   ├── ai.ts
│   │   │   ├── auth.ts
│   │   │   └── doc.ts
│   │   ├── services/
│   │   │   ├── ai.service.ts
│   │   │   └── document.service.ts
│   │   ├── utils/
│   │   │   ├── logger.ts            # Winston logger
│   │   │   └── yjsUtils.ts          # Yjs encode/decode helpers
│   │   ├── app.ts                   # Express app setup
│   │   ├── index.ts                 # Server entrypoint
│   │   └── socketHandler.ts         # WebSocket / Yjs collaboration logic
│   ├── tests/
│   │   ├── integration/
│   │   │   └── api.test.ts
│   │   └── unit/
│   │       └── permission.test.ts
│   ├── logs/
│   │   ├── combined.log
│   │   └── error.log
│   ├── jest.config.cjs
│   ├── package.json
│   └── tsconfig.json
│
├── .gitignore
└── README.md

System Design

The backend follows a layered MVC-style structure rather than a feature-module structure — each concern (auth, document, AI) is split horizontally across routes/, controllers/, services/, and model/:

Layer Files Responsibility
Routes routes/auth.ts, routes/doc.ts, routes/ai.ts Express endpoint definitions, wiring middleware to controllers
Controllers controllers/auth.ts, controllers/doc.ts, controllers/ai.ts Request/response handling, input parsing, calling services
Services services/document.service.ts, services/ai.service.ts Business logic: permission evaluation, Gemini calls, document operations
Models model/User.ts, model/Document.ts Mongoose schemas and instance methods (e.g., password hashing)
Middleware middleware/auth.ts, rateLimiter.ts, sanitize.ts, validater.ts, ai.ts, error.ts, notFound.ts JWT verification, rate limiting, input sanitization/validation, AI-route guards, centralized error handling
Collaboration socketHandler.ts, utils/yjsUtils.ts WebSocket connection handling, Y.Doc room management, CRDT encode/decode
Observability utils/logger.ts, metrics/metrics.ts, middleware/metricsmiddleware.ts Winston logging, Prometheus metric definitions, per-request metrics capture
Config config/db.ts, config/env.ts MongoDB connection setup, environment variable loading

This separation keeps request handling, business logic, and persistence independently testable, even though they aren't grouped into per-feature folders.


Database Schema

erDiagram
    USER {
        ObjectId _id
        string username
        string email
        string password
        date createdAt
        date updatedAt
    }

    DOCUMENT {
        ObjectId _id
        string title
        string content
        ObjectId owner
        binary yjsState
        string shareLink
        boolean isPublic
        date lastSaved
        date createdAt
        date updatedAt
    }

    PERMISSION {
        ObjectId user
        string role
    }

    USER ||--o{ DOCUMENT : owns
    DOCUMENT ||--o{ PERMISSION : "has many"
    USER ||--o{ PERMISSION : "is assigned"
Loading

User Collection

Field Type Notes
username String Unique
email String Unique, indexed
password String bcrypt-hashed
createdAt / updatedAt Date Timestamps

The user model exposes a password-comparison method built on bcrypt for secure authentication.

Document Collection

Field Type Notes
title String
content String Serialized rich-text snapshot
owner ObjectId References User
permissions [{ user, role }] Embedded permission list
shareLink String Unique token for link-based access
isPublic Boolean Whether the share link grants access without invitation
yjsState Binary Persisted CRDT state for recovery
lastSaved Date Last successful auto-save
createdAt / updatedAt Date Timestamps

Role-Based Access Control (RBAC)

Every document maintains a permissions array of { user, role } entries. Roles follow a strict hierarchy:

Owner > Editor > Viewer

Owner inherits all Editor and Viewer permissions; Editor inherits Viewer permissions. The Document model exposes a permission-evaluation utility that resolves this hierarchy for any access-control check.

Capability Owner Editor Viewer
View document
Edit content
Real-time collaboration ✅ (read-only session)
Use AI features
Delete document
Generate / manage share links
Invite / remove collaborators Only if explicitly granted
Change collaborator roles
Transfer ownership ✅ (future-ready)

Sharing & Access Revocation

Authorized users (owners, and editors with explicit grants) can:

  • Invite collaborators and assign a role at invitation time
  • Upgrade or downgrade an existing collaborator's role
  • Revoke a collaborator's access entirely
  • Generate and rotate secure share links

When access is revoked, enforcement is immediate and consistent across the system:

  • Subsequent REST API requests for that document are denied
  • The user's real-time collaboration session is terminated
  • Protected document routes return an authorization error
  • AI actions on the document are blocked

Enforcement Layers

Permission checks are not centralized in a single place — they are validated at every layer that touches a document:

flowchart LR
    Req[Incoming Request] --> AuthCheck[Authentication Check]
    AuthCheck --> RoleCheck{Permission Evaluation Utility}
    RoleCheck -->|API Layer| API[REST CRUD / Sharing Routes]
    RoleCheck -->|Collaboration Layer| Room[WebSocket Room Join]
    RoleCheck -->|AI Layer| AIGate[AI Action Gate]
    API -->|Authorized| Allow1[Proceed]
    Room -->|Authorized| Allow2[Join Y.Doc Room]
    AIGate -->|Authorized| Allow3[Invoke Gemini]
    API -->|Unauthorized| Deny1[403 Forbidden]
    Room -->|Unauthorized| Deny2[Connection Rejected]
    AIGate -->|Unauthorized| Deny3[403 Forbidden]
Loading
  • API layer — every protected document route validates authentication, document ownership, and required role level.
  • Collaboration layer — before a client is allowed to join a collaboration room, identity is verified and document permissions are re-validated; unauthorized users are denied a WebSocket connection.
  • AI layer — AI actions require valid authentication and sufficient document permission; users without access cannot invoke AI operations on a protected document.

This mirrors the layered permission enforcement found in systems like Google Docs, Notion, and Confluence.


Real-Time Collaboration Workflow

Synchronization is handled entirely through CRDT state merging — there is no operational-transform layer and no central "lock" on document state.

sequenceDiagram
    participant U1 as User A (Quill)
    participant Y1 as Y.Doc (Client A)
    participant WS as WebSocket Server
    participant Y2 as Y.Doc (Client B)
    participant U2 as User B (Quill)

    U1->>Y1: Local edit
    Y1->>Y1: Update Y.Text
    Y1->>WS: Broadcast CRDT update
    WS->>Y2: Relay update to peers in room
    Y2->>Y2: Merge update (conflict-free)
    Y2->>U2: Re-render editor
    Note over Y1,Y2: No manual conflict resolution required
Loading

Editing flow

  1. A user edits text in the Quill editor.
  2. QuillBinding propagates the change into the local Y.Text.
  3. The Y.Doc state updates.
  4. The WebSocket provider broadcasts the encoded update.
  5. The backend relays the update to all peers connected to that document's room.
  6. Peers merge the update automatically via CRDT semantics.
  7. The UI updates instantly for every connected client, with no manual conflict resolution.

Persistence flow

  1. Users edit the document; CRDT state synchronizes instantly across clients.
  2. An auto-save interval periodically serializes the current state.
  3. Content (and the binary yjsState) is persisted to MongoDB.
  4. MongoDB acts as durable backup storage, while live collaboration state remains owned by Yjs in memory.

AI Workflow

sequenceDiagram
    participant User
    participant Frontend
    participant Backend as AI Module
    participant Gemini as Google Gemini API

    User->>Frontend: Select text + trigger AI action
    Frontend->>Backend: POST /api/ai/:action (SSE)
    Backend->>Backend: Validate auth + document permission
    Backend->>Backend: Apply rate limit
    Backend->>Gemini: Generate request
    Gemini-->>Backend: Streamed tokens
    Backend-->>Frontend: SSE chunks
    Frontend-->>User: Progressive render
    User->>Frontend: Apply result to editor
Loading
  1. The user selects text and triggers an AI action (grammar fix, enhancement, or summarization).
  2. The backend validates the user's permission on the target document.
  3. Rate limits are enforced on the AI endpoint specifically.
  4. The Gemini API generates the response.
  5. For streaming requests, output is sent as Server-Sent Events, chunk by chunk.
  6. The frontend renders the content progressively as it arrives.
  7. The user reviews and applies the generated result back into the Quill editor.

API Overview

Base URL: /api

Auth

Method Endpoint Description
POST /auth/register Create a new user account
POST /auth/login Authenticate and receive a session cookie
POST /auth/logout Invalidate the current session
GET /auth/me Return the current authenticated user

Documents

Method Endpoint Description
GET /documents List documents owned by or shared with the user
POST /documents Create a new document
GET /documents/:id Retrieve a document (permission-checked)
PUT /documents/:id Update document content or metadata
DELETE /documents/:id Delete a document (owner only)
POST /documents/:id/share Generate or update a share link
GET /documents/shared/:token Access a document via share link
POST /documents/:id/collaborators Invite a collaborator with a role
PATCH /documents/:id/collaborators/:userId Update a collaborator's role
DELETE /documents/:id/collaborators/:userId Revoke a collaborator's access

AI

Method Endpoint Description
POST /ai/grammar Grammar and clarity correction
POST /ai/enhance Tone and readability enhancement
POST /ai/summarize Summarization / key-point extraction
POST /ai/stream/:action SSE-streamed variant of the above actions

Real-Time

Protocol Endpoint Description
WS /ws/documents/:id Join a document's collaboration room (Yjs sync + awareness)

Observability

Method Endpoint Description
GET /metrics Prometheus-formatted metrics
GET /health Liveness/readiness probe

Installation

Prerequisites

  • Node.js 18+
  • npm or yarn
  • A MongoDB instance (local or Atlas)
  • A Google Gemini API key

Clone the repository

git clone https://github.com/your-username/collab-editor.git
cd collab-editor

Install dependencies

# Server
cd server
npm install

# Client
cd ../client
npm install

Environment Variables

Create a .env file in server/ (see .env.example):

# Server
PORT=5000
NODE_ENV=development

# Database
MONGODB_URI=mongodb+srv://<user>:<password>@cluster.mongodb.net/collab-editor

# Auth
JWT_SECRET=your_jwt_secret
JWT_EXPIRES_IN=7d
COOKIE_SECURE=false

# AI
GEMINI_API_KEY=your_gemini_api_key
GEMINI_MODEL=gemini-1.5-pro

# CORS
CLIENT_ORIGIN=http://localhost:3000

# Rate Limiting
RATE_LIMIT_WINDOW_MS=900000
RATE_LIMIT_MAX=100
AI_RATE_LIMIT_MAX=20

Create a .env file in client/:

VITE_API_BASE_URL=http://localhost:5000/api
VITE_WS_URL=ws://localhost:5000

Local Development Setup

# Terminal 1 — server
cd server
npm run dev

# Terminal 2 — client
cd client
npm run dev

By default:

  • Backend runs on http://localhost:5000
  • Frontend (Vite) runs on http://localhost:5173
  • WebSocket collaboration server runs on the same port as the backend, under /ws

Deployment Guide

Backend (Render)

  1. Create a new Web Service on Render, pointing at the server/ directory.
  2. Set the build command to npm install && npm run build and the start command to npm start.
  3. Configure all backend environment variables in the Render dashboard.
  4. Ensure the service plan supports long-lived WebSocket connections.

Frontend (Vercel)

  1. Import the repository into Vercel and set the root directory to client/.
  2. Set VITE_API_BASE_URL and VITE_WS_URL to your deployed Render backend's HTTPS/WSS URLs.
  3. Deploy — Vercel will build and serve the static frontend via its edge CDN.

Database (MongoDB Atlas)

  1. Provision a cluster on MongoDB Atlas.
  2. Whitelist the Render service's outbound IP (or allow access from anywhere for simplicity, scoped down for production).
  3. Use the generated connection string as MONGODB_URI.

Monitoring & Observability

Winston (Application Logging)

Used for application events, database connection lifecycle, error tracking, and service startup/shutdown logs, categorized into info, warn, error, and debug levels.

Morgan (HTTP Request Logging)

Tracks HTTP requests, response status codes, response times, and request metadata — useful for API debugging and traffic analysis.

Prometheus (Metrics)

Exposes an operational metrics endpoint (/metrics) including:

  • Total request counts
  • Response duration histograms
  • Active WebSocket connection counts
  • Error counts by route
  • Per-endpoint performance breakdowns

These metrics are scrape-compatible with a standard Prometheus + Grafana stack for dashboards and alerting.


Security

Layer Measures
Authentication JWT validation, secure HTTP-only cookies, bcrypt password hashing
API Security Helmet security headers, CORS allowlists, input validation, request sanitization
Abuse Prevention Global rate limiting, route-specific rate limiting, dedicated AI endpoint throttling
Data Protection Permission validation, resource ownership checks, protected document access enforcement

Permission and ownership checks are applied consistently across REST APIs, document CRUD operations, share-link workflows, real-time collaboration entry points, and AI-assisted actions — not just at the outermost route layer.


Testing

Unit Tests

  • User model (password hashing, comparison)
  • Authentication utilities
  • Permission validation logic

API Tests

  • Auth endpoints (register, login, session)
  • Document endpoints (CRUD)
  • Permission boundary enforcement

Integration Tests

  • End-to-end share-link workflows
  • Cross-role authorization checks (owner/editor/viewer)
cd server
npm run test
npm run test:integration

Roadmap

  • Ownership transfer workflow (already permission-ready in the data model)
  • Offline editing with local persistence and reconnection sync
  • Document version history and rollback
  • Comment threads and inline suggestions
  • Org/workspace-level access control
  • Pluggable AI providers beyond Gemini
  • Mobile-responsive editor experience

Screenshots

Add screenshots or screen recordings here.

Dashboard Editor AI Panel
./docs/screenshots/dashboard.png ./docs/screenshots/editor.png ./docs/screenshots/ai-panel.png

License

This project is licensed under the MIT License.

About

Resources

Stars

3 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages