A simple, clean Task Manager app built with Node.js/Express (backend) and React Native/Expo (mobile frontend).
Task Manager/
├── server/ ← Backend REST API
│ ├── server.js
│ └── package.json
└── TaskManagerApp/ ← Mobile App (Expo)
└── src/
├── app/index.tsx
├── components/TaskItem.tsx
├── constants/api.ts
└── types/Task.ts
- Node.js (v18 or above)
- Expo Go app installed on your phone (iOS or Android)
- Your phone and computer on the same Wi-Fi network
cd server
npm install
npm startYou should see:
✅ Task Manager API is running!
🌐 Local: http://localhost:3000/tasks
Open a new terminal window:
cd TaskManagerApp
npm install
npx expo startA QR code will appear in the terminal.
- Open the Expo Go app on your phone
- Tap "Scan QR Code"
- Scan the QR code from your terminal
- The app will load on your phone! 🎉
⚠️ Important: Your phone and PC must be on the same Wi-Fi network.
| Method | Endpoint | Description |
|---|---|---|
| GET | /tasks |
Get all tasks |
| POST | /tasks |
Create a new task |
| PATCH | /tasks/:id |
Update task status |
| DELETE | /tasks/:id |
Delete a task |
| Field | Type | Description |
|---|---|---|
id |
string | Unique identifier (UUID) |
title |
string | Task title |
completed |
boolean | Completion status |
createdAt |
string | ISO timestamp |
- ✅ View all tasks
- ✅ Add new tasks (via bottom sheet modal)
- ✅ Mark tasks as complete/incomplete
- ✅ Edit existing task titles
- ✅ Delete tasks
- ✅ Filter by All / Active / Completed
- ✅ Progress bar showing completion rate
- ✅ Loading skeleton and error state
- ✅ Pull-to-refresh
- Frontend: React Native, Expo SDK 55, TypeScript
- Backend: Node.js, Express.js
- Storage: JSON file-based storage (
tasks.json) for persistence across restarts - Navigation: Expo Router
-
JSON file storage over a database: I used a flat
tasks.jsonfile for persistence instead of a database (e.g., SQLite, MongoDB). This keeps the project dependency-free and runnable without any setup, which is appropriate for a short exercise. In production, this would be replaced with a proper database. -
In-memory + file sync: Tasks are held in a
let tasks = []array in memory and written to disk on every mutation. This avoids over-engineering (e.g., connection pooling) while still being correct for a single-instance server. -
Optimistic UI updates: On toggle and delete actions, the frontend updates the UI immediately before the server confirms. If the server fails, the change is reverted. This gives the app a fast, responsive feel without sacrificing correctness.
-
Auto-detected backend URL: The app uses Expo's
hostUrito automatically figure out the backend IP address. This means no manual configuration is needed when switching between devices or networks. -
No authentication: The brief did not require user accounts, so none were added. This keeps the scope focused on CRUD fundamentals.
-
Mobile-first scope: The frontend is built as a native mobile app (React Native / Expo) rather than a web app, as it best showcases the full-stack integration in a real-world mobile context.