This repository contains a small MERN-stack (MongoDB, Express, React, Node) Todo application split into two folders:
backend/- Express API + Mongoose modelsfrontend/- React app bootstrapped with Vite
This README documents how to run the app locally, the API surface, project structure, and recommended improvements.
The app provides a minimal Todo list with the ability to:
- Create tasks
- Read all tasks
- Mark tasks as done (toggle)
- Edit a task's text
- Delete a task
It is a great starter project for learning the MERN stack and how a React frontend talks to an Express/Mongo backend.
- Backend: Node.js + Express + Mongoose (MongoDB)
- Frontend: React + Vite, using Axios for HTTP requests
- backend/
server.js- Express server and routesmodels/Todo.js- Mongoose schema for todospackage.json- backend scripts & dependencies
- frontend/
src/- React source files (App, Home, Create, etc.)package.json- frontend scripts & dependenciesindex.html, Vite config, assets
- Node.js >= 16
- npm
- MongoDB running locally (default instructions use a local MongoDB URI)
If you prefer, you can use MongoDB Atlas instead of a local MongoDB instance. See the Environment section below.
The backend listens on port 5000 by default and expects a MongoDB instance available at mongodb://127.0.0.1:27017/TODO.
From the project root:
cd backend
npm install
# start the server (nodemon is used in package.json)
npm startThe server file (backend/server.js) currently:
- uses CORS
- exposes JSON endpoints described below
- connects to MongoDB using the hardcoded URI
mongodb://127.0.0.1:27017/TODO
Tip: To use a custom MongoDB URI or change the port, either edit server.js or wire up environment variables (example below).
Create a .env file in backend/ and set (if you change server.js to read env vars):
MONGO_URI=mongodb://127.0.0.1:27017/TODO
PORT=5000
Base URL (default): http://localhost:5000
Endpoints:
-
POST /add
- Body: { "task": "some text" }
- Creates a new task. Returns the created document.
-
GET /get
- Returns an array of todo documents.
-
PUT /edit/:id
- Toggles or sets the
doneflag. The server implementation setsdone:truewhen called.
- Toggles or sets the
-
PUT /update/:id
- Body: { "task": "new text" }
- Updates the task text for the given id.
-
DELETE /delete/:id
- Deletes the todo with the given id.
Examples (curl):
# Create
curl -X POST http://localhost:5000/add -H "Content-Type: application/json" -d '{"task":"Buy milk"}'
# Get
curl http://localhost:5000/get
# Mark done (or run the edit route)
curl -X PUT http://localhost:5000/edit/<id>
# Update text
curl -X PUT http://localhost:5000/update/<id> -H "Content-Type: application/json" -d '{"task":"New text"}'
# Delete
curl -X DELETE http://localhost:5000/delete/<id>backend/models/Todo.js defines the schema:
task(String, required)done(Boolean, default false)- timestamps enabled
The Mongoose model is registered under the collection name tasks.
The frontend uses Vite. By default it makes requests to http://localhost:5000 directly (hardcoded in the source).
From the project root:
cd frontend
npm install
npm run devOpen the URL printed by Vite (usually http://localhost:5173) to view the app.
-
The React components that call the API are in
frontend/src/:Create.jsx— sends POST /addHome.jsx— fetches GET /get, calls PUT /edit/:id, PUT /update/:id, DELETE /delete/:id
-
The Axios base URL is currently hardcoded as
http://localhost:5000in the components. For production or portability, switch to an environment variable:VITE_API_URLand referenceimport.meta.env.VITE_API_URL.
-
Backend (from
backend/package.json):npm start— runsnodemon server.js(auto-restarts on changes)
-
Frontend (from
frontend/package.json):npm run dev— start Vite dev servernpm run build— build production bundlenpm run preview— preview production buildnpm run lint— run ESLint
- Use Postman or curl to exercise API endpoints independently when debugging backend issues.
- If you use MongoDB Atlas, update the MongoDB connection string in
server.jsor add env var support and setMONGO_URIaccordingly.
- The backend currently uses a hardcoded MongoDB URI and port; moving to a
.envfile and readingprocess.envwould make the app configurable. - The frontend hardcodes
http://localhost:5000in Axios calls — switch to an environment variable (VITE_API_URL) so builds can target a different backend URL. - Small bug found in
Home.jsx: after updating a task the code callsWindow.location.reload()(capitalW) which will throw — it should bewindow.location.reload()or better, update state without reloading. - Add basic validation on the backend for payloads (e.g., ensure
taskis not empty) and return proper HTTP status codes and error messages.
- Build the frontend with
npm run buildand serve thedistfolder from a static hosting provider (Netlify, Vercel, or a static site host). - Deploy backend to a Node host (Heroku, Render, Railway, DigitalOcean App Platform) and point the frontend to the deployed backend URL.
If you'd like to contribute:
- Fork the repository
- Create a branch (feature/fix)
- Make changes, run linting and tests
- Open a pull request with a clear description of changes
This project does not have a license file in the repo. Add a LICENSE file if you want to set an explicit license (MIT is a common choice for small projects).
This README documents the current state of the repository and includes suggested small improvements that will make the app more robust and production-ready. If you'd like, I can:
- add environment variable support to
server.jsand update.env.example - centralize Axios base URL in a small
api.jsclient that reads fromimport.meta.env.VITE_API_URL - fix the
Window.location.reload()bug and add a couple of unit tests
If you want any of those changes implemented now, tell me which and I'll make them.