Skip to content

Repository files navigation

Tars Chat — Real-time Messaging App

A production-quality real-time chat application built with Next.js, TypeScript, Convex, and Clerk.

Tech Stack

Layer Technology
Frontend Next.js 14 (App Router) + TypeScript
Styling Tailwind CSS + shadcn/ui
Backend / DB Convex (serverless, real-time)
Auth Clerk
Deployment Vercel

Local Setup

1. Clone and install

git clone https://github.com/YOUR_USERNAME/tars-chat
cd tars-chat
npm install

2. Set up Clerk

  1. Create a free account at clerk.com
  2. Create a new application
  3. In JWT Templates, create a new template named convex
  4. Copy your API keys to .env.local

3. Set up Convex

npx convex dev

This will:

  • Create a Convex project (or link an existing one)
  • Generate the convex/_generated/ folder
  • Start watching for schema/function changes

In the Convex dashboard, go to Settings → Environment Variables and add:

CLERK_JWT_ISSUER_DOMAIN = https://your-app.clerk.accounts.dev

4. Configure environment variables

cp .env.local.example .env.local
# Fill in your Convex URL, Clerk keys, and Clerk JWT issuer domain

5. Run the app

# Terminal 1: Convex dev server
npx convex dev

# Terminal 2: Next.js dev server
npm run dev

Visit http://localhost:3000


Architecture Overview

Schema Design

users           ← Synced from Clerk on login
conversations   ← A chat channel (DM or group)
members         ← Join table: user ↔ conversation + lastReadTime
messages        ← Content, soft-deletable
presence        ← Online/offline per user
typing          ← Ephemeral typing indicators

Key design decisions:

  • Join table for conversations: Allows group chat extension without schema changes
  • Denormalized lastMessage on conversation: Avoids N+1 queries for sidebar preview
  • Soft delete for messages: Preserves conversation history context
  • Both isOnline + lastSeen for presence: Handles browser crashes gracefully
  • Typed indexes on every foreign key: All queries use indexes, no full table scans

Real-time Architecture

Convex's useQuery hook creates a reactive subscription. When data changes:

  1. Convex server detects the change
  2. Pushes the diff to all subscribed clients over WebSocket
  3. React re-renders automatically

No manual WebSocket setup, no polling.

Component Tree

app/layout.tsx          (ClerkProvider + ConvexProvider)
  app/chat/layout.tsx   (user sync + presence setup)
    Sidebar
      UserSearch        ← search + start DM
      ConversationList  ← all conversations with unread badges
    app/chat/page.tsx   ← "select a conversation" empty state
    app/chat/[id]/page.tsx
      ChatHeader        ← name + online status + back button
      MessageList       ← smart scroll + date dividers
        MessageItem     ← bubble + delete + timestamp
        TypingIndicator ← "Alex is typing..."
      MessageInput      ← send + typing notifications

Features Implemented

  • Authentication (Clerk: email + social login)
  • User sync to Convex on login
  • User list + real-time search
  • One-on-one DMs (get-or-create pattern)
  • Real-time messages via Convex subscriptions
  • Sidebar with conversation previews
  • Smart timestamp formatting (time / date+time / date+year)
  • Date dividers in message history
  • Empty states everywhere
  • Responsive layout (mobile sidebar / desktop split)
  • Online/offline presence with heartbeat
  • Typing indicators with debounce + auto-clear
  • Unread message count badges
  • Marks-as-read on conversation open
  • Smart auto-scroll with "↓ New messages" button
  • Soft-delete messages ("This message was deleted")
  • Skeleton loaders

Deployment Checklist (Vercel)

Before deploying:

  • npx convex deploy — deploys your Convex functions to production
  • In Convex dashboard, add CLERK_JWT_ISSUER_DOMAIN env var for production
  • In Clerk dashboard, add your Vercel domain to Allowed Origins

In Vercel:

  1. Import GitHub repo at vercel.com/new
  2. Add all environment variables from .env.local:
    • NEXT_PUBLIC_CONVEX_URL (use production URL from npx convex deploy output)
    • NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY
    • CLERK_SECRET_KEY
    • NEXT_PUBLIC_CLERK_SIGN_IN_URL = /sign-in
    • NEXT_PUBLIC_CLERK_SIGN_UP_URL = /sign-up
    • NEXT_PUBLIC_CLERK_AFTER_SIGN_IN_URL = /chat
    • NEXT_PUBLIC_CLERK_AFTER_SIGN_UP_URL = /chat
  3. Deploy

After deploying:

  • Test sign up with a new account
  • Test DM flow end-to-end
  • Test real-time with two browser tabs
  • Test on mobile viewport
  • Verify online/offline status updates

About

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages