A modern full-stack web application for real-time collaborative drawing with advanced authentication features. Built with Next.js, TypeScript, WebSockets, and PostgreSQL.
- Features
- Tech Stack
- Project Structure
- Quick Start
- Development
- Scripts
- Docker Deployment
- Database
- Architecture
- Authentication
- Contributing
- Troubleshooting
- 🎯 Real-time Collaborative Drawing - Multiple users can draw simultaneously with WebSocket synchronization
- 💾 Persistent Storage - All drawings automatically saved to PostgreSQL database
- 📱 Responsive UI - Beautiful, modern interface with Tailwind CSS that works on all devices
- 🚀 Monorepo Architecture - Organized with pnpm workspaces and Turbo for optimal development
- 🐳 Docker Ready - Fully containerized with docker-compose for easy deployment
- 📝 Type Safe - 100% TypeScript codebase with strict type checking
- ⚡ Fast Builds - Optimized with Turbo caching and incremental builds
- 🔐 Email/Password Authentication - Secure JWT-based authentication with bcrypt password hashing
- 📧 OTP Email Verification - 6-digit OTP sent via email for account verification
- 🔗 OAuth Integration - Sign in with Google or GitHub for seamless authentication
- ✅ Email Verification System - Token-based email verification with expiration
- 🔒 Protected Routes - Middleware-based route protection for authenticated users
- 🛡️ Session Management - Secure JWT token management with localStorage
- 🎨 Infinite Canvas - Draw without boundaries on an unlimited canvas
- 🖌️ Drawing Tools - Rectangles, circles, lines, and freehand drawing
- 👥 Room-based Collaboration - Create rooms with custom slugs for team collaboration
- 📊 Dashboard - User dashboard to view and manage all your rooms
- 🌐 Social OAuth - Quick sign-in with Google and GitHub accounts
- 💌 Email Notifications - Automated email system for OTPs and verifications
- Next.js 15.5 - React framework with App Router and SSR
- React 19 - Latest UI library with concurrent features
- TypeScript 5.3 - Static type checking and IntelliSense
- Tailwind CSS 3.4 - Utility-first CSS framework for styling
- Lucide React - Beautiful icon library
- Socket.io Client - WebSocket communication for real-time features
- Node.js 20 - JavaScript runtime environment
- Express.js 4.x - Fast, minimalist web framework
- WebSocket (ws) - Real-time bidirectional communication
- JWT (jsonwebtoken) - Secure authentication tokens
- bcrypt - Password hashing with salt rounds
- Prisma 5.x - Next-generation TypeScript ORM
- Nodemailer - Email sending for OTP and verifications
- PostgreSQL 16 - Advanced relational database
- Prisma Client - Type-safe database client
- Prisma Migrate - Database migration system
- JWT Authentication - Stateless token-based auth
- OAuth 2.0 - Google and GitHub social login
- OTP System - 6-digit email verification codes
- Email Verification - Token-based email confirmation
- Docker & Docker Compose - Container orchestration
- pnpm 9.0+ - Fast, disk space efficient package manager
- Turbo - High-performance monorepo build system
- ESLint & Prettier - Code linting and formatting
- TypeScript Config - Shared TypeScript configurations
Excalidraw/
├── apps/
│ ├── excelidraw-frontend/ # Next.js 15 React app
│ │ ├── app/ # App directory structure
│ │ ├── Components/ # React components
│ │ ├── public/ # Static assets
│ │ └── package.json
│ ├── http-backend/ # Express REST API
│ │ ├── src/
│ │ │ ├── index.ts # Server entry point
│ │ │ └── middleware.ts # Custom middleware
│ │ └── package.json
│ └── ws-backend/ # WebSocket server
│ ├── src/
│ │ └── index.ts # WS server entry
│ └── package.json
├── packages/
│ ├── db/ # Prisma ORM & migrations
│ │ ├── prisma/
│ │ │ ├── schema.prisma # Database schema
│ │ │ └── migrations/ # DB migrations
│ │ └── package.json
│ ├── common/ # Shared TypeScript types
│ ├── backend-common/ # Backend utilities
│ ├── ui/ # Shared React components
│ ├── typescript-config/ # Shared tsconfig
│ └── eslint-config/ # Shared ESLint config
├── docker-compose.yml # Service orchestration
├── pnpm-workspace.yaml # Workspace config
├── turbo.json # Build configuration
├── package.json # Root package
└── README.md # This file
- Node.js 18+ (Download)
- pnpm 9.0+
npm install -g pnpm@9.0.0
- PostgreSQL 16+ (for local development) or use Docker
- Docker & Docker Compose (recommended for easiest setup)
# 1. Clone the repository
git clone https://github.com/imshubham07/Draw-app.git
cd Excalidraw
# 2. Create environment file (optional - has defaults)
cp .env.example .env
# Edit .env with your EMAIL_USER and EMAIL_PASSWORD for OTP emails
# 3. Start all services with Docker
docker compose up -d --build
# 4. Access the application
# Frontend: http://localhost:3000
# API: http://localhost:3001
# WebSocket: ws://localhost:8080
# Database: localhost:5433 (note: 5433, not 5432)That's it! The application is now running with all services.
Step 1: Clone and Install
git clone https://github.com/imshubham07/Draw-app.git
cd Excalidraw
pnpm installStep 2: Configure Environment
# Create .env in project root
cat > .env << EOF
# Database
DATABASE_URL=postgresql://postgres:postgres@localhost:5432/excalidraw
# JWT Secret (change in production)
JWT_SECRET=your-super-secret-jwt-key-change-this
# Frontend URL
FRONTEND_URL=http://localhost:3000
NEXT_PUBLIC_HTTP_BACKEND=http://localhost:3001
NEXT_PUBLIC_WS_URL=ws://localhost:8080
# Email Configuration (for OTP)
EMAIL_SERVICE=gmail
EMAIL_USER=your-email@gmail.com
EMAIL_PASSWORD=your-app-specific-password
# OAuth (optional - for social login)
NEXT_PUBLIC_GOOGLE_CLIENT_ID=your-google-client-id
NEXT_PUBLIC_GITHUB_CLIENT_ID=your-github-client-id
GITHUB_CLIENT_SECRET=your-github-client-secret
EOFStep 3: Setup Database
# Make sure PostgreSQL is running on port 5432
cd packages/db
npx prisma migrate dev
npx prisma generate
cd ../..Step 4: Start Development Servers
# This starts all services concurrently:
# - Frontend on :3000
# - HTTP Backend on :3001
# - WebSocket Backend on :8080
pnpm devStep 5: Access the Application
- Frontend: http://localhost:3000
- HTTP API: http://localhost:3001
- WebSocket: ws://localhost:8080
To enable OTP email verification, configure your email provider:
- Enable 2-Factor Authentication on your Google account
- Generate an App Password: https://myaccount.google.com/apppasswords
- Use the app password in
.env:EMAIL_SERVICE=gmail EMAIL_USER=your-email@gmail.com EMAIL_PASSWORD=your-16-char-app-password
Update EMAIL_SERVICE to your provider (outlook, yahoo, etc.)
pnpm installpnpm devpnpm buildpnpm check-typespnpm lint # Run ESLint
pnpm format # Format with Prettierpnpm dev --filter=excelidraw-frontend
pnpm dev --filter=http-backend
pnpm dev --filter=ws-backendAll scripts run via pnpm in the root directory:
| Script | Purpose |
|---|---|
pnpm dev |
Start all services in dev mode |
pnpm build |
Build all apps & packages for production |
pnpm lint |
Run ESLint on all code |
pnpm format |
Format code with Prettier |
pnpm check-types |
TypeScript type checking |
Database scripts (from packages/db):
npx prisma migrate dev # Create & apply migrations
npx prisma generate # Generate Prisma client
npx prisma studio # Open database GUIQuick start with Docker:
docker compose up -d --buildServices:
- Frontend: http://localhost:3000
- API: http://localhost:3001
- WebSocket: ws://localhost:8080
- Database: localhost:5432
Useful Docker Commands:
# View logs
docker compose logs -f http-backend
docker compose logs -f ws-backend
# Stop services
docker compose down
# Rebuild specific service
docker compose up -d --build http-backendSee README.docker.md for complete Docker documentation.
The PostgreSQL database includes the following tables:
id- UUID primary keyemail- Unique email addresspassword- Bcrypt hashed password (nullable for OAuth users)name- User's display namephoto- Profile photo URL (optional)isEmailVerified- Boolean flag for email verification statusotp- 6-digit OTP code for verification (temporary)otpExpiry- OTP expiration timestampemailVerificationToken- Token for email verification linksemailVerificationTokenExpiry- Token expiration timestampgoogleId- Google OAuth unique identifier (optional)githubId- GitHub OAuth unique identifier (optional)createdAt- Account creation timestamp
id- Serial primary keyslug- Unique URL-friendly room identifiercreatedAt- Room creation timestampadminId- Foreign key to Users table (room creator)
id- UUID primary keyroomId- Foreign key to Rooms tabletype- Shape type (rectangle, circle, line, etc.)data- JSON data containing shape propertiescreatedAt- Shape creation timestamp
# Navigate to database package
cd packages/db
# Create a new migration
npx prisma migrate dev --name migration_name
# Apply migrations (production)
npx prisma migrate deploy
# Generate Prisma Client
npx prisma generate
# Open Prisma Studio (database GUI)
npx prisma studio
# Reset database (WARNING: deletes all data)
npx prisma migrate resetLocal PostgreSQL:
psql postgresql://postgres:postgres@localhost:5432/excalidrawDocker Database:
# Connect to database (note: use port 5433 from host)
docker compose exec db psql -U postgres -d excalidraw
# Or from host machine
psql -h localhost -p 5433 -U postgres -d excalidrawCommon SQL Commands:
-- List all tables
\dt
-- Describe a table
\d users
-- Query users
SELECT id, email, name, "isEmailVerified" FROM users;
-- Count rooms
SELECT COUNT(*) FROM rooms;
-- Exit
\q- pnpm workspaces - Efficient dependency management with workspace protocol
- Turbo - Intelligent build caching and parallel execution
- Shared packages - Common code reduces duplication (types, configs, utilities)
- Independent deployability - Each app can be deployed separately
┌──────────────────────────────────────────────────────────┐
│ Next.js Frontend (Port 3000) │
│ ┌────────────────────────────────────────────────────┐ │
│ │ • User Interface with Tailwind CSS │ │
│ │ • Drawing Canvas Component │ │
│ │ • Authentication Pages (Sign In/Up, OTP, OAuth) │ │
│ │ • Dashboard & Room Management │ │
│ │ • Real-time Sync via WebSocket Client │ │
│ └────────────────────────────────────────────────────┘ │
└──────────────────┬──────────────────┬────────────────────┘
│ │
┌──────────▼────────┐ ┌─────▼──────────┐
│ HTTP Backend │ │ WebSocket │
│ (Port 3001) │ │ (Port 8080) │
│ ┌───────────────┐ │ │ ┌────────────┐ │
│ │ • REST API │ │ │ │ • Real-time│ │
│ │ • JWT Auth │ │ │ │ • Drawing │ │
│ │ • OTP System │ │ │ │ • Sync │ │
│ │ • OAuth │ │ │ │ • Broadcast│ │
│ │ • Email Send │ │ │ │ • Rooms │ │
│ └───────────────┘ │ │ └────────────┘ │
└──────────┬────────┘ └────────┬───────┘
│ │
└──────────┬──────────┘
│
┌──────────▼───────────┐
│ PostgreSQL 16 │
│ (Port 5432/5433) │
│ ┌──────────────────┐ │
│ │ • Users │ │
│ │ • Rooms │ │
│ │ • Shapes │ │
│ │ • Sessions │ │
│ └──────────────────┘ │
└──────────────────────┘
Authentication Flow:
- User signs up → Backend validates → Sends OTP email
- User verifies OTP → Backend creates JWT token
- Frontend stores token → Uses for authenticated requests
- OAuth: Redirect → Provider auth → Callback → JWT token
Drawing Flow:
- User draws on canvas → WebSocket emits event
- WS Backend broadcasts to all room members
- Clients update their canvases in real-time
- Backend persists shapes to PostgreSQL
Why Monorepo?
- Shared TypeScript types across frontend/backend
- Unified dependency management
- Atomic commits across multiple packages
- Easier refactoring and code reuse
Why pnpm?
- 3x faster than npm
- Saves disk space with content-addressable storage
- Strict dependency resolution prevents phantom dependencies
Why Turbo?
- Intelligent caching speeds up builds
- Parallel task execution
- Remote caching for CI/CD
Why Prisma?
- Type-safe database queries
- Auto-generated TypeScript types
- Easy migrations with version control
- Excellent DX with Prisma Studio
The application supports three authentication methods:
Sign Up Flow:
User → Enter Email/Password/Name → Submit
↓
Backend → Validate Input → Hash Password → Generate 6-digit OTP
↓
Email Service → Send OTP to User Email (10-min expiry)
↓
User → Enter OTP → Verify
↓
Backend → Validate OTP → Mark Email Verified → Return JWT Token
↓
User → Redirected to Dashboard
Sign In Flow:
User → Enter Email/Password → Submit
↓
Backend → Validate Credentials → Check Email Verified
↓
Backend → Generate JWT Token → Return to User
↓
User → Redirected to Dashboard
User → Click "Sign in with Google" Button
↓
Redirect to Google Auth → User Approves
↓
Google → Returns ID Token
↓
Backend → Verify Google Token → Get User Info
↓
Backend → Create/Link Account → Generate JWT
↓
User → Redirected to Dashboard
Setup:
- Get credentials from Google Cloud Console
- Add to
.env:NEXT_PUBLIC_GOOGLE_CLIENT_ID=your-client-id
User → Click "Continue with GitHub" Button
↓
Redirect to GitHub → User Authorizes
↓
GitHub → Returns Authorization Code
↓
Backend → Exchange Code for Access Token
↓
Backend → Fetch User Info from GitHub API
↓
Backend → Create/Link Account → Generate JWT
↓
User → Redirected to Dashboard
Setup:
- Register OAuth App at GitHub Settings
- Add to
.env:NEXT_PUBLIC_GITHUB_CLIENT_ID=your-client-id GITHUB_CLIENT_SECRET=your-client-secret
- Password Hashing: bcrypt with 10 salt rounds
- JWT Tokens: Signed with secret key, stored in localStorage
- OTP Expiration: 10-minute validity window
- Email Verification: Required before account access
- Rate Limiting: Prevent brute force attacks (TODO)
- HTTPS: Recommended for production
- CORS: Configured for frontend origin
Authentication:
POST /signup- Create new account with OTPPOST /signin- Login with credentialsPOST /verify-otp- Verify OTP codePOST /resend-otp- Resend OTP emailPOST /verify-email- Verify email with tokenPOST /resend-verification-email- Resend verification emailPOST /auth/google- Google OAuth handlerPOST /auth/github- GitHub OAuth handler
Protected Endpoints (require JWT):
POST /room- Create new roomGET /room/:slug- Get room detailsGET /room/:slug/shapes- Get all shapes in room
See DEVELOPMENT.md for complete API documentation. │ - Real-time Sync via WebSocket │ └──────────────┬──────────────────────┘ │ ┌─────────┴─────────┐ │ │ ┌────▼────────┐ ┌────▼────────┐ │ HTTP API │ │ WebSocket │ │ (3001) │ │ (8080) │ │ - Auth │ │ - Real-time │ │ - CRUD │ │ - Drawing │ │ - JWT │ │ - Sync │ └────┬────────┘ └────┬────────┘ │ │ └─────────┬─────────┘ │ ┌──────▼──────┐ │ PostgreSQL │ │ (5432) │ │ - Users │ │ - Drawings │ └──────────────┘
## 🤝 Contributing
We welcome contributions! Here's how to get started:
### Development Workflow
1. **Fork the repository**
```bash
# Click "Fork" on GitHub, then clone your fork
git clone https://github.com/YOUR_USERNAME/Draw-app.git
cd Draw-app
-
Create a feature branch
git checkout -b feature/amazing-feature
-
Install dependencies
pnpm install
-
Make your changes
- Follow the existing code style
- Add TypeScript types for all new code
- Write meaningful commit messages
-
Run quality checks
pnpm lint # Check for linting errors pnpm format # Format code with Prettier pnpm check-types # TypeScript type checking pnpm build # Ensure everything builds
-
Commit and push
git add . git commit -m "feat: add amazing feature" git push origin feature/amazing-feature
-
Create Pull Request
- Go to GitHub and create a PR
- Describe your changes clearly
- Link any related issues
- TypeScript: Use strict types, avoid
any - Components: Use functional components with hooks
- Naming: camelCase for variables, PascalCase for components
- Imports: Group by external → internal → relative
- Comments: Write clear comments for complex logic
Follow Conventional Commits:
feat: add OAuth login support
fix: resolve websocket connection issue
docs: update authentication guide
style: format code with prettier
refactor: simplify user validation logic
test: add unit tests for auth flow
chore: update dependencies
MIT License - feel free to use this project for personal or commercial purposes.
See LICENSE file for details.
Problem: Error: listen EADDRINUSE: address already in use :::3000
Solutions:
# Find and kill process on port 3000 (Linux/Mac)
lsof -i :3000 | grep LISTEN | awk '{print $2}' | xargs kill -9
# Windows
netstat -ano | findstr :3000
taskkill /PID <PID> /F
# Or change ports in package.json dev scriptsProblem: Can't reach database server at localhost:5432
Solutions:
# Check if PostgreSQL is running
sudo systemctl status postgresql # Linux
brew services list # Mac
# Start PostgreSQL
sudo systemctl start postgresql # Linux
brew services start postgresql # Mac
# Verify connection
psql postgresql://postgres:postgres@localhost:5432/excalidraw
# Check Docker database
docker compose ps db
docker compose logs dbProblem: OTP verification emails not arriving
Solutions:
-
Check email credentials in
.env:EMAIL_SERVICE=gmail EMAIL_USER=your-email@gmail.com EMAIL_PASSWORD=your-app-password # NOT your regular password!
-
For Gmail:
- Enable 2FA
- Generate App Password: https://myaccount.google.com/apppasswords
- Use the 16-character app password
-
Check spam folder
-
View backend logs:
# Local # Check terminal where http-backend is running # Docker docker compose logs -f http-backend
Problem: Module resolution errors or dependency conflicts
Solutions:
# Clean install
rm -rf node_modules packages/*/node_modules apps/*/node_modules
pnpm store prune
pnpm install
# Clear turbo cache
rm -rf .turbo
# Rebuild everything
pnpm buildProblem: Containers won't start or keep restarting
Solutions:
# Check container status
docker compose ps
# View logs for failing service
docker compose logs <service-name>
# Remove everything and start fresh
docker compose down -v
docker system prune -a
docker compose up -d --build
# Check disk space
docker system dfProblem: Google/GitHub OAuth fails
Solutions:
Google OAuth:
- Verify
NEXT_PUBLIC_GOOGLE_CLIENT_IDin.env - Check authorized JavaScript origins in Google Console:
- Check authorized redirect URIs
- Ensure Google+ API is enabled
GitHub OAuth:
- Verify credentials in
.env:NEXT_PUBLIC_GITHUB_CLIENT_ID=your-client-id GITHUB_CLIENT_SECRET=your-secret
- Check callback URL in GitHub App settings:
- Ensure email scope is requested
Problem: TypeScript or build errors
Solutions:
# Regenerate Prisma client
cd packages/db
npx prisma generate
cd ../..
# Check TypeScript
pnpm check-types
# Clean and rebuild
rm -rf .turbo dist .next
pnpm buildStill stuck? Here's where to get help:
-
Check existing documentation:
- README.docker.md - Docker-specific issues
- DEVELOPMENT.md - API and development details
-
Search GitHub Issues: https://github.com/imshubham07/Draw-app/issues
-
Create a new issue: Provide:
- Operating system and version
- Node.js and pnpm versions
- Complete error message
- Steps to reproduce
- What you've already tried
# Development
pnpm dev # Start all services
pnpm build # Build for production
pnpm lint # Run ESLint
pnpm format # Format with Prettier
pnpm check-types # TypeScript checking
# Database
cd packages/db
npx prisma studio # Open database GUI
npx prisma migrate dev # Create migration
npx prisma generate # Generate client
# Docker
docker compose up -d # Start services
docker compose down # Stop services
docker compose logs -f # Follow logs
docker compose ps # Check status
docker compose restart # Restart all
# Troubleshooting
pnpm store prune # Clean pnpm cache
rm -rf node_modules # Remove dependencies
pnpm install # Reinstall
docker system prune -a # Clean DockerHappy Drawing! 🎨
Made with ❤️ by Shubham
⭐ Star this repo if you found it helpful!