A full-stack async video messaging platform for recording, transcribing, and sharing videos. Built to explore video processing, AI integration, and multi-platform development from the ground up.
- Cross-Platform Recording - Native desktop app for screen and camera capture (macOS, Windows, Linux)
- Auto-Transcription - Automatic speech-to-text using Whisper AI with SRT subtitle generation
- AI Summaries - Smart video summaries and titles powered by Mistral
- Real-Time Updates - Live upload progress and processing status via WebSockets
- Clean Dashboard - Modern Next.js web interface for managing recordings
- Instant Sharing - Generate shareable links with embedded transcripts
- Workspace Management - Organize videos into folders and workspaces
- Payment Integration - Stripe-powered subscription system
Frontend & Desktop:
- Next.js 15 - React framework with App Router
- React 19 - UI library
- Electron - Cross-platform desktop app
- TypeScript - Type safety
- Tailwind CSS - Utility-first styling
- Radix UI - Accessible component primitives
- Clerk - Authentication and user management
Backend & Infrastructure:
- Node.js - JavaScript runtime
- Express - Web framework
- Socket.io - Real-time bidirectional communication
- Prisma - Type-safe ORM
- PostgreSQL - Database
- MinIO - S3-compatible object storage
- Docker - Containerization
AI & Processing:
- Whisper - Speech-to-text transcription
- Mistral AI - Text summarization and title generation
- SRT/VTT subtitle generation
Development Tools:
- Vite - Build tool for Electron app
- TanStack Query - Data fetching and caching
- Redux Toolkit - State management
- Zod - Schema validation
- pnpm - Fast, disk space efficient package manager
- Node.js >= 16.0.0
- pnpm >= 8.0.0
- Docker and Docker Compose (for backend services)
- PostgreSQL database (provided via Docker or external)
- MinIO or S3-compatible storage (provided via Docker or external)
- Whisper API endpoint (provided via Docker or external)
- Mistral AI API key (required for AI summaries)
git clone https://github.com/techquestsdev/videmo.git
cd videmocd server
# Install dependencies with pnpm
pnpm install
# Set up environment variables
cp .env.example .env
# Edit .env with your configuration
# Start Docker services (MinIO, PostgreSQL)
pnpm docker:up
# Run the development server
pnpm dev
# Check health at http://localhost:5000/health
pnpm healthcd webapp
# Install dependencies with pnpm
pnpm install
# Set up environment variables
cp .env.example .env
# Configure Clerk, database, and API URLs
# Generate Prisma client and push schema
npx prisma generate
npx prisma db push
# Run the development server
pnpm dev
# Open http://localhost:3000cd desktop
# Install dependencies with pnpm
pnpm install
# Set up environment variables
cp .env.example .env
# Configure API endpoints and Clerk keys
# Run the development version
pnpm dev
# Build for production
pnpm build
# Build for specific platforms
pnpm build --mac
pnpm build --win
pnpm build --linuxCreate a .env file in the server/ directory:
# Server Configuration
PORT=5000
NODE_ENV=development
TEMP_DIR=/tmp
# Main API Configuration
NEXT_API_HOST=http://localhost:3000/api
ELECTRON_HOST=http://localhost:5173
# S3/MinIO Configuration
BUCKET_NAME=videmo
AWS_ENDPOINT=http://localhost:9000
AWS_REGION=local
AWS_ACCESS_KEY_ID=local
AWS_SECRET_ACCESS_KEY=locallocal
# Mistral AI Configuration (for title and summary generation)
MISTRAL_API=https://api.mistral.ai
MISTRAL_API_KEY=your-mistral-api-key-here
# Whisper Server Configuration (runs locally via docker-compose)
# The server automatically uses http://localhost:8000 for transcriptionCreate a .env file in the webapp/ directory:
# Database (Postgres)
# Format: postgres://USER:PASSWORD@HOST:PORT/DATABASE
# If you use pgbouncer or connection poolers, keep the params
DATABASE_URL="postgres://USER:PASSWORD@HOST:5432/videmo?pgbouncer=true&connection_limit=1"
# Clerk (authentication)
# - NEXT_PUBLIC... keys are safe for client-side usage
# - CLERK_SECRET_KEY must remain server-side
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY="pk_test_your_clerk_publishable_key_here"
CLERK_SECRET_KEY="sk_test_your_clerk_secret_key_here"
NEXT_PUBLIC_CLERK_SIGN_IN_FORCE_REDIRECT_URL="/auth/callback"
NEXT_PUBLIC_CLERK_SIGN_UP_FORCE_REDIRECT_URL="/auth/callback"
# Stripe
# - `STRIPE_CLIENT_SECRET` is your Stripe secret (server only)
# - `STRIPE_SUBSCRIPTION_PRICE_ID` is the price/product id used for subscriptions
STRIPE_CLIENT_SECRET="your_stripe_client_secret_here"
STRIPE_SUBSCRIPTION_PRICE_ID="your_stripe_price_id_here"
# Host / CDN URLs
# - `NEXT_PUBLIC_HOST_URL` should match your frontend origin
# - `NEXT_PUBLIC_CLOUD_FRONT_STREAM_URL` used for signed/served streams
NEXT_PUBLIC_HOST_URL="http://localhost:3000"
NEXT_PUBLIC_CLOUD_FRONT_STREAM_URL="http://localhost:9000/videmo"
# Mailer credentials (used by server for sending email)
MAILER_EMAIL="your_mailer_email_here"
MAILER_PASSWORD="your_mailer_password_here"Create a .env file in the desktop/ directory:
# Clerk Authentication
VITE_CLERK_PUBLISHABLE_KEY=pk_test_...
# API Endpoints
VITE_HOST_URL=http://localhost:3000/api
VITE_SOCKET_URL=http://localhost:5000/
VITE_APP_URL=http://localhost:5173Desktop App:
- Launch the Videmo desktop application
- Sign in with your Clerk account
- Configure camera and microphone settings
- Click "Start Recording" and select:
- Screen only
- Camera only
- Screen + Camera (picture-in-picture)
- Stop recording when finished
- Video automatically uploads to the backend with real-time progress
Web Dashboard:
- Navigate to
http://localhost:3000 - Sign in with your Clerk account
- View all recordings organized by workspace and folder
- Click any video to:
- Watch with embedded player
- Read auto-generated transcript
- View AI-powered summary
- Edit title and description
- Move to different folders
- Generate share link
- Download video or transcript
# Each video gets a shareable preview URL
https://your-domain.com/preview/{videoId}
# Share links include:
- Video player with subtitles
- Full transcript
- AI summary
- No authentication required for recipientsWorkspaces:
- Create multiple workspaces for different projects or teams
- Invite collaborators to workspaces
- Manage workspace settings and permissions
Folders:
- Organize videos within workspaces using folders
- Create nested folder structures
- Move videos between folders with drag-and-drop
videmo/
├── server/ # Express.js backend API
│ ├── src/
│ │ ├── config/ # Configuration management
│ │ ├── middleware/ # Express middleware
│ │ ├── routes/ # API route handlers
│ │ ├── services/ # Business logic layer
│ │ │ ├── ai.service.js # Mistral integration
│ │ │ ├── storage.service.js # S3/MinIO operations
│ │ │ ├── transcription.service.js # Whisper integration
│ │ │ └── video-processing.service.js
│ │ ├── sockets/ # Socket.io event handlers
│ │ └── utils/ # Helper functions
│ ├── docker-compose.yaml
│ └── server.js
│
├── webapp/ # Next.js web application
│ ├── src/
│ │ ├── app/ # Next.js App Router
│ │ │ ├── (website) # Public marketing pages
│ │ │ ├── auth/ # Authentication pages
│ │ │ ├── dashboard/ # Protected dashboard
│ │ │ ├── preview/ # Public video sharing
│ │ │ └── api/ # API routes
│ │ ├── components/
│ │ │ ├── forms/ # Form components
│ │ │ ├── global/ # Shared components
│ │ │ ├── icons/ # Custom icon components
│ │ │ └── ui/ # Radix UI components
│ │ ├── actions/ # Server actions
│ │ ├── hooks/ # Custom React hooks
│ │ ├── lib/ # Utilities and helpers
│ │ ├── redux/ # Redux Toolkit store
│ │ └── types/ # TypeScript types
│ ├── prisma/
│ │ ├── schema.prisma # Database schema
│ │ └── migrations/ # Database migrations
│ └── public/
│
└── desktop/ # Electron desktop recorder
├── electron/ # Electron main process
│ ├── main.ts # Main process entry
│ └── preload.ts # Preload script
├── src/
│ ├── components/
│ │ ├── global/ # App components
│ │ │ ├── MediaConfiguration/
│ │ │ ├── StudioTray/
│ │ │ └── Webcam/
│ │ └── ui/ # Radix UI components
│ ├── hooks/ # Custom hooks
│ ├── layouts/ # Layout components
│ ├── lib/ # Utilities (recorder logic)
│ └── schemas/ # Zod validation schemas
├── index.html # Main window
├── studio.html # Recording studio window
├── webcam.html # Webcam overlay window
└── vite.config.ts-
Recording Phase
- Desktop app captures video stream (MediaRecorder API)
- Video chunks buffered in memory
- User stops recording
-
Upload Phase
- Electron app uploads video via HTTP POST to
/api/upload - Backend receives stream and saves to MinIO/S3
- Real-time progress updates via Socket.io
- Database record created with metadata
- Electron app uploads video via HTTP POST to
-
Processing Phase
- Backend extracts audio from video
- Whisper API transcribes audio to text
- SRT subtitle file generated
- Mistral AI generates title and summary
- Status updates broadcast via WebSocket
-
Viewing Phase
- Web app fetches video metadata from database
- Video streams from MinIO/S3
- Transcript and subtitles displayed inline
- AI summary shown in sidebar
-
Sharing Phase
- User generates share link
- Public preview page renders without auth
- Video player with embedded subtitles
- Transcript and summary visible to recipient
Set up your local development environment by following the installation steps above. Use the commands below to run and test individual components.
# Backend server (Express + Socket.io)
cd server
pnpm dev # Development mode with nodemon
pnpm start # Production mode
pnpm docker:up # Start MinIO and PostgreSQL
pnpm health # Check server health
# Web application (Next.js)
cd webapp
pnpm dev # Development mode (http://localhost:3000)
pnpm build # Build for production
pnpm start # Start production server
pnpm lint # Run ESLint
# Desktop app (Electron)
cd desktop
pnpm dev # Development mode with hot reload
pnpm build # Build installers for current platform
pnpm build --mac # Build for macOS
pnpm build --win # Build for Windows
pnpm build --linux # Build for Linux# Generate Prisma client after schema changes
npx prisma generate
# Push schema changes to database (development)
npx prisma db push
# Create a new migration (production)
npx prisma migrate dev --name add_new_field
# Apply migrations
npx prisma migrate deploy
# Open Prisma Studio (database GUI)
npx prisma studio
# Reset database (warning: deletes all data)
npx prisma migrate reset# Start services for each component (needs to be in component directory)
docker-compose up -d
# View logs
docker-compose logs -f
# View specific service logs
docker-compose logs -f service_name
# Stop all services
docker-compose down
# Remove volumes (warning: deletes data)
docker-compose down -v# Build production images
docker build -t videmo-server:latest ./server
docker build -t videmo-webapp:latest ./webapp
# Run with Docker
docker run -d \
--name videmo-server \
-p 5000:5000 \
--env-file ./server/.env \
videmo-server:latest
docker run -d \
--name videmo-webapp \
-p 3000:3000 \
--env-file ./webapp/.env \
videmo-webapp:latestProblem: Upload hangs or times out
Solution: Check backend connectivity and storage configuration
# Verify server is running
curl http://localhost:5000/health
# Check MinIO is accessible
docker ps | grep minio
# Test MinIO connection
curl http://localhost:9000/minio/health/live
# Check backend logs for errors
cd server
pnpm docker:logs
# Verify S3 environment variables in server/.env
echo $S3_ENDPOINT
echo $S3_ACCESS_KEYProblem: Videos process but no transcription appears
Solution: Verify Whisper API configuration and connectivity
# Check Whisper service is running
curl http://localhost:8000/health
# Test Whisper API with sample audio
curl -X POST http://localhost:8000/transcribe \
-F "audio=@sample.wav"
# Check WHISPER_API_URL in server/.env
cat server/.env | grep WHISPER
# View backend logs for API errors
cd server
pnpm docker:logs | grep whisperProblem: Desktop app cannot reach backend API
Solution: Verify API URL and network configuration
# Verify VITE_API_URL in desktop/.env
cat desktop/.env | grep VITE_API_URL
# Check CORS settings in server
# Ensure desktop origin is allowed in server/.env:
ALLOWED_ORIGINS=http://localhost:5173
# Test WebSocket connection
wscat -c ws://localhost:5000Problem: Web app or backend cannot connect to PostgreSQL
Solution: Verify PostgreSQL is running and DATABASE_URL is correct
# Check PostgreSQL container status
docker ps | grep postgres
# Test database connection
psql "postgresql://postgres:password@localhost:5432/videmo"
# Verify DATABASE_URL format
# Should be: postgresql://USER:PASSWORD@HOST:PORT/DATABASE
echo $DATABASE_URL
# Regenerate Prisma client after schema changes
cd webapp
npx prisma generate
# Push schema to database
npx prisma db pushProblem: Authentication not working or showing errors
Solution: Verify Clerk configuration and keys
# Check Clerk publishable key is set
echo $NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY
echo $VITE_CLERK_PUBLISHABLE_KEY
# Ensure keys match between webapp and desktop
# Keys should start with: pk_test_ or pk_live_
# Verify Clerk webhook endpoints in Clerk Dashboard
# Add: https://your-domain.com/api/webhooks/clerk
# Check Clerk environment (test vs production)
# Ensure all keys are from the same environmentProblem: Cannot access uploaded videos
Solution: Verify MinIO bucket configuration
# Access MinIO console
open http://localhost:9001
# Login with credentials from docker-compose.yaml
# User: minioadmin
# Password: minioadmin
# Check if bucket exists and is accessible
# Bucket should be: videmo-uploads
# Verify bucket policy allows public read (for sharing)
# Can configure via MinIO console or mc client
# Test file upload manually
curl -X POST http://localhost:5000/api/upload?userId=test&filename=test.mp4 \
-H "Content-Type: video/mp4" \
--data-binary @test-video.mp4Problem: Build fails with dependency or TypeScript errors
Solution: Clean install and rebuild
# Remove all node_modules and lock files
make clean
# Reinstall dependencies
make install
# Clear pnpm cache if needed
pnpm store prune
# Rebuild Prisma client
cd webapp
npx prisma generate
# Check for outdated dependencies
pnpm outdatedStorage Service (src/services/storage.service.js)
- Handles S3/MinIO file operations
- Uploads, downloads, and deletes videos
- Generates pre-signed URLs for secure access
Transcription Service (src/services/transcription.service.js)
- Integrates with Whisper API
- Converts video to audio format
- Generates SRT subtitle files
- Handles error retry logic
AI Service (src/services/ai.service.js)
- Integrates with Mistral API
- Generates video titles and summaries
- Processes transcripts for key insights
Video Processing Service (src/services/video-processing.service.js)
- Orchestrates the complete processing pipeline
- Coordinates transcription and AI services
- Manages processing state and WebSocket events
- Video Upload: Chunked uploads for large files with progress tracking
- Streaming: Videos served directly from MinIO/S3 with range requests
- Caching: TanStack Query caches API responses on the client
- Lazy Loading: Video thumbnails and metadata loaded on demand
- WebSocket: Real-time updates without polling overhead
- Optimistic Updates: UI updates immediately before server confirmation
- Image Optimization: Next.js Image component with WebP/AVIF
- Authentication: Clerk handles secure user authentication and session management
- Authorization: Row-level security ensures users only access their own content
- CORS: Configured to allow only trusted origins
- API Keys: Stored in environment variables, never committed to version control
- S3 Pre-signed URLs: Time-limited secure access to private videos
- Input Validation: Zod schemas validate all user input
- SQL Injection: Prisma protects against SQL injection attacks
- XSS Protection: React escapes user-generated content by default
Videmo is a functional side project built for learning and skill development. It successfully demonstrates:
- End-to-end video processing pipeline: From capture to transcription to AI enhancement
- Multi-platform development: Coordinated web and desktop experiences
- Real-time communication: WebSocket integration for live updates
- AI integration: Practical application of speech-to-text and language models
- Modern full-stack architecture: Type-safe APIs, state management, and authentication
Current State: Feature-complete for core video recording, processing, and sharing workflows. Intentionally maintained as a portfolio/learning project rather than a production-ready commercial product.
Potential areas for expansion:
- Video editing capabilities (trim, crop, annotations)
- Team collaboration features (comments, mentions)
- Advanced analytics (view counts, engagement metrics)
- Mobile app (React Native)
- Video compression and format conversion
- Live streaming support
- Integrations (Slack, Discord, Notion)
- Advanced search (full-text search in transcripts)
This is a personal learning project, but feedback and suggestions are welcome!
Ways to Contribute:
- Report bugs or issues
- Suggest new features
- Improve documentation
- Share use cases or ideas
Please open an issue for discussion before significant work.
This project is licensed under the GNU GPLv3 License - see the LICENSE file for details.
- Loom - Inspiration for the project concept
- Whisper - Speech-to-text technology
- Mistral AI - Text generation and summarization
- Clerk - Authentication infrastructure
- Vercel - Next.js development and hosting
- Electron - Cross-platform desktop framework
- WebProdigies - Video reference architecture
- Next.js Documentation - React framework
- Electron Documentation - Desktop app framework
- Prisma Documentation - Database ORM
- Socket.io Documentation - Real-time communication
- Clerk Documentation - Authentication
- TanStack Query Documentation - Data fetching
- Radix UI Documentation - UI components
- Cap - Async video messaging tool
- Loom - Professional async video platform
- Screen Studio - Screen recording tool