A production-style full-stack finance tracker with role-based access control, JWT authentication, and a clean React frontend.
smart-finance-tracker/
βββ backend/
β βββ controllers/ # Route handlers (thin layer, calls services)
β β βββ authController.js
β β βββ transactionController.js
β β βββ dashboardController.js
β β βββ userController.js
β βββ routes/ # Express route definitions
β β βββ authRoutes.js
β β βββ transactionRoutes.js
β β βββ dashboardRoutes.js
β β βββ userRoutes.js
β βββ models/ # Mongoose schemas
β β βββ User.js
β β βββ Transaction.js
β βββ middleware/ # Express middleware
β β βββ authMiddleware.js # JWT protect + authorize(roles)
β β βββ validationMiddleware.js
β β βββ errorHandler.js
β βββ services/ # Business logic (keep controllers thin)
β β βββ authService.js
β β βββ transactionService.js
β β βββ dashboardService.js
β βββ utils/
β β βββ db.js # MongoDB connection
β β βββ jwtHelper.js # Token generation/verification
β β βββ responseHelper.js # Consistent API responses
β βββ server.js
β βββ package.json
β βββ .env.example
β
βββ frontend/
βββ public/
β βββ index.html
βββ src/
βββ context/
β βββ AuthContext.js # Global auth state (React Context)
βββ services/
β βββ api.js # Axios instance + all API calls
βββ components/
β βββ Sidebar.js
β βββ AddTransactionModal.js
βββ pages/
β βββ LoginPage.js
β βββ RegisterPage.js
β βββ DashboardPage.js
β βββ TransactionsPage.js
β βββ InsightsPage.js
β βββ UsersPage.js
βββ App.js
βββ index.js
βββ index.css
| Layer | Technology |
|---|---|
| Backend | Node.js, Express.js |
| Database | MongoDB + Mongoose |
| Auth | JWT + bcryptjs |
| Validation | express-validator |
| Frontend | React 18, Axios |
- Node.js v18+ installed
- MongoDB running locally on port 27017 (or a MongoDB Atlas URI)
# If using this as a folder, navigate into it
cd smart-finance-trackercd backend
# Install dependencies
npm install
# Create your .env file from the example
cp .env.example .envEdit .env with your values:
PORT=5000
MONGO_URI=mongodb://localhost:27017/smart-finance-tracker
JWT_SECRET=change_this_to_a_long_random_secret
JWT_EXPIRES_IN=7d
# Start the backend (development mode with auto-reload)
npm run dev
# Or in production mode
npm startThe API will be running at: http://localhost:5001
cd ../frontend
# Install dependencies
npm install
# Start the React dev server
npm startThe app will open at: http://localhost:3000
The
"proxy": "http://localhost:5000"infrontend/package.jsonroutes all/api/...calls to the backend automatically.
| Action | Viewer | Analyst | Admin |
|---|---|---|---|
| View dashboard | β | β | β |
| View transactions | β | β | β |
| Create transactions | β | β | β |
| Update transactions | β | β | β |
| Delete transactions | β | β | β |
| View insights | β | β | β |
| Manage users (CRUD) | β | β | β |
{
name: String (required, max 50)
email: String (required, unique, lowercase)
password: String (required, hashed, min 6)
role: String (enum: viewer | analyst | admin, default: viewer)
isActive: Boolean (default: true)
createdAt: Date
updatedAt: Date
}{
user: ObjectId β ref: User
amount: Number (required, min 0.01)
type: String (enum: income | expense)
category: String (enum: salary | food | transport | ...)
description: String (optional, max 200)
date: Date (required)
createdAt: Date
updatedAt: Date
}| Method | Endpoint | Access | Description |
|---|---|---|---|
| POST | /api/auth/register |
Public | Register new user |
| POST | /api/auth/login |
Public | Login, get JWT |
| GET | /api/auth/me |
All users | Get own profile |
| Method | Endpoint | Access | Description |
|---|---|---|---|
| GET | /api/transactions |
All users | List (filter by params) |
| POST | /api/transactions |
Analyst + Admin | Create transaction |
| GET | /api/transactions/:id |
All users | Get single transaction |
| PUT | /api/transactions/:id |
Analyst + Admin | Update transaction |
| DELETE | /api/transactions/:id |
Admin only | Delete transaction |
| Method | Endpoint | Access | Description |
|---|---|---|---|
| GET | /api/dashboard |
All users | Summary stats |
| GET | /api/dashboard/insights |
Analyst + Admin | Deep category insights |
| Method | Endpoint | Access | Description |
|---|---|---|---|
| GET | /api/users |
Admin only | List all users |
| GET | /api/users/:id |
Admin only | Get user by ID |
| PUT | /api/users/:id |
Admin only | Update role/status |
| DELETE | /api/users/:id |
Admin only | Delete user |
GET /api/transactions?type=expense&category=food&startDate=2024-01-01&endDate=2024-12-31&limit=20
| Param | Example | Description |
|---|---|---|
type |
income / expense |
Filter by type |
category |
food |
Filter by category |
startDate |
2024-01-01 |
From date (ISO) |
endDate |
2024-12-31 |
To date (ISO) |
limit |
20 |
Max results (default 100) |
All protected routes require:
Authorization: Bearer <your_jwt_token>
The JWT is returned from /api/auth/register and /api/auth/login.
- MVC Pattern: Routes β Controllers β Services β Models. Controllers are thin β all business logic lives in services.
- Middleware chain:
protectverifies JWT βauthorize(roles)checks role βvalidateXvalidates body β controller runs. - Consistent responses: All endpoints return
{ success, message, data }viaresponseHelper.js. - Password security: bcrypt with salt rounds of 12. Password field excluded from queries by default (
select: false). - MongoDB indexes: Transactions indexed on
(user, date),(user, type),(user, category)for fast dashboard aggregations.