Skip to content

imshubham07/Draw-app

Repository files navigation

🎨 Excalidraw Clone - Collaborative Drawing App

A modern full-stack web application for real-time collaborative drawing with advanced authentication features. Built with Next.js, TypeScript, WebSockets, and PostgreSQL.

Node TypeScript Next.js Docker License

📌 Table of Contents

✨ Features

Core Features

  • 🎯 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

Authentication & Security

  • 🔐 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

User Experience

  • 🎨 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

🛠️ Tech Stack

Frontend

  • 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

Backend

  • 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

Database

  • PostgreSQL 16 - Advanced relational database
  • Prisma Client - Type-safe database client
  • Prisma Migrate - Database migration system

Authentication

  • 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

DevOps & Tools

  • 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

📁 Project Structure

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

🚀 Quick Start

Prerequisites

  • 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)

Option 1: Docker (Recommended - Fastest)

# 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.

Option 2: Local Development (Full Control)

Step 1: Clone and Install

git clone https://github.com/imshubham07/Draw-app.git
cd Excalidraw
pnpm install

Step 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
EOF

Step 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 dev

Step 5: Access the Application

Email Configuration (Important for OTP)

To enable OTP email verification, configure your email provider:

Gmail Setup

  1. Enable 2-Factor Authentication on your Google account
  2. Generate an App Password: https://myaccount.google.com/apppasswords
  3. Use the app password in .env:
    EMAIL_SERVICE=gmail
    EMAIL_USER=your-email@gmail.com
    EMAIL_PASSWORD=your-16-char-app-password

Other Email Providers

Update EMAIL_SERVICE to your provider (outlook, yahoo, etc.)

💻 Development

Install Dependencies

pnpm install

Start Dev Server

pnpm dev

Build for Production

pnpm build

Type Checking

pnpm check-types

Linting & Formatting

pnpm lint          # Run ESLint
pnpm format        # Format with Prettier

Run Specific App

pnpm dev --filter=excelidraw-frontend
pnpm dev --filter=http-backend
pnpm dev --filter=ws-backend

📋 Scripts

All 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 GUI

🐳 Docker Deployment

Quick start with Docker:

docker compose up -d --build

Services:

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-backend

See README.docker.md for complete Docker documentation.

🗄️ Database

Database Schema

The PostgreSQL database includes the following tables:

Users Table

  • id - UUID primary key
  • email - Unique email address
  • password - Bcrypt hashed password (nullable for OAuth users)
  • name - User's display name
  • photo - Profile photo URL (optional)
  • isEmailVerified - Boolean flag for email verification status
  • otp - 6-digit OTP code for verification (temporary)
  • otpExpiry - OTP expiration timestamp
  • emailVerificationToken - Token for email verification links
  • emailVerificationTokenExpiry - Token expiration timestamp
  • googleId - Google OAuth unique identifier (optional)
  • githubId - GitHub OAuth unique identifier (optional)
  • createdAt - Account creation timestamp

Rooms Table

  • id - Serial primary key
  • slug - Unique URL-friendly room identifier
  • createdAt - Room creation timestamp
  • adminId - Foreign key to Users table (room creator)

Shapes Table

  • id - UUID primary key
  • roomId - Foreign key to Rooms table
  • type - Shape type (rectangle, circle, line, etc.)
  • data - JSON data containing shape properties
  • createdAt - Shape creation timestamp

Prisma Commands

# 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 reset

Database Access

Local PostgreSQL:

psql postgresql://postgres:postgres@localhost:5432/excalidraw

Docker 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 excalidraw

Common 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

🏗️ Architecture

Monorepo Structure

  • 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

Service Architecture

┌──────────────────────────────────────────────────────────┐
│             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       │ │
                   │ └──────────────────┘ │
                   └──────────────────────┘

Data Flow

Authentication Flow:

  1. User signs up → Backend validates → Sends OTP email
  2. User verifies OTP → Backend creates JWT token
  3. Frontend stores token → Uses for authenticated requests
  4. OAuth: Redirect → Provider auth → Callback → JWT token

Drawing Flow:

  1. User draws on canvas → WebSocket emits event
  2. WS Backend broadcasts to all room members
  3. Clients update their canvases in real-time
  4. Backend persists shapes to PostgreSQL

Technology Decisions

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

🔐 Authentication

Authentication Methods

The application supports three authentication methods:

1. Email/Password with OTP Verification

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

2. Google OAuth 2.0

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:

  1. Get credentials from Google Cloud Console
  2. Add to .env:
    NEXT_PUBLIC_GOOGLE_CLIENT_ID=your-client-id

3. GitHub OAuth 2.0

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:

  1. Register OAuth App at GitHub Settings
  2. Add to .env:
    NEXT_PUBLIC_GITHUB_CLIENT_ID=your-client-id
    GITHUB_CLIENT_SECRET=your-client-secret

Security Features

  • 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

API Endpoints

Authentication:

  • POST /signup - Create new account with OTP
  • POST /signin - Login with credentials
  • POST /verify-otp - Verify OTP code
  • POST /resend-otp - Resend OTP email
  • POST /verify-email - Verify email with token
  • POST /resend-verification-email - Resend verification email
  • POST /auth/google - Google OAuth handler
  • POST /auth/github - GitHub OAuth handler

Protected Endpoints (require JWT):

  • POST /room - Create new room
  • GET /room/:slug - Get room details
  • GET /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
  1. Create a feature branch

    git checkout -b feature/amazing-feature
  2. Install dependencies

    pnpm install
  3. Make your changes

    • Follow the existing code style
    • Add TypeScript types for all new code
    • Write meaningful commit messages
  4. 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
  5. Commit and push

    git add .
    git commit -m "feat: add amazing feature"
    git push origin feature/amazing-feature
  6. Create Pull Request

    • Go to GitHub and create a PR
    • Describe your changes clearly
    • Link any related issues

Code Style Guidelines

  • 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

Commit Message Convention

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

📄 License

MIT License - feel free to use this project for personal or commercial purposes.

See LICENSE file for details.

🆘 Troubleshooting

Common Issues

Port Already in Use

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 scripts

Database Connection Failed

Problem: 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 db

OTP Emails Not Sending

Problem: OTP verification emails not arriving

Solutions:

  1. Check email credentials in .env:

    EMAIL_SERVICE=gmail
    EMAIL_USER=your-email@gmail.com
    EMAIL_PASSWORD=your-app-password  # NOT your regular password!
  2. For Gmail:

  3. Check spam folder

  4. View backend logs:

    # Local
    # Check terminal where http-backend is running
    
    # Docker
    docker compose logs -f http-backend

Node Modules Issues

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 build

Docker Issues

Problem: 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 df

OAuth Not Working

Problem: Google/GitHub OAuth fails

Solutions:

Google OAuth:

  1. Verify NEXT_PUBLIC_GOOGLE_CLIENT_ID in .env
  2. Check authorized JavaScript origins in Google Console:
  3. Check authorized redirect URIs
  4. Ensure Google+ API is enabled

GitHub OAuth:

  1. Verify credentials in .env:
    NEXT_PUBLIC_GITHUB_CLIENT_ID=your-client-id
    GITHUB_CLIENT_SECRET=your-secret
  2. Check callback URL in GitHub App settings:
  3. Ensure email scope is requested

Build Errors

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 build

Getting Help

Still stuck? Here's where to get help:

  1. Check existing documentation:

  2. Search GitHub Issues: https://github.com/imshubham07/Draw-app/issues

  3. 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

Useful Commands Reference

# 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 Docker

Happy Drawing! 🎨

Made with ❤️ by Shubham

⭐ Star this repo if you found it helpful!

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors