Quill is a high-fidelity, full-stack collaborative workspace platform designed for teams to brainstorm, draft documents, design diagrams, and chat in real time. Combining a headless rich-text editor, a vector-based diagram canvas, and workspace-wide channels, Quill provides a unified hub for team productivity.
- Rich-Text Mode (TipTap): Fully collaborative headless text editor powered by ProseMirror, supporting formatting (bold, italic, lists, quotes, code blocks) and real-time document saves.
- Visual Diagram Mode (Excalidraw): Interactive whiteboard canvas for designing architecture diagrams, mind maps, and wireframes in real time.
- Real-Time Selections & Pointers: Syncs active text carets (from/to positions) and canvas pointers (coordinates, button states, and stable user colors) with other collaborators at 60 FPS.
- Typing Guard Engine: Implements an active keystroke guard (
1200mswindow) that defers incoming remote synchronization blocks while a user is typing, preventing cursor jumps and text overwrites.
- Workspace Channels: Dedicated general channels scoped to specific workspaces.
- Live Sync Messages: Full CRUD operations on chat messages (Send, Edit, Delete) with immediate Socket.io broadcasts.
- Typing Indicators: Bouncing indicators showing which team members are currently composing a message.
- Active Members List: Dynamic updates showing which workspace members are currently online in the chat lobby.
- Workspaces: Group documents, drawings, and discussions into independent workspaces.
- Invite Engine: Generate invite codes for team members to join private workspaces seamlessly.
- Visibility Toggles: Switch workspaces between
publicandprivatevisibility rules.
- Framework: React 19 (Concurrent rendering hooks)
- Bundle & Tooling: Vite
- Styling: Tailwind CSS v4 (Compiler-based, low runtime footprint)
- Server Cache State: TanStack React Query v5 (Auto-refetching, query mutations, optimistic UI updates)
- Global State: Redux Toolkit (RTK) (Auth credentials, global UI settings)
- Libraries: Lucide-React, React-Router v7, Socket.io-client
- Framework: Express 5
- Real-time Engine: Socket.io (Namespaces, heartbeats, automatic reconnection, dynamic rooms)
- Database (ODM): MongoDB + Mongoose
- Security: JWT Authentication (HTTP-Only Cookie storage), custom WebSockets handshake authentication middleware
- Utilities: Express-validator, bcryptjs, cookie-parser
graph TD
subgraph Client [Frontend - React 19]
C_Ed[TipTap Rich Text]
C_Dr[Excalidraw Canvas]
C_Ch[Workspace Chat]
end
subgraph Transport [Dual-Protocol Transport]
HTTP[REST HTTP Gateway]
WS[Socket.io WebSockets Gateway]
end
subgraph Server [Backend - Express 5 App]
MW[Auth & Validation Middleware]
SM[Socket Rooms Coordinator]
DAO[Data Access Objects]
end
subgraph Storage [Database]
MDB[(MongoDB Atlas)]
end
C_Ed <-->|Live Edits / Cursors| WS
C_Dr <-->|Pointers / Elements| WS
C_Ch <-->|Typing / Messages| WS
C_Ed -->|Load Document| HTTP
C_Dr -->|Load Elements| HTTP
C_Ch -->|Fetch History| HTTP
HTTP --> MW
WS -->|Handshake Verification| SM
MW --> DAO
SM --> DAO
DAO <--> MDB
- Node.js (v18 or higher)
- MongoDB Instance (Atlas URI or local server)
git clone https://github.com/few-4/Quill.git
cd QuillNavigate to the Backend directory:
cd Backend
npm installCreate a .env file inside the Backend folder using the variables below:
PORT=3000
MONGO_URI=mongodb+srv://<username>:<password>@cluster0.mongodb.net/quill
ACCESS_TOKEN_SECRET=your_jwt_access_secret_key
REFRESH_TOKEN_SECRET=your_jwt_refresh_secret_key
CORS_ORIGIN=http://localhost:5173Run the backend in development mode:
npm run devNavigate to the Frontend directory in a new terminal window:
cd Frontend
npm installCreate a .env file inside the Frontend folder:
VITE_BACKEND_URL=http://localhost:3000Run the frontend development server:
npm run devOpen http://localhost:5173 in your browser.
POST /register- Register a new user.POST /login- Login, authenticates credentials, and issues HTTP-Only access cookies.POST /logout- Clear cookies and terminate active user session.
POST /create- Establish a new workspace (Private Access).GET /all- Fetch all workspaces the user participates in as owner or member.POST /join- Join an existing workspace using a generated invite code.DELETE /:workspaceId- Delete a workspace (Owner-only privilege).
POST /create- Create a new document (type: "text"ortype: "visual").GET /workspace/:workspaceId- Retrieve all documents belonging to a workspace.GET /:docId- Hydrate a single document's metadata and full JSON state.PATCH /:docId- Rename a document.DELETE /:docId- Delete a document.
POST /:workspaceId- Post a new message to the workspace channel.GET /:workspaceId- Fetch paginated chat history.PUT /:messageId- Edit a message.DELETE /:messageId- Delete a message.
- WebSocket Handshake Guard: Every Socket connection is parsed at connection handshake via
io.useto authenticate JWT tokens, denying unauthenticated socket queries from consuming connection slots. - Excalidraw Loop-Change Gate: Calculates elements' version sums to distinguish between local changes and incoming socket updates, breaking state loop cycles.
- Mongoose Compound Indexes: Speeds sorting and filtering queries from linear searches to
O(log N)index lookups using pre-sorted B-Trees:documentSchema.index({ workspaceId: 1, updatedAt: -1 }); messageSchema.index({ workspaceId: 1, createdAt: -1 });