A full-stack TODO list application with persistent server-sided timers. Each TODO item can have a timer started on the server, and the timer persists across page refreshes and multiple client connections.
- Framework: Express.js
- Database: MongoDB for persistent TODO storage
- Real-time Communication: Socket.IO for WebSocket connections
- Timer Management: In-memory timer registry with automatic cleanup
Key Features:
- REST API for backend health checks
- WebSocket events for real-time TODO updates
- Server-sided timer logic that persists independently of client state
- Automatic timer completion notifications to all connected clients
- Framework: React 19 with TypeScript
- Build Tool: Vite for fast development and optimized builds
- Real-time Client: Socket.IO client for WebSocket communication
- State Management: React hooks for local state management
Key Features:
- Real-time synchronization with server via WebSocket
- Client-side countdown display synced to server time
- Instant UI updates on TODO modifications
- Responsive design for mobile and desktop
interview-app/
├── backend/
│ ├── package.json
│ ├── pnpm-lock.yaml
│ ├── .env
│ └── server.js # Main Express server with Socket.IO
├── frontend/
│ ├── package.json
│ ├── pnpm-lock.yaml
│ ├── .env
│ ├── index.html
│ ├── vite.config.ts
│ ├── tsconfig.json
│ └── src/
│ ├── main.tsx # React entry point
│ ├── App.tsx # Main component with Socket.IO logic
│ └── App.css # Styling
├── Dockerfile # Multi-stage Docker build
├── docker-compose.yml # Orchestration for app + MongoDB
└── README.md
load-todos: Request all TODO itemsadd-todo(text): Create a new TODOtoggle-todo(id): Toggle TODO completion statusdelete-todo(id): Delete a TODO itemstart-timer(data: {id, duration}): Start a server-sided timer (default: 60s)stop-timer(id): Stop and reset the timer
todos-list(todos): Initial TODO list datatodo-added(todo): New TODO createdtodo-updated(todo): TODO modifiedtodo-deleted(id): TODO removedtimer-started({id, endTime}): Timer started with end timestamptimer-finished(id): Timer completedtimer-stopped(id): Timer manually stopped
{
_id: ObjectId,
text: String,
completed: Boolean,
timerStarted: Boolean,
timerEndTime: Number | null, // Unix timestamp in milliseconds
createdAt: Date
}- Install dependencies:
cd backend && pnpm install
cd ../frontend && pnpm install- Set up environment variables:
# backend/.env
PORT=3001
MONGO_URI=mongodb://localhost:27017/todolist
FRONTEND_URL=http://localhost:5173
# frontend/.env
VITE_API_URL=http://localhost:3001- Start MongoDB:
# Requires MongoDB installed locally
mongod- Start backend:
cd backend
pnpm start- In another terminal, start frontend:
cd frontend
pnpm devAccess the app at http://localhost:5173
- Build and start with Docker Compose:
docker-compose up --build- Access the app at
http://localhost:3001
- Client clicks "Start Timer" → Sends
start-timerevent with duration - Server receives event → Creates timer end timestamp, stores in MongoDB, registers timeout
- Server broadcasts → Sends
timer-startedevent with end timestamp to all clients - Client receives → Displays countdown based on server end time (synced across refreshes)
- Timer completes → Server clears timeout, updates MongoDB, broadcasts
timer-finished - All clients notified → Timers are removed from all connected clients
Key Advantage: Timer persists on server even if client disconnects/refreshes. Reconnecting clients receive the current state and continue the countdown from the correct time.
- ✅ Add, edit, delete TODO items
- ✅ Check off completed items
- ✅ Start/stop server-sided timers (60 seconds default)
- ✅ Real-time sync across browser tabs/windows
- ✅ Timer state persists on server
- ✅ Responsive UI for mobile and desktop
- ✅ MongoDB persistence
- ✅ Docker containerization
- Timers are stored in server memory and MongoDB for persistence
- When server restarts, in-memory timers are lost but can be recovered from MongoDB
- Multiple clients see real-time updates instantly
- Timer countdown syncs to server time to prevent client-side clock drift