Direct messages with typing indicators and read receipts, a shared post feed, profiles and follows.
SocialJavaScript · CSSGitHub @vasug369OnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
No updates detected yet. GitHub releases will appear here.
our social media site
Translation pending
Loading the full README.
Read the full README ↗A social platform combining microblogging with real-time messaging, built with React 19 and Node.js/Express 5.
| Layer | Technology |
|---|---|
| Frontend | React 19, Vite 6, Tailwind CSS v4, React Router v7, Axios, Socket.io-client |
| Backend | Node.js, Express 5, Mongoose 8, JWT, Socket.io, Cloudinary, Nodemailer |
| Validation | Zod (every endpoint) |
| Testing | Vitest + Supertest + mongodb-memory-server |
| Database | MongoDB Atlas |
| Deployment | Frontend: Vercel (www.chattrix.online) · Backend: AWS EC2 + pm2 (api.chattrix.online) |
chattrix/
├── backend/
│ ├── src/
│ │ ├── server.js # Entry point — the only file that binds a port
│ │ ├── app.js # Express app, middleware chain, route mounting
│ │ ├── config/ # env (validated), DB, Cloudinary, Nodemailer
│ │ ├── models/ # Mongoose schemas
│ │ ├── controllers/ # HTTP layer: read request, send response
│ │ ├── services/ # Business logic; returns values, throws AppError
│ │ ├── middlewares/ # auth, validate, errorHandler, rateLimiters
│ │ ├── validation/ # Zod schemas per resource
│ │ ├── realtime/ # Socket.io registry (decoupled from server.js)
│ │ ├── routes/ # Route definitions
│ │ └── utils/ # AppError, asyncHandler, otp, sanitize
│ ├── tests/ # Integration suites
│ ├── .env.example
│ └── package.json
├── frontend/
│ ├── src/
│ │ ├── App.jsx # Router + providers
│ │ ├── index.css # "Aurora Glass" design system
│ │ ├── lib/api.js # The single axios instance
│ │ ├── context/ # AuthContext, SocketContext
│ │ └── components/
│ │ └── ui/ # Glass primitives, Aurora background
│ ├── .env.example
│ └── package.json
├── .github/ # Deploy workflow, PR and issue templates
├── CLAUDE.md # Rules for AI-assisted work
├── CONTRIBUTING.md # Setup, workflow, code rules
└── SECURITY.md # Vulnerability reporting
mongod)cd backend
cp .env.example .env
# Fill in JWT_SECRET and JWT_REFRESH_SECRET at minimum:
# openssl rand -hex 32
npm install
npm run dev # nodemon, port 3000
The server validates its configuration at boot and refuses to start with a precise error if anything is missing, rather than failing later with an opaque 500.
Local development uses one persistent database, chattrix_local, on a local
MongoDB. Fill it with demo users, follows, posts, comments, messages and a
blocked pair:
cd backend
npm run seed # MONGO_URI defaults to mongodb://127.0.0.1:27017/chattrix_local
MONGO_URI from the shell, never from .env, and
refuses any host other than localhost.local-dev/accounts.txt (git-ignored).Run the API against it, overriding production values that may be in .env:
MONGO_URI=mongodb://127.0.0.1:27017/chattrix_local COOKIE_DOMAIN= \
CORS_ORIGINS=http://localhost:5173 MAIL_PROVIDER=disabled npm run dev
cd frontend
cp .env.example .env
npm install
npm run dev # Vite, port 5173
cd backend
npm test # integration suite, ~10s
npm run test:watch
npm run test:coverage
Tests run against a real MongoDB started in-process by mongodb-memory-server.
If the machine already has a mongod, it is reused (see tests/globalSetup.js)
rather than downloading one; override with MONGOMS_SYSTEM_BINARY.
Services return, controllers respond. Services never touch res; they
return values or throw an AppError carrying an HTTP status. A single
errorHandler turns anything thrown into a response, so no handler echoes raw
Mongoose messages back to clients.
Validation is a boundary, not a suggestion. Every route runs its payload
through a Zod schema that replaces req.body / req.params with the parsed
result, so downstream code only ever sees coerced, trimmed, whitelisted data.
Query strings land on req.validatedQuery (Express 5 makes req.query
read-only). Profile updates use .strict(), so unknown fields are rejected
outright rather than silently reaching a Mongoose update.
Sockets are decoupled from the HTTP server. Handlers import
realtime/socket.js, never server.js. Importing a route therefore does not
start a listener or open a database connection, which is what makes the app
testable with Supertest.
Sessions are revocable at two granularities. A tokenVersion on the user
kills every session at once — the right hammer for a password reset. Each login
also writes a Session row and stamps its jti into both tokens, so a single
device can be signed out without disturbing the others. The cost is one indexed
lookup per request; lastSeenAt is only written when it is more than a minute
stale, so reads do not silently become writes.
The socket handshake is authenticated. Identity comes from the session
cookie the browser already sends with the handshake, verified in
realtime/socketAuth.js. It previously came from handshake.query.userId,
which the client controls — so anyone could connect as anyone and receive their
notifications and direct messages.
This is the beginning of the README. Read the rest at the original. Read the full README ↗