A full-stack social media platform with real-time messaging, audio/video calling, stories, push notifications, and PWA support.
Live: https://nexus-ezh1.onrender.com
- Create, like, save, and comment on posts
- Image upload support
- Infinite scroll feed from followed users
- Explore page to discover new content and users
- 24-hour expiring stories with image support
- Story view tracking and like reactions
- Horizontal story bar with auto-advance
- Public profiles with follower/following counts
- Avatar upload and bio editing
- Follow/unfollow with live count updates via Socket.io
- Profile search by username or name
- Real-time 1-on-1 conversations via Socket.io
- Text, image, audio, and file messages
- Typing indicators and read receipts
- Unread badge counts
- Optimistic message sends (instant UI, confirmed by server)
- WebRTC peer-to-peer audio and video calls
- Inline call overlay (no separate window)
- Incoming call modal with accept/reject
- Busy signal when recipient is already in a call
- Instant reject/end with decline sound feedback
- Reliable signaling via module-level event bus — no dropped events on mount
- Real-time in-app notifications for likes, comments, follows, mentions
- Notification count badge in nav
- Mark all as read
- Web Push via VAPID — works when the browser is backgrounded or closed
- Notifications for new messages and incoming calls
- Call push:
requireInteraction: true, 45s TTL,urgency: high - Message push:
urgency: high, 1h TTL - App-focused tab detection — skips notification if tab is already visible (except calls)
- Re-subscribe logic before expiry (7-day window)
- Email + password sign-up and login
- OAuth (Google, GitHub) via Supabase
- Profile auto-created on first sign-in (handles
INITIAL_SESSION,SIGNED_IN, OAuth callback) - Password reset flow via email
- Installable on desktop and mobile
- Service worker with offline cache (
nexus-v2) SKIP_WAITINGfor instant SW updates
Browser
├── Next.js 15 App Router (React 19)
│ ├── Server Components — data fetching, SEO
│ ├── Client Components — interactive UI (Zustand, TanStack Query)
│ └── API Routes — REST endpoints
│
├── Socket.io client — real-time events
└── Service Worker (public/sw.js) — push + offline cache
Server (server.ts via tsx)
├── Next.js request handler
├── Socket.io server
│ ├── Rooms: user:{id} (personal), conversation:{id} (shared)
│ ├── Presence tracking
│ └── WebRTC signaling relay
└── Redis adapter — multi-instance Socket.io scaling
Supabase
├── PostgreSQL — all persistent data
├── Row Level Security — per-user data isolation
├── Auth — email + OAuth sessions
└── Storage — media uploads
Render — deployment platform
| Layer | Tool | Purpose |
|---|---|---|
| Server state | TanStack Query | API data caching, background refetch |
| Real-time state | Zustand | Messages, notifications, call state, auth |
| WebRTC signaling | callEvents.ts singleton |
Event bus survives React re-renders, buffers events before CallOverlay mounts |
| Table | Description |
|---|---|
profiles |
User profiles, bio, avatar, follower counts |
posts |
Feed posts with media |
post_likes / post_saves |
Many-to-many engagement |
comments |
Nested post comments |
follows |
Follow graph |
conversations + conversation_participants |
DM threads |
messages |
Chat messages with type (text/image/audio/file) |
stories + story_views + story_likes |
Ephemeral stories |
notifications |
Activity notifications |
push_subscriptions |
Web Push endpoint storage |
| Category | Library |
|---|---|
| Framework | Next.js 15.3.3 |
| UI | React 19 |
| Styling | Tailwind CSS |
| Components | Radix UI |
| Animation | Framer Motion 11 |
| Icons | FontAwesome, Lucide |
| Real-time | Socket.io 4.8.1 |
| Database | Supabase (PostgreSQL) |
| Auth | Supabase Auth |
| Server state | TanStack Query 5 |
| Client state | Zustand 5 |
| Push | web-push (VAPID) |
| Resend | |
| Cache/Scale | Redis (Socket.io adapter) |
| Deployment | Render |
git clone https://github.com/ranjanpalai69/nexus.git
cd nexus
npm installnpx web-push generate-vapid-keysSave the output — you'll need both keys.
Create a .env.local file in the project root:
# Supabase
NEXT_PUBLIC_SUPABASE_URL=https://your-project.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key
SUPABASE_SERVICE_ROLE_KEY=your-service-role-key
# App URL (used for redirect URLs and push notifications)
NEXT_PUBLIC_APP_URL=http://localhost:3000
# Redis (for Socket.io multi-instance adapter)
REDIS_URL=redis://localhost:6379
# Web Push (VAPID)
NEXT_PUBLIC_VAPID_PUBLIC_KEY=your-vapid-public-key
VAPID_PRIVATE_KEY=your-vapid-private-key
VAPID_EMAIL=mailto:your@email.comIn the Supabase SQL Editor, run each migration file in order:
supabase/migrations/001_initial_schema.sql
supabase/migrations/002_stories.sql
supabase/migrations/003_notifications.sql
supabase/migrations/004_calls.sql
supabase/migrations/005_last_sender.sql
supabase/migrations/006_push_subscriptions.sql
npm run dev
# or directly:
tsx server.tsOpen http://localhost:3000.
- Create a new Web Service on Render pointing to this repo
- Set Build Command:
npm run build - Set Start Command:
NODE_ENV=production tsx server.ts - Add all environment variables from
.env.localin the Render dashboard (replacelocalhost:3000with your Render URL forNEXT_PUBLIC_APP_URL) - Run the 6 SQL migrations in your production Supabase project
NEXT_PUBLIC_SUPABASE_URL
NEXT_PUBLIC_SUPABASE_ANON_KEY
SUPABASE_SERVICE_ROLE_KEY
NEXT_PUBLIC_APP_URL
REDIS_URL
NEXT_PUBLIC_VAPID_PUBLIC_KEY
VAPID_PRIVATE_KEY
VAPID_EMAIL
npm run dev # Development server (tsx server.ts + Next.js HMR)
npm run build # Production build
npm start # Production server
npm run lint # ESLintContributions are welcome.
- Fork the repo and create a branch from
main - Make your changes with clear, focused commits
- Ensure the app builds without TypeScript errors (
npm run build) - Open a pull request describing what you changed and why
For bugs, open an issue with steps to reproduce. For features, open an issue first to discuss the approach before building.
MIT