| public | ||
| tests | ||
| .gitignore | ||
| package.json | ||
| README.md | ||
| server.js | ||
Todo List API 📝
A fully-featured Todo List application with a beautiful, responsive frontend and a robust REST API backend. Built with Node.js, Express, and vanilla JavaScript.
📋 Table of Contents
- Features
- Tech Stack
- Installation
- Running the Application
- Running Tests
- API Documentation
- Frontend Features
- Project Structure
- Design Decisions
- Challenges & Solutions
- Future Improvements
✨ Features
Core Features
- ✅ Create, Read, Update, and Delete todos
- ✅ Mark todos as complete/incomplete
- ✅ Beautiful, responsive UI that works on desktop and mobile
- ✅ Real-time statistics dashboard
- ✅ Search functionality to find todos by title
- ✅ Filter todos by status (all/pending/completed)
- ✅ Input validation with meaningful error messages
- ✅ Persistent storage (data saved to file)
- ✅ Multi-user support - Each user gets their own unique ID and data
Bonus Features
- 🎨 Priority levels (low/medium/high) with visual indicators
- 🔍 Advanced search and filtering
- 📊 Statistics endpoint showing completion rates and priority counts
- 🌓 Dark mode toggle with smooth transitions
- ✨ Beautiful animations and transitions
- 💾 Data persistence across server restarts
- 📱 Fully responsive design
- 🎯 Toast notifications for user actions
- ⚡ Loading states for better UX
- 👥 Multi-user system with automatic user ID generation
- 🔐 User data isolation (each user has separate data file)
🛠 Tech Stack
Backend
- Node.js - JavaScript runtime
- Express.js - Web framework for Node.js
- CORS - Enable cross-origin requests
- File System (fs) - Data persistence
Frontend
- HTML5 - Semantic markup
- CSS3 - Modern styling with CSS variables, Grid, and Flexbox
- Vanilla JavaScript - No frameworks, pure ES6+
- Google Fonts - Inter font family
Testing
- Custom test framework - Simple, built-in test runner
- Node.js HTTP module - For making test requests
📦 Installation
Prerequisites
- Node.js (v14 or higher)
- npm (v6 or higher)
Steps
-
Clone or extract the project:
cd instorify_assignment -
Install dependencies:
npm installThis will install:
express(^4.18.2)cors(^2.8.5)nodemon(^3.0.1) - for development
🚀 Running the Application
Development Mode (with auto-reload)
npm run dev
Production Mode
npm start
The server will start on http://localhost:3000
You should see:
✅ Todo API server running on http://localhost:3000
📝 API endpoints available at http://localhost:3000/todos
🌐 Frontend UI available at http://localhost:3000
Accessing the Application
- Frontend UI: Open your browser and navigate to
http://localhost:3000 - API Endpoints:
http://localhost:3000/todos - Health Check:
http://localhost:3000/health
🧪 Running Tests
Run all tests:
npm test
The test suite includes comprehensive tests covering:
- ✅ Creating todos (with validation)
- ✅ Getting all todos (with filtering and search)
- ✅ Getting specific todos by ID
- ✅ Updating todos
- ✅ Deleting todos
- ✅ Statistics endpoint
- ✅ Error handling (404, 400, 500)
- ✅ Edge cases (long titles, special characters, concurrent requests)
Expected Output:
🚀 Starting API Tests...
📦 Test Suite: POST /todos - Create Todo
🧪 Should create a todo successfully... ✅ PASSED
🧪 Should return 400 when title is missing... ✅ PASSED
...
📊 Test Summary
✅ Passed: 50
❌ Failed: 0
📈 Total: 50
🎯 Success Rate: 100%
📚 API Documentation
Base URL
http://localhost:3000
Authentication
All API endpoints (except /health) require a user ID to be provided in the request headers:
Header Required:
X-User-Id: <your-unique-user-id>
User ID Format:
- Alphanumeric characters, hyphens, and underscores
- Between 8-64 characters
- Example:
user_lrjx4k_8h3k2m9p
Automatic Generation:
The frontend automatically generates a unique user ID on first visit and stores it in localStorage. This ID is included in all API requests.
Error Response without User ID:
{
"error": "User ID is required. Please provide X-User-Id header."
}
Endpoints
1. Create a Todo
POST /todos
Create a new todo item.
Headers:
X-User-Id: user_lrjx4k_8h3k2m9p
Content-Type: application/json
Request Body:
{
"title": "Buy groceries",
"completed": false,
"priority": "medium"
}
Response: 201 Created
{
"id": 1,
"title": "Buy groceries",
"completed": false,
"priority": "medium",
"createdAt": "2024-01-01T12:00:00.000Z"
}
Validation:
titleis required and must be a non-empty stringtitlemust be less than 500 charactersprioritymust be one of:low,medium,highcompleteddefaults tofalseif not provided
Error Response: 400 Bad Request
{
"error": "Title is required and must be a string"
}
2. Get All Todos
GET /todos
Retrieve all todos with optional filtering and search.
Headers:
X-User-Id: user_lrjx4k_8h3k2m9p
Query Parameters:
filter(optional): Filter by status -completedorpendingsearch(optional): Search todos by title (case-insensitive)
Examples:
curl -H "X-User-Id: user_123" http://localhost:3000/todos
curl -H "X-User-Id: user_123" http://localhost:3000/todos?filter=completed
curl -H "X-User-Id: user_123" http://localhost:3000/todos?filter=pending
curl -H "X-User-Id: user_123" http://localhost:3000/todos?search=groceries
curl -H "X-User-Id: user_123" http://localhost:3000/todos?filter=pending&search=assignment
Response: 200 OK
[
{
"id": 1,
"title": "Buy groceries",
"completed": false,
"priority": "high",
"createdAt": "2024-01-01T12:00:00.000Z"
},
{
"id": 2,
"title": "Complete assignment",
"completed": true,
"priority": "medium",
"createdAt": "2024-01-01T13:00:00.000Z"
}
]
3. Get a Specific Todo
GET /todos/:id
Retrieve a single todo by its ID.
Example:
GET /todos/1
Response: 200 OK
{
"id": 1,
"title": "Buy groceries",
"completed": false,
"priority": "high",
"createdAt": "2024-01-01T12:00:00.000Z"
}
Error Response: 404 Not Found
{
"error": "Todo not found"
}
4. Update a Todo
PUT /todos/:id
Update an existing todo. You can update any combination of fields.
Request Body:
{
"title": "Buy groceries and cook dinner",
"completed": true,
"priority": "low"
}
Response: 200 OK
{
"id": 1,
"title": "Buy groceries and cook dinner",
"completed": true,
"priority": "low",
"createdAt": "2024-01-01T12:00:00.000Z"
}
Error Responses:
404 Not Found- Todo doesn't exist400 Bad Request- Invalid data (empty title, invalid priority, etc.)
5. Delete a Todo
DELETE /todos/:id
Delete a todo by its ID.
Example:
DELETE /todos/1
Response: 200 OK
{
"message": "Todo deleted successfully",
"todo": {
"id": 1,
"title": "Buy groceries",
"completed": false,
"priority": "medium",
"createdAt": "2024-01-01T12:00:00.000Z"
}
}
Error Response: 404 Not Found
{
"error": "Todo not found"
}
6. Get Statistics (Bonus)
GET /todos/stats
Get statistics about todos including counts and completion rate.
Response: 200 OK
{
"total": 10,
"completed": 6,
"pending": 4,
"completionRate": 60,
"priorityCounts": {
"low": 3,
"medium": 4,
"high": 3
}
}
7. Health Check
GET /health
Check if the server is running.
Response: 200 OK
{
"status": "ok",
"timestamp": "2024-01-01T12:00:00.000Z"
}
HTTP Status Codes
| Code | Description |
|---|---|
| 200 | Success - Request completed successfully |
| 201 | Created - Resource created successfully |
| 400 | Bad Request - Invalid input or validation error |
| 404 | Not Found - Resource doesn't exist |
| 500 | Internal Server Error - Something went wrong on the server |
🎨 Frontend Features
User Interface
-
User Identity
- Automatic unique user ID generation on first visit
- ID stored in browser's localStorage
- Persistent across sessions
- Each user sees only their own todos
-
Dashboard Statistics
- Total tasks count
- Pending tasks count
- Completed tasks count
- Completion rate percentage
-
Add Todo Form
- Text input for todo title
- Priority selector (low/medium/high)
- Add button with icon
-
Search & Filter
- Real-time search by title
- Filter buttons: All, Pending, Completed
- Debounced search for better performance
-
Todo List
- Each todo shows:
- Checkbox for completion status
- Title
- Priority badge with color coding
- Creation date (relative time)
- Delete button
- Visual distinction for completed items (strikethrough, opacity)
- Priority color indicators:
- 🟢 Low - Green
- 🟡 Medium - Yellow
- 🔴 High - Red
- Each todo shows:
-
Dark Mode
- Toggle button in top-right corner
- Smooth transitions between themes
- Preference saved in localStorage
-
Responsive Design
- Works perfectly on desktop, tablet, and mobile
- Adaptive layout
- Touch-friendly buttons
-
User Feedback
- Toast notifications for actions
- Loading spinners during API calls
- Error messages with auto-dismiss
- Empty state when no todos exist
📁 Project Structure
storify_assignment/
├── server.js # Main server file with all API endpoints
├── package.json # Project dependencies and scripts
├── user_data/ # User-specific data files (auto-generated)
│ ├── todos_user_abc123.json # User 1's todos
│ ├── todos_user_xyz789.json # User 2's todos
│ └── ... # More user files
├── public/ # Frontend files
│ ├── index.html # Main HTML file
│ ├── styles.css # Complete CSS with dark mode
│ └── app.js # Frontend JavaScript
├── tests/ # Test files
│ └── api.test.js # Comprehensive API tests
└── README.md # This file
💡 Design Decisions
1. Technology Choices
Why Node.js + Express?
- Lightweight and fast
- Easy to set up and understand
- Large ecosystem
- Perfect for REST APIs
- JavaScript on both frontend and backend
Why Vanilla JavaScript for Frontend?
- No build tools required
- Faster to set up
- Shows fundamental JavaScript skills
- No framework learning curve
- Smaller bundle size
2. Architecture Decisions
In-Memory Storage with File Persistence:
- Fast read/write operations
- Simple implementation
- Data persists between restarts
- No database setup required
- Perfect for a take-home assignment
- User-specific JSON files for data isolation
REST API Design:
- Follows REST conventions
- Intuitive endpoints
- Proper HTTP methods and status codes
- Clear error messages
Separation of Concerns:
- Backend (server.js) handles all API logic
- Frontend files completely separate
- Easy to maintain and extend
3. UX/UI Decisions
Dark Mode:
- Reduces eye strain
- Modern user expectation
- Shows CSS variable mastery
Animations:
- Fade-in effects for smooth loading
- Slide animations for todo items
- Hover effects for interactive elements
- Improves perceived performance
Toast Notifications:
- Non-intrusive feedback
- Auto-dismiss to avoid clutter
- Better than alert() dialogs
Responsive Design:
- Mobile-first approach
- CSS Grid and Flexbox for layouts
- Touch-friendly tap targets
4. Code Quality Decisions
Input Validation:
- Server-side validation (never trust the client)
- Meaningful error messages
- Edge case handling
Error Handling:
- Try-catch blocks
- Proper HTTP status codes
- User-friendly error messages
- Graceful degradation
Code Organization:
- Clear comments and sections
- Consistent naming conventions
- DRY principles (Don't Repeat Yourself)
- Reusable functions
🚧 Challenges & Solutions
Challenge 1: Data Persistence
Problem: Todos were lost on server restart.
Solution: Implemented file-based storage using Node.js fs module. Each user's todos are automatically saved to separate JSON files (e.g., todos_user_123.json) after every modification and loaded on demand.
Challenge 2: Multi-User Support
Problem: All users shared the same todo list.
Solution:
- Frontend generates unique user ID on first visit and stores in localStorage
- User ID sent with every API request via
X-User-Idheader - Backend creates separate JSON file for each user
- In-memory cache per user for performance
- Data completely isolated between users
Challenge 3: Real-time Search Performance
Problem: Searching on every keystroke could cause too many API requests.
Solution: Implemented debouncing (300ms delay) to wait for the user to finish typing before making the API call.
Challenge 4: Dark Mode State Persistence
Problem: Theme preference was lost on page reload.
Solution: Used localStorage to save and restore the user's theme preference.
Challenge 5: Responsive Design Complexity
Problem: Making the UI look good on all screen sizes.
Solution: Used CSS Grid with auto-fit and media queries. Tested on multiple device sizes and adjusted breakpoints accordingly.
Challenge 6: Testing Without a Framework
Problem: No testing framework like Jest was specified.
Solution: Built a simple custom test framework with describe/test/expect functions. It's lightweight and does everything we need.
Challenge 7: Smooth Animations
Problem: Adding/removing todos felt jarring.
Solution: Used CSS animations with staggered delays (each todo animates slightly after the previous one). Added transitions for hover effects and theme changes.
🔮 Future Improvements
If I had more time, I would add:
-
Backend Enhancements:
- Database integration (MongoDB or PostgreSQL)
- User authentication and authorization
- Due dates for todos
- Tags/categories for organization
- Todo subtasks/checklist items
- Sorting options (by date, priority, alphabetical)
- Pagination for large lists
- Rate limiting for API protection
-
Frontend Enhancements:
- Drag-and-drop reordering
- Bulk operations (delete multiple, mark multiple as complete)
- Undo/redo functionality
- Export todos (JSON, CSV, PDF)
- Keyboard shortcuts
- Progressive Web App (PWA) features
- Offline support with service workers
- Accessibility improvements (ARIA labels, keyboard navigation)
-
Features:
- Todo categories/projects
- Recurring todos
- Reminders and notifications
- Collaboration features
- Activity history/audit log
- Todo templates
-
DevOps:
- Docker containerization
- CI/CD pipeline
- Deployment to cloud (Heroku, AWS, etc.)
- Environment-based configuration
- Logging and monitoring
-
Testing:
- Frontend unit tests
- Integration tests
- E2E tests (Cypress, Playwright)
- Performance testing
- Test coverage reports
📄 License
ISC License
Copyright 2026 Majid Abdelilah
Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
🙏 Acknowledgments
- Google Fonts for the Inter font family
- The Express.js team for the excellent framework
- MDN Web Docs for CSS and JavaScript references
📞 Contact
If you have any questions about the implementation or design decisions, I'm happy to explain further in the follow-up interview!
Thank you for reviewing my submission! 🎉