Skip to content

Pappyjay23/threadx

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

55 Commits
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

πŸ’¬ ThreadX

Real-time messaging β€” direct chats, group conversations, and everything in between.

🌟 Overview

ThreadX is a full-stack real-time messaging application built for seamless one-on-one and group conversations. Users sign up (or continue with Google), and immediately get access to a conversation-centric workspace: Direct chats, group rooms with admin controls, image sharing, message replies, pinned chats, and live typing indicatorsβ€”all streaming over WebSocket in real time. The app pairs a fast React SPA with a secure Express API backed by MongoDB, using JWT access tokens, httpOnly refresh cookies, automatic token refresh, and Arcjet-powered security on every endpoint.

Snapshot πŸ“Έ

Screenshot (50)

πŸ›  Tech Stack

Frontend

Backend

  • Node.js – Runtime.
  • Express 5 – REST API (/api/auth, /api/user, /api/messages).
  • TypeScript – Typed controllers, models, and middleware.
  • Socket.IO – Real-time event server (online presence, typing indicators, message broadcast).
  • MongoDB + Mongoose – User, Conversation, Message, and token persistence.
  • JWT – Short-lived access tokens; refresh tokens stored server-side and in httpOnly cookies.
  • bcrypt – Password hashing.
  • Zod – Request body validation on create/update flows.
  • Arcjet – Bot detection, shield protection, and sliding-window rate limiting on every route (@arcjet/node).
  • Cloudinary – Signed upload and storage for profile pictures and message images.
  • Google Auth Library – Server-side Google ID token verification.
  • Nodemailer + Resend – Transactional email for password-reset flows.
  • cookie-parser & cors – Cookies and cross-origin configuration for the SPA.

πŸš€ Key Features

  • Authentication – Email/password sign-up and login, plus one-tap Google OAuth. Access token stored in a cookie; refresh token in an httpOnly cookie.
  • Forgot / Reset Password – Secure email-based password reset with time-limited tokens.
  • Session resilience – Axios interceptor calls /auth/refresh on 401 and retries the original request; Socket.IO reconnects and re-authenticates transparently.
  • Direct Messaging – One-on-one conversations with a persistent conversation thread.
  • Group Chats – Create named groups with a custom avatar, add/remove members, leave, or delete the group entirely.
  • Message Replies – Reply to any message with a linked preview; scroll-to-original on click.
  • Image Sharing – Send images in chat via direct Cloudinary upload with signed URL.
  • Optimistic UI – Messages are added to the local store immediately with a temporary ID. Once the server confirms, the temp entry is swapped for the real document. On failure the temp message is rolled back and an error toast is shown.
  • Unread Counts & Mark as Read – Per-conversation unread badge that clears when the chat is opened.
  • Pin Chats – Pin important conversations to the top of the chat list (per user).
  • Real-time Typing Indicators – Live "…is typing" broadcast to all participants in a conversation.
  • Online Presence – Live online user list pushed to all connected clients over WebSocket.
  • Delete Messages – Only the sender can delete their own messages; the image is removed from Cloudinary before the document is deleted, and unread counts are reconciled across all participants.
  • Chat Deletion (soft-delete) – Deleting a direct chat sets a per-user hidden flag on the Conversation document rather than removing any data. The conversation reappears automatically if a new message is sent. Group deletion (admin only) is a hard delete β€” all messages and Cloudinary assets are purged before the conversation document is destroyed.
  • Profile Management – Upload a profile picture via Cloudinary signed upload.
  • Sound Notifications – Toggleable in-app sound on incoming messages.
  • PWA Support – Installable on desktop and mobile; service worker for offline readiness.
  • Security – Arcjet shield, bot detection, and per-IP rate limiting on auth routes (10 req/min) and general API routes (100 req/min).

πŸ“ Project Structure

threadx/
β”œβ”€β”€ backend/          # Express API, Socket.IO server
β”‚   └── src/
β”‚       β”œβ”€β”€ config/       # DB, socket, arcjet, env, cloudinary
β”‚       β”œβ”€β”€ controllers/  # auth, user, message
β”‚       β”œβ”€β”€ middlewares/  # auth, arcjet, origin, socket-auth
β”‚       β”œβ”€β”€ models/       # User, Conversation, Message, tokens
β”‚       β”œβ”€β”€ routes/       # auth, user, message
β”‚       β”œβ”€β”€ schemas/      # Zod validation schemas
β”‚       β”œβ”€β”€ template/     # Email HTML templates
β”‚       β”œβ”€β”€ utils/        # Helpers (token, email, etc.)
β”‚       └── server.ts
└── frontend/         # React + Vite SPA
    └── src/
        β”œβ”€β”€ api/          # Axios API layer (auth, user, message)
        β”œβ”€β”€ components/   # chat, navigation, shared, ui
        β”œβ”€β”€ config/       # axios instance, route config
        β”œβ”€β”€ hooks/        # Custom React hooks
        β”œβ”€β”€ pages/        # landing, auth, home, error, loading
        β”œβ”€β”€ routes/       # Route definitions & guards
        β”œβ”€β”€ schemas/      # Zod form schemas
        β”œβ”€β”€ store/        # Zustand stores (useAuthStore, useChatStore)
        β”œβ”€β”€ types/        # TypeScript interfaces
        └── utils/        # Utility functions

πŸ“‘ API Routes

Method Path Auth Description
POST /api/auth/signup No Register with email & password
POST /api/auth/login No Login with email & password
POST /api/auth/google No Login / register via Google OAuth
POST /api/auth/forgot-password No Send password-reset email
POST /api/auth/reset-password No Reset password with token
POST /api/auth/refresh No Exchange refresh cookie for new token
POST /api/auth/logout Yes Invalidate session
GET /api/auth/upload-profile-signature Yes Cloudinary signed upload params
PATCH /api/auth/update-profile Yes Update profile picture URL
GET /api/user/ Yes Get current authenticated user
GET /api/messages/contacts Yes Paginated contact list
GET /api/messages/chats Yes All conversations for current user
GET /api/messages/conversations/:id Yes Messages by conversation ID
GET /api/messages/:id Yes Messages by user ID (direct chat)
POST /api/messages/:id Yes Send a message
DELETE /api/messages/:messageId Yes Delete a message
POST /api/messages/:id/read Yes Mark conversation as read
PATCH /api/messages/:id/pin Yes Toggle pin on a chat
DELETE /api/messages/chats/:id Yes Delete entire direct chat
POST /api/messages/groups Yes Create a group conversation
PATCH /api/messages/groups/:id Yes Update group name / avatar
DELETE /api/messages/groups/:id Yes Delete group (admin only)
POST /api/messages/groups/:id/members Yes Add members to group
POST /api/messages/groups/:id/remove Yes Remove a member from group
POST /api/messages/groups/:id/leave Yes Leave a group
GET /api/messages/upload-message-signature Yes Cloudinary signed params for images
GET /api/messages/upload-group-avatar-signature Yes Cloudinary signed params for group avatar

πŸ”Œ WebSocket Events

Event Direction Description
getOnlineUsers Server β†’ Client Array of currently online user IDs
newMessage Server β†’ Client Broadcast new message to conversation recipients
typing:start Client β†’ Server User started typing in a conversation
typing:stop Client β†’ Server User stopped typing in a conversation
typing:update Server β†’ Client Typing state for a conversation participant
unreadUpdate Server β†’ Client Updated unread count for a conversation
messagesRead Server β†’ Client Conversation marked as read by a participant

πŸ’» How to Run Locally

You need Node.js and a MongoDB deployment (local or Atlas). A Cloudinary account is required for media uploads, and Arcjet for security/rate limiting.

1. Clone the repository

git clone https://github.com/Pappyjay23/threadx.git
cd threadx

2. Backend

cd backend
npm install

Create backend/.env:

# Server
PORT=5001
NODE_ENV=development

# CORS – set to your frontend origin
CLIENT_URL=http://localhost:5173

# Database
MONGODB_URI=mongodb://localhost:27017/threadx
# or your MongoDB Atlas connection string

# JWT – use long random strings in production
JWT_ACCESS_SECRET=your_access_secret
JWT_REFRESH_SECRET=your_refresh_secret
# Optional overrides (defaults: 15m access, 7d refresh)
# JWT_ACCESS_TOKEN_EXPIRES_IN=15m
# JWT_REFRESH_TOKEN_EXPIRES_IN=7d

# Google OAuth
GOOGLE_CLIENT_ID=your_google_client_id

# Cloudinary
CLOUDINARY_CLOUD_NAME=your_cloud_name
CLOUDINARY_API_KEY=your_api_key
CLOUDINARY_API_SECRET=your_api_secret

# Arcjet (https://arcjet.com)
ARCJET_KEY=your_arcjet_key

# Email (Resend or Nodemailer SMTP)
RESEND_API_KEY=your_resend_api_key

Start the API:

npm run dev

The server listens on http://localhost:5001 by default (GET /health returns a status JSON).

Production build:

npm run build
npm start

3. Frontend

Open a second terminal:

cd frontend
npm install

Create frontend/.env:

VITE_THREADX_API_URL=http://localhost:5001/api

Start the dev server:

npm run dev

Open http://localhost:5173. Make sure the backend is running first.

Production build:

npm run build
npm run preview

Monorepo Layout

Path Role
frontend/ React 19 + Vite 7 SPA (PWA)
backend/ Express 5 API, Socket.IO, MongoDB, Auth, Arcjet security

There is no root-level package.json; install and run each package separately.

Credits ✍

Implementation by Pappyjay23

About

A full-stack real-time messaging application supporting direct messages, group chats with admin controls, message replies, image sharing, and live typing indicators. Features JWT auth with Google OAuth, optimistic UI, PWA support, and Arcjet-powered security. Built with React 19, Express 5, Socket.IO, MongoDB, and Tailwind CSS.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages