Create. Collaborate. Save Forever.
A real-time collaborative drawing platform — the Google Docs of visual collaboration.
Instant. Intuitive. Multiplayer-first.
- Overview
- Features
- System Architecture
- Tech Stack
- Project Structure
- Getting Started
- Environment Variables
- Development Commands
- How Real-Time Collaboration Works
- Deployment
- Roadmap
- Documentation
- Contributing
- License
DrawSaver empowers individuals and teams to draw, brainstorm, and collaborate visually — all in real-time on a shared canvas. Whether you're a student sketching diagrams, a designer wireframing, or a remote team whiteboarding, DrawSaver gives you a seamless multiplayer creative workspace.
┌──────────────────────────────────────────────────────────────┐
│ │
│ 🎯 Problem → 💡 Solution │
│ │
│ Fragmented visual → One platform for drawing, │
│ collaboration collaborating, and saving │
│ tools with no — instantly, with anyone, │
│ real-time sync anywhere. │
│ │
└──────────────────────────────────────────────────────────────┘
|
|
|
|
graph TB
subgraph Clients["🖥️ Clients"]
B1["Browser A<br/>(React + Fabric.js)"]
B2["Browser B<br/>(React + Fabric.js)"]
B3["Browser C<br/>(React + Fabric.js)"]
end
subgraph Edge["🌐 Edge Layer"]
CDN["CDN / Vercel Edge<br/>Static Assets"]
end
subgraph Backend["⚙️ Backend Services"]
API["REST API Server<br/>(Express.js)"]
WS["WebSocket Server<br/>(Socket.IO)"]
end
subgraph Data["🗄️ Data Layer"]
DB["MongoDB Atlas<br/>(Primary Store)"]
CACHE["Redis<br/>(Cache / PubSub)"]
S3["AWS S3<br/>(File Storage)"]
end
B1 & B2 & B3 -->|"HTTPS"| CDN
B1 & B2 & B3 -->|"REST API"| API
B1 & B2 & B3 <-->|"WebSocket"| WS
API --> DB
API --> CACHE
API --> S3
WS --> CACHE
WS --> DB
style Clients fill:#1a1a2e,stroke:#6c5ce7,color:#f8f9fa
style Edge fill:#16213e,stroke:#00cec9,color:#f8f9fa
style Backend fill:#1a1a2e,stroke:#6c5ce7,color:#f8f9fa
style Data fill:#16213e,stroke:#00cec9,color:#f8f9fa
sequenceDiagram
participant A as 👤 User A
participant S as 🖥️ Server
participant R as 📦 Redis
participant B as 👤 User B
A->>S: draw-action (rect added)
S->>S: Validate + timestamp
S->>R: Buffer action
S->>B: Broadcast draw-action
B->>B: Apply to local canvas
Note over R,S: Every 30s
S->>S: Flush buffer → MongoDB
| Layer | Technology | Why |
|---|---|---|
| ⚛️ Frontend | React 18 + Vite | Fast HMR, component model, largest ecosystem |
| 🎨 Canvas | Fabric.js | Object model, built-in serialization, rich events |
| 📦 State | Zustand | Minimal boilerplate, works outside React (canvas events) |
| 💅 Styling | Tailwind CSS | Utility-first, rapid UI development |
| 🟢 Runtime | Node.js 20 LTS | Same language as frontend, non-blocking I/O |
| 🚂 API | Express.js | Mature, widest middleware ecosystem |
| 🔌 Real-Time | Socket.IO | Rooms, auto-reconnect, fallback, Redis adapter |
| 🍃 Database | MongoDB + Mongoose | Flexible schema fits canvas JSON, horizontal scaling |
| ⚡ Cache | Redis | PubSub for Socket.IO scaling, rate limiting, sessions |
| ☁️ Storage | AWS S3 | 99.999999999% durability, presigned uploads, CDN-ready |
| 🔐 Auth | Passport.js + JWT | OAuth strategies, full control over token flow |
| ✅ Testing | Vitest + Playwright | Fast unit tests + reliable E2E browser tests |
| 🚀 CI/CD | GitHub Actions | Native GitHub integration, matrix builds |
| 📡 Deploy | Vercel + Render | Zero-config frontend CDN + Docker backend hosting |
DrawSaver/
│
├── 📂 docs/ # 13 production-grade documentation files
│
├── 📂 frontend/ # React + Vite SPA
│ └── src/
│ ├── components/ # UI: canvas/, collaboration/, layout/, ui/
│ ├── pages/ # LandingPage, Dashboard, DrawingWorkspace, ...
│ ├── hooks/ # useCanvas, useSocket, useAuth, useAutoSave
│ ├── store/ # Zustand: canvasStore, roomStore, authStore
│ ├── services/ # API clients (Axios + interceptors)
│ ├── socket/ # Socket.IO client + event handlers
│ └── utils/ # Helpers, constants, throttle
│
├── 📂 backend/ # Node.js + Express API
│ └── src/
│ ├── config/ # MongoDB, Redis, S3, Passport, env validation
│ ├── models/ # User, Room, Drawing, DrawingVersion
│ ├── routes/ # /auth, /rooms, /drawings, /users
│ ├── controllers/ # Thin request handlers
│ ├── services/ # Business logic layer
│ ├── middleware/ # authGuard, validate, rateLimiter, errorHandler
│ ├── socket/ # Room, drawing, cursor, presence handlers
│ ├── validators/ # Zod schemas
│ └── utils/ # Logger, error class, token helpers
│
├── 📂 shared/ # Shared constants + types
├── 📂 .github/workflows/ # CI/CD pipelines
├── 🐳 docker-compose.yml # Local dev: MongoDB + Redis + MinIO
└── 📄 README.md
| Tool | Version | Download |
|---|---|---|
| Node.js | 20+ | nodejs.org |
| Docker | Latest | docker.com |
| Git | Latest | git-scm.com |
graph LR
A["1️⃣ Clone Repo"] --> B["2️⃣ Start Docker"]
B --> C["3️⃣ Setup Backend"]
C --> D["4️⃣ Setup Frontend"]
D --> E["5️⃣ Open App 🎉"]
style A fill:#6c5ce7,stroke:#6c5ce7,color:#fff
style B fill:#00cec9,stroke:#00cec9,color:#fff
style C fill:#6c5ce7,stroke:#6c5ce7,color:#fff
style D fill:#00cec9,stroke:#00cec9,color:#fff
style E fill:#00b894,stroke:#00b894,color:#fff
git clone https://github.com/algorithnicmind/DrawSaver.git
cd DrawSaverdocker compose up -dThis starts MongoDB (
localhost:27017), Redis (localhost:6379), and MinIO S3 (localhost:9000).
cd backend
cp .env.example .env # Configure your environment
npm install
npm run dev # → http://localhost:5000cd frontend
cp .env.example .env # Set API URL
npm install
npm run dev # → http://localhost:5173Navigate to http://localhost:5173 and start drawing! 🎨
🔧 Backend .env (click to expand)
# Server
NODE_ENV=development
PORT=5000
# Database
MONGODB_URI=mongodb://admin:devpassword@localhost:27017/drawsaver?authSource=admin
REDIS_URL=redis://localhost:6379
# Authentication
JWT_ACCESS_SECRET=your-access-secret-min-32-chars
JWT_REFRESH_SECRET=your-refresh-secret-min-32-chars
# OAuth
GOOGLE_CLIENT_ID=your-google-client-id
GOOGLE_CLIENT_SECRET=your-google-client-secret
GITHUB_CLIENT_ID=your-github-client-id
GITHUB_CLIENT_SECRET=your-github-client-secret
# Storage (S3/MinIO)
S3_ENDPOINT=http://localhost:9000
S3_ACCESS_KEY=minioadmin
S3_SECRET_KEY=minioadmin
S3_BUCKET=drawsaver-assets
# CORS
FRONTEND_URL=http://localhost:5173⚛️ Frontend .env (click to expand)
VITE_API_URL=http://localhost:5000/api/v1
VITE_WS_URL=http://localhost:5000
VITE_GOOGLE_CLIENT_ID=your-google-client-idBackend Commands
| Command | Description |
|---|---|
npm run dev |
Start dev server with hot reload |
npm run start |
Start production server |
npm run test |
Run unit tests (Vitest) |
npm run lint |
Run ESLint |
npm run lint:fix |
Auto-fix lint issues |
Frontend Commands
| Command | Description |
|---|---|
npm run dev |
Start Vite dev server (HMR) |
npm run build |
Production build |
npm run preview |
Preview production build |
npm run test |
Run Vitest unit tests |
npm run test:e2e |
Run Playwright E2E tests |
npm run lint |
Run ESLint |
Docker Commands
| Command | Description |
|---|---|
docker compose up -d |
Start all services |
docker compose down |
Stop all services |
docker compose down -v |
Stop + remove volumes (full reset) |
docker compose logs -f |
Tail all service logs |
docker compose ps |
Check service status |
graph TD
subgraph UserA["👤 User A"]
A1["Draws rectangle<br/>on local canvas"]
A2["Fabric.js fires<br/>object:added"]
A3["Serialize object<br/>to JSON"]
A4["Emit draw-action<br/>via Socket.IO"]
end
subgraph Server["🖥️ Socket.IO Server"]
S1["Receive &<br/>validate action"]
S2["Add server<br/>timestamp"]
S3["Buffer in<br/>Redis"]
S4["Broadcast to<br/>room (excl. sender)"]
end
subgraph UserB["👤 User B"]
B1["Receive<br/>draw-action"]
B2["Deserialize<br/>object"]
B3["Add to local<br/>canvas"]
B4["Render ✅"]
end
A1 --> A2 --> A3 --> A4
A4 -->|WebSocket| S1
S1 --> S2 --> S3 --> S4
S4 -->|WebSocket| B1
B1 --> B2 --> B3 --> B4
style UserA fill:#1a1a2e,stroke:#6c5ce7,color:#f8f9fa
style Server fill:#16213e,stroke:#00cec9,color:#f8f9fa
style UserB fill:#1a1a2e,stroke:#6c5ce7,color:#f8f9fa
| Aspect | Strategy | Rationale |
|---|---|---|
| Sync Model | Operation-based (not snapshots) | Lower bandwidth, instant updates |
| Conflict Resolution | Last-write-wins (MVP) → CRDT (v2) | Simple first, scale later |
| Cursor Tracking | Throttled to 50ms, HTML overlay | Smooth rendering without canvas overhead |
| Presence | Redis key expiry + heartbeats | Stateless, auto-cleanup on crash |
| Reconnection | 30s grace period, full state resync | No data loss on network blips |
graph LR
subgraph Production
V["Vercel<br/>Frontend CDN"]
R["Render<br/>Backend Docker"]
MA["MongoDB Atlas<br/>Database"]
RC["Redis Cloud<br/>Cache"]
S3["AWS S3<br/>Files"]
end
GH["GitHub Push"] -->|"auto-deploy"| V
GH -->|"CI/CD"| R
R --> MA
R --> RC
R --> S3
style Production fill:#0f0f23,stroke:#6c5ce7,color:#f8f9fa
style GH fill:#00b894,stroke:#00b894,color:#fff
| Service | Platform | Free Tier → Production |
|---|---|---|
| Frontend | Vercel | Free → Pro ($20/mo) |
| Backend | Render | $7/mo → $25/mo |
| Database | MongoDB Atlas | M0 Free → M10 ($57/mo) |
| Cache | Redis Cloud | Free 30MB → $5/mo |
| Storage | AWS S3 | Pay-as-you-go (~$1–5/mo) |
| Errors | Sentry | Free 5K events/mo |
| 📊 Total MVP | ~$10–30/mo |
Step-by-step deployment instructions
Frontend → Vercel
- Connect GitHub repo to Vercel
- Set root directory:
frontend/ - Build command:
npm run build - Output directory:
dist - Add environment variables in dashboard
Backend → Render
- Create Web Service on Render
- Connect GitHub repo
- Root directory:
backend/ - Start command:
node server.js - Add environment variables
- Enable Docker deployment
Database → MongoDB Atlas
- Create cluster at MongoDB Atlas
- Create database user
- Whitelist IPs (allow all for Render)
- Copy connection string → set as
MONGODB_URI
gantt
title DrawSaver Development Roadmap
dateFormat YYYY-MM-DD
axisFormat %b %d
section Phase 1 — MVP
Project Setup & Auth :done, p1a, 2026-06-01, 7d
Canvas Engine :active, p1b, after p1a, 7d
Rooms & Persistence :p1c, after p1b, 7d
MVP Polish & Launch :p1d, after p1c, 7d
section Phase 2 — Collaboration
WebSocket Foundation :p2a, after p1d, 7d
Presence & Cursors :p2b, after p2a, 7d
Collaboration Polish :p2c, after p2b, 7d
section Phase 3 — Advanced
Version History & Layers :p3a, after p2c, 7d
Export & Sharing :p3b, after p3a, 7d
UX Polish & Performance :p3c, after p3b, 7d
section Phase 4 — Production
Testing & Security :p4a, after p3c, 7d
DevOps & Launch :p4b, after p4a, 7d
section Phase 5 — AI & Scale
AI Features :p5, after p4b, 30d
| Phase | Status | Focus |
|---|---|---|
| ✅ Phase 0 | Complete | Project documentation (14 docs) |
| 🔄 Phase 1 | In Progress | Auth + Canvas + Save (MVP) |
| ⬜ Phase 2 | Planned | WebSocket + Rooms + Real-time |
| ⬜ Phase 3 | Planned | History, Export, Layers, UX |
| ⬜ Phase 4 | Planned | Testing, DevOps, Production deploy |
| ⬜ Phase 5 | Future | AI drawing assist, Mobile, Enterprise |
All project documentation lives in the docs/ directory — 13 production-grade documents covering every aspect of the system:
|
|
We welcome contributions! Here's the workflow:
graph LR
A["🍴 Fork"] --> B["🌿 Branch"]
B --> C["💻 Code"]
C --> D["✅ Test"]
D --> E["📤 Push"]
E --> F["🔀 PR"]
style A fill:#6c5ce7,stroke:#6c5ce7,color:#fff
style B fill:#00cec9,stroke:#00cec9,color:#fff
style C fill:#6c5ce7,stroke:#6c5ce7,color:#fff
style D fill:#00b894,stroke:#00b894,color:#fff
style E fill:#00cec9,stroke:#00cec9,color:#fff
style F fill:#6c5ce7,stroke:#6c5ce7,color:#fff
# 1. Fork the repo and clone your fork
git clone https://github.com/your-username/DrawSaver.git
# 2. Create a feature branch
git checkout -b feature/DS-XXX-your-feature
# 3. Make your changes and commit (conventional commits)
git commit -m "feat: add pencil pressure sensitivity"
# 4. Push and open a PR
git push origin feature/DS-XXX-your-featureSee Project Tracking for full guidelines, PR template, and code review checklist.
This project is licensed under the Apache License 2.0 — see the LICENSE file for details.
Built with ❤️ by @algorithnicmind
If you find this project useful, consider giving it a ⭐