A secure and modern full-stack Todo application built with React, TailwindCSS, Express.js, SQLite, and Sequelize ORM. Features user authentication with JWT and password hashing via bcrypt. Designed for security, performance, and a clean developer experience.
- โ JWT-based Authentication
- ๐ Password hashing with bcrypt
- ๐ CRUD for Todos
- ๐ฆ SQLite database via Sequelize ORM
- ๐จ TailwindCSS for UI styling
- โ๏ธ React Frontend
- โ๏ธ Express.js Backend
- ๐งช Secure and scalable folder structure
- real-time communication using socket.io
- React
- TailwindCSS
- socket.io-client
- Node.js
- Express.js
- Sequelize ORM
- SQLite
- JWT (jsonwebtoken)
- bcryptjs
- socket.io
- Node.js & npm
Socket.IO is a JavaScript library that makes real-time, bidirectional communication between browsers (or other clients) and a Node.js server easy. It gives you event-based sockets with lots of useful features (auto reconnect, rooms, namespaces, fallbacks) so you can build chat apps, live dashboards, multiplayer games, notifications, collaborative editors, etc.
- A client + server library for realtime messaging (JS on both browser and Node).
- Wraps a protocol on top of WebSocket and HTTP long-polling โ exposing a nice event-based API:
socket.emit('myEvent', data)andsocket.on('myEvent', handler). - Adds features WebSocket alone does not provide out of the box: automatic reconnection, heartbeats, acknowledgement callbacks, rooms, namespaces, and a small framing/protocol layer.
- Socket.IO = event-driven realtime library (client + server).
- Adds reliability & higher-level features beyond raw WebSockets.
A quick yet comprehensive reference for all ways to send and receive events in Socket.IO.
ioโ The main server instance. Use it to send events to all connected clients, to a room, or to a specific socket ID.socketโ Represents one specific client connection. Use it to send messages only to that client, or to broadcast to others.
Client:
// frontend.js
socket.emit("chatMessage", { text: "Hello server!" });Server:
// server.js
socket.on("chatMessage", (data) => {
console.log("Received from client:", data);
});- Who receives? Server only.
- Use case: User sends a chat message to the server.
Server:
socket.emit("welcome", "Hello, this is a private welcome message!");Client:
socket.on("welcome", (msg) => {
console.log(msg);
});- Who receives? Only that connected client.
- Use case: Sending a private welcome message after connecting.
Server:
io.emit("announcement", "Server will restart in 5 minutes.");Client:
socket.on("announcement", (msg) => {
console.log(msg);
});- Who receives? Every connected client.
- Use case: Public announcements.
Server:
socket.broadcast.emit("userJoined", `${socket.id} joined the chat.`);Client:
socket.on("userJoined", (msg) => {
console.log(msg);
});- Who receives? All clients except the sender.
- Use case: Notify others when a new user joins.
Server:
socket.join("room1"); // Join
socket.leave("room1"); // Leave- Use case: Group chats, game lobbies.
Server:
io.to("room1").emit("roomMessage", "Hello Room 1!");Client:
socket.on("roomMessage", (msg) => {
console.log(msg);
});- Who receives? Everyone in
room1. - Use case: Chat messages for a specific group.
Server:
socket.to("room1").emit("roomMessage", "Someone else says hello!");- Who receives? Everyone in
room1except sender. - Use case: Prevent echoing messages back to sender.
Server:
io.to("some-socket-id").emit("privateMessage", "Hey! Just for you.");Client:
socket.on("privateMessage", (msg) => {
console.log(msg);
});- Who receives? The client with that socket ID.
- Use case: One-to-one chat.
Server:
socket.on("typing", () => {
console.log(`${socket.id} is typing...`);
});Client:
socket.on("userTyping", (user) => {
console.log(`${user} is typing...`);
});- Use case: Typing indicators.
| Method | Location | Who Receives | Example Use Case |
|---|---|---|---|
socket.emit |
Client | Server only | Send form data to server |
socket.emit |
Server | One client | Private welcome message |
io.emit |
Server | All clients | Broadcast announcement |
socket.broadcast.emit |
Server | All except sender | Notify others of join/leave |
socket.join(room) |
Server | N/A | Add client to room |
socket.leave(room) |
Server | N/A | Remove client from room |
io.to(room).emit |
Server | All in room | Group message |
socket.to(room).emit |
Server | All in room except sender | Avoid message echo |
io.to(socketId).emit |
Server | One client by ID | Direct private message |
socket.on(event) |
Client/Server | The one listening | Handle incoming events |
Pro Tip: Always namespace your events and avoid generic names like message to prevent conflicts in large apps.
# Clone the repository
$ git clone https://github.com/ExploitEngineer/secure-todo-app.git
# Navigate into the project directory
$ cd secure-todo-app
# Install backend dependencies
$ cd server
$ npm install
# Setup SQLite DB (optional: seed data)
$ npx sequelize-cli db:migrate
$ cd ..
# Install frontend dependencies
$ cd client
$ npm installcd server
npm run devcd client
npm startsecure-todo-app/
โโโ client/ # React frontend
โ โโโ ...
โโโ server/ # Express backend
โ โโโ controllers/
โ โโโ middleware/
โ โโโ models/
โ โโโ routes/
โ โโโ ...
โโโ README.md- Passwords hashed with
bcrypt - JWT-based session management
- Protected routes on both frontend & backend
- Secure API design practices
This project is open-source and available under the MIT License.
Made with โค๏ธ by ExploitEngineer