Dockerized Expense Tracker Web Application

Dockerized Expense Tracker Web Application with PostgreSQL, Node.js, and Nginx

INTRODUCTION

Managing personal finances is essential for financial well-being, but manually tracking expenses and income can be cumbersome and error-prone. This project aims to address this challenge by developing a full-stack Expense Tracker application that allows users to efficiently monitor, record, and analyse their financial activities.

The application provides secure user authentication, enabling users to maintain personal accounts, while transaction management allows adding, editing, and deleting incomes and expenses. Users can view real-time summaries, including total income, total expenses, and account balance, along with category-wise insights to better understand spending patterns.

The backend is implemented using Node.js with Express, connected to a PostgreSQL database, ensuring reliable and persistent data storage. The frontend is designed with HTML, CSS, and JavaScript to provide an interactive and intuitive user experience. For deployment, the entire application is Dockerized, ensuring consistency across different environments, while Nginx serves as a reverse proxy, routing API requests and serving static frontend files efficiently.

A key focus of this project is containerization and Docker orchestration. Each component - frontend, backend, and database - runs in separate containers, connected via a Docker network to allow seamless communication. The PostgreSQL database uses Docker volumes to persist data across container restarts, while environment variables manage sensitive information like database credentials and JWT secrets. Docker Compose orchestrates multi-container deployment, enabling scalable and reproducible setups. This approach demonstrates not only full-stack development but also modern containerization practices, highlighting portability, scalability, and maintainability.

By combining a robust backend, a responsive frontend, and containerized deployment, this Expense Tracker provides users with a practical, reliable, and user-friendly tool for managing their finances.


OBJECTIVES OF PART 1 - Backend Creation and Dockerization 

  1. Design and Implementation of Core Backend APIs

  • Develop a RESTful backend using Node.js and Express.js.

  • Implement endpoints for transaction management (add, view, edit, delete).

  • Store transaction data temporarily in memory (arrays or variables) to simulate database operations.

  • Incorporate basic validation and error handling to ensure proper API responses.

  1. Dockerization of Backend

  • Create a Dockerfile for the backend service.

  • Configure the container to run Node.js with all dependencies preinstalled.

  • Verify the containerized backend using Postman to send API requests and confirm proper functionality.

  1. Outcome of Part 1

  • A working backend prototype with API endpoints for transaction management.

  • Containerized Node.js backend environment.


OBJECTIVES OF PART 2 - Database Integration and Frontend Creation

  1. Database Integration

  • Add PostgreSQL as the persistent database for data storage.

  • Modify backend routes to perform CRUD operations directly on PostgreSQL.

  • Use environment variables for secure configuration of database credentials.

  • Test all database operations using Postman to ensure accurate backend responses.

  1. Frontend Development

  • Create a responsive web-based frontend using HTML, CSS, and JavaScript.

  • Include pages for login, registration, and dashboard.

  • Design the dashboard to display:

  1. Total income, expenses, and balance.

  2. Transaction list with edit and delete features.

  3. Summary charts for spending categories.

  1. Dockerization of Frontend

  • Create a Dockerfile for the frontend and use Nginx to:

  • Serve static frontend files.

  • Proxy /api requests to the backend container.

  1. Outcome of Part 2

  • Functional backend connected to a persistent PostgreSQL database.

  • Fully developed frontend containerized and ready for integration in Part 3.


OBJECTIVES OF PART 3 - Docker Hub Publishing, Integration, Orchestration and Final Deployment

  1. Image Build, Tagging & Docker Hub Management

  • Build backend and frontend Docker images locally and verify them.

  • Tag images following the Docker Hub naming convention (e.g., yuvaraj015/expense-tracker-backend:v1.0.0).

  • Push the tagged images to Docker Hub so they are publicly available for deployment.

  1. Compose Integration and Deployment

  • Create the docker-compose.yml file to pull images directly from Docker Hub instead of local builds.

  • Include services for backend, frontend, and postgres with proper networking and volumes.

  • Run the full stack using docker-compose up -d and verify smooth container orchestration.

  1. Testing and Verification

  • Access the application via the web interface and confirm all features (login, transactions, analytics) work correctly.

  • Validate data persistence even after container restarts.

  • Ensure minimal setup for end-users - they only need the compose file to deploy the entire app.

  1. Outcome of Part 3

  • Fully integrated, multi-container Expense Tracker with backend, frontend, and database.

  • All images hosted on Docker Hub for easy reuse and deployment.

  • One-step deployment using the Docker Compose file.

  • A reproducible, production-ready setup demonstrating successful container orchestration.


CONTAINER DETAILS AND THEIR FUNCTIONAL ROLES

Container Name

Base Image Used

Function

Repository Link

expense-tracker-frontend

nginx:alpine

Hosts the static user interface built with HTML, CSS, and JavaScript. Serves all frontend content and routes API requests to the backend service.

https://hub.docker.com/r/yuvaraj015/expense-tracker-frontend

expense-tracker-backend

node:20

Runs the Express.js REST API that manages authentication, expense transactions, and communicates with the PostgreSQL database.

https://hub.docker.com/r/yuvaraj015/expense-tracker-backend

expense-tracker-db

postgres:15

Provides a persistent relational database for securely storing user details and expense data.

https://hub.docker.com/_/postgres


SOFTWARE TOOLS AND TECHNOLOGIES USED

Tool/Software

Version

Purpose/Role in the Project

Node.js

20

Runtime environment for the backend server (Express.js app). Handles API routes, authentication, and database interaction.

Express.js

^5.1.0

Framework for creating REST APIs - used for routes like /register, /login, /transactions, /summary, etc.

PostgreSQL

15

Relational database used to store user credentials and transaction data persistently.

pg (Node PostgreSQL Client)

^8.16.3

Node library to connect and query the PostgreSQL database.

bcrypt

^6.0.0

Library used for hashing passwords securely before storing them in the database.

jsonwebtoken (JWT)

^9.0.2

Used for implementing secure token-based authentication for users.

cors

^2.8.5

Enables Cross-Origin Resource Sharing so frontend (different origin) can access backend APIs.

Nginx (Alpine)

latest (from base image)

Used as the web server to host the static frontend (HTML, CSS, JS) files and route traffic efficiently.

Docker Desktop

4.43.2

Used to build, run, and manage Docker containers for frontend, backend, and database.

Docker Engine

28.3.2

Core engine used by Docker Desktop for container management.

Docker Compose

Bundled with Docker Desktop

Used to orchestrate multiple containers using a single configuration file.

Docker Hub

-

Used to store and host custom backend and frontend container images

Postman

11.61.6

Tool used to test API endpoints (register, login, CRUD, summary) before connecting the frontend.

VS Code

1.105.1

Integrated development environment used for writing code and debugging.

HTML / CSS / JavaScript

-

Used for building the static frontend interface, including login, register, and dashboard pages.

Git & GitHub

2.48.1.windows.1

Used for version control


ARCHITECTURE OF Part 1 – Dockerized Backend Service

Description:

In Part 1 the backend was implemented and containerized using Node.js (Node:20) and Express. The backend exposed RESTful APIs for transaction CRUD, storing transaction data temporarily in memory (no persistent database in Part 1). The API endpoints were tested using Postman. The backend ran inside a Docker container (built from the backend Dockerfile) to ensure an isolated, reproducible environment.

ARCHITECTURE OF PART 2 - Persistent Storage and Frontend Containerization

Description:

Part 2 focused on extending the backend with persistent storage and introducing a dedicated frontend container. The system evolved into three independent containers, each with its own Dockerfile but not yet integrated using Docker Compose:

  • Backend (Node.js + Express): Handles expense management APIs such as adding, editing, and deleting transactions.

  • Database (PostgreSQL:15): Provides persistent data storage for user and transaction details.

  • Frontend (HTML/CSS/JS): A simple static user interface that interacts with the backend APIs.

Each container could be built and run individually using Docker commands. Networking and orchestration were not yet automated.

ARCHITECTURE OF PART 3 - Integration and Deployment

Description:

Part 3 represented the complete system integration and deployment phase. All three services - frontend, backend, and database - were unified under Docker Compose, enabling smooth communication, automated network creation, and persistent data volumes.

The application was fully deployable with a single command (docker compose up), making it production-ready.

OVERALL ARCHITECTURE - Dockerized Full Stack Expense Tracker
Description:
The Expense Tracker Application follows a fully containerized three-tier architecture consisting of a frontend, backend, and database, all orchestrated through Docker Compose. The frontend, developed using HTML, CSS, and JavaScript, provides an intuitive user interface that allows users to register, log in, and manage their financial transactions. The backend, built using Node.js and Express, serves as the logical layer that processes incoming requests, applies validation and business rules, and communicates with the database. The PostgreSQL database acts as the persistent storage layer, ensuring that all user and transaction data remain secure and accessible across sessions.

The entire system is containerized to ensure portability, scalability, and ease of deployment. Each service runs in an isolated Docker container, minimizing dependency conflicts and simplifying maintenance. Docker Compose manages the communication between containers through an internal network and mounts persistent volumes for reliable data storage. Additionally, the backend image is pushed to Docker Hub, enabling seamless reuse and deployment on any environment. This architecture demonstrates a complete DevOps-oriented workflow - from modular development to integration, orchestration, and cloud-ready deployment - making the application both robust and production-ready.


Data Flow:

  • Inputs:

    • Users interact with the web-based interface to perform actions such as login, registration, and transaction management.

  • Process:

    • The frontend container (Nginx) handles UI and forwards API requests to the backend.

    • The backend container processes logic, communicates with PostgreSQL for data operations, and returns structured responses.

    • Docker Compose orchestrates communication between containers through a virtual network and mounts persistent volumes for data safety.

  • Outputs:

    • Users receive dynamic responses and visual summaries on the browser interface.

    • Data is securely stored in PostgreSQL, remaining intact across container restarts.

    • Application images are available on Docker Hub for reuse, scalability, and deployment on any Docker-compatible system.


PROCEDURE - PART 1: Dockerized Backend Service

Step 1: Create the project folder

  • Create a new folder named expense-tracker-da1.

  • Open this folder in Visual Studio Code (VS Code) for development.




Step 2: Initialize Node.js project

  1. Initialize a new Node.js project: npm init -y

  • This creates package.json file containing project metadata and dependencies.



  1. Install the required framework: npm install express

    • This adds Express.js to handle HTTP requests and automatically generates a package-lock.json file.




Step 3: Create index.js File

  • Create a file named index.js and add all backend logic.

  • Implement REST API endpoints:

    • GET / - Default route to verify API response.

    • GET /health - Health check endpoint.

    • GET /transactions - Retrieve all transactions.

    • POST /transactions - Add new transaction.

    • PUT /transactions/:id - Update existing transaction.

    • DELETE /transactions/:id - Delete a transaction.

    • GET /summary - Display total income, expense, and balance.

    • GET /category-summary - Category-wise financial summary.

  • Use in-memory arrays to temporarily store transactions.

  • Add validation and error handling for missing or invalid inputs.


Step 4: Create Dockerfile
  • Create a Dockerfile in the project root directory to containerize the backend.

  • The Dockerfile should:

  • Use Node:20 as the base image.

  • Copy all project files into the container.

  • Install dependencies using npm install.

  • Expose port 5000.

  • Set the default command to run the server.


Step 5: Build the Docker image

  • docker build -t expense-tracker-backend .

  • Builds a Docker image named expense-tracker-backend using the Dockerfile.


Step 6: Run the container

  • docker run -d -p 5000:5000 --name expense-tracker-backend-da1 expense-tracker-backend

  • Runs the backend container in detached mode and maps container port 5000 to the host port 5000.


Step 7: Test Endpoints using Postman
  1. GET /

Purpose: Check if the API is up and running.


  1. GET /health

Purpose: Health check endpoint to verify the server’s status.


  1. GET /transactions (initially empty)

Purpose: Retrieve all transactions.


  1. POST /transactions (invalid input)

Purpose: Add a transaction.


  1. POST /transactions (valid input)

Purpose: Add a transaction.



  1. GET /transactions (after adding)

Purpose: Retrieve all transactions.


  1. GET /summary

Purpose: View total income, total expense, and balance.


  1. PUT /transactions/:id (update transaction)

Purpose: Modify existing transaction.


  1. GET /category-summary

Purpose: View category-wise total income and expenses.


  1. DELETE /transactions/:id

Purpose: Delete a transaction.


Step 8: Stop and remove container

  • docker stop expense-tracker-backend-da1

  • docker rm expense-tracker-backend-da1


PROCEDURE - PART 2: Frontend Creation, Database Setup, and Containerization

Step 1: Creating the Project Folder Structure

  • Create a main directory named expense-tracker.

  • Inside it, create two subfolders:

  • backend/ - Contains Node.js server files and its Dockerfile.

  • frontend/ - Contains HTML, CSS, and JS files for the user interface along with its Dockerfile.


Step 2: Set Up the Backend Folder

  • Inside backend folder, create the following files:

  • index.js - Contains the Express.js backend logic and routes for transactions (add, edit, delete, view) and summaries.

  • db.js - Manages PostgreSQL connection using environment variables for host, user, password, and database.

  • init.sql - Contains SQL statements to create necessary tables for users and transactions.

  • package.json and package-lock.json - Holds project dependencies and metadata (like express, pg, cors, etc.).

  • Dockerfile - Defines instructions to build the backend image using Node:20, install dependencies, copy source code, and expose port 5000.



Step 3: Set Up the Frontend Folder

  • Inside frontend folder, create:

  • index.html - Contains login and signup UI.

  • dashboard.html - Displays the user’s income, expenses, and transaction history.

  • style.css - Styles the entire frontend UI.

  • script.js - Handles user login, registration, and local storage.

  • dashboard.js - Fetches data from the backend APIs and updates the dashboard dynamically.

  • config.js - Stores backend API endpoint URLs (useful when backend runs on a different container).

  • nginx.conf - Nginx configuration file for serving static frontend files.

  • Dockerfile - Builds a lightweight Nginx container to serves the frontend application.




PROCEDURE - PART 3: Integration and Deployment using Docker Compose

Step 1: Build and Tag Docker Images Locally

  1. Navigate to the backend directory:

cd backend

docker build -t expense-tracker-backend:latest .

  • This command builds the Docker image for the backend API and tags it as latest.

  1. Navigate to the frontend directory:

cd ../frontend

docker build -t expense-tracker-frontend:latest .

  • This builds the Docker image for the frontend service.


Step 2: Push Images to Docker Hub

  1. Log in to Docker Hub:

docker login

  • Enter your Docker Hub credentials when prompted.

  1. Tag the images with your Docker Hub username and version (v1.0.0):

docker tag expense-tracker-backend:latest yuvaraj015/expense-tracker-backend:v1.0.0

docker tag expense-tracker-frontend:latest yuvaraj015/expense-tracker-frontend:v1.0.0

  • This renames local image tags for proper repository upload.

  1. Push both images:

docker push yuvaraj015/expense-tracker-backend:v1.0.0

docker push yuvaraj015/expense-tracker-frontend:v1.0.0

  • Each image is uploaded to your Docker Hub repository.

  1. Verify on Docker Hub:

    • Visit the Docker Hub account (hub.docker.com/u/yuvaraj015) and check that both images are listed.


Step 3: Create docker-compose.yml in the Root Folder

  • In the project’s root directory (expense-tracker), create a new file named docker-compose.yml.

  • The docker-compose.yml file defines and connects three services:

  • db – PostgreSQL database

  • backend - Node.js API (uses image from Docker Hub)

  • frontend - Nginx UI (uses image from Docker Hub)

  • Key elements it should include:

  • image: Lines referencing your Docker Hub repositories

  • depends_on: Ensures backend waits for DB and frontend waits for backend

  • volumes: Include pgdata for PostgreSQL data persistence

  • Port mappings:

  • 5432:5432 for PostgreSQL

  • 5000:5000 for backend

  • 80:80 for frontend



Step 4: Build and Run the Containers

docker-compose up –build

  • This command builds (if necessary) and runs all three containers together.


Step 5: Access the Web Application


Step 6: Test Functionality through the Website

  1. Register a New User

    1. Empty fields


  1. Valid details: Confirm user is registered successfully.


  1. User Login

    1. Invalid Credentials


  1. Valid Credentials: Ensure login success.


  1. Transaction Management

    1. Add Transaction

      1. Missing Fields


  1. Valid Transaction: Ensure successful addition.







  1. Edit Transaction



  1. Delete Transaction



  1. Category-wise Summary



Step 7: Stop the Containers

docker-compose down

  • Stops and removes all running containers cleanly.




MODIFICATIONS DONE IN CONTAINERS AND INSTRUCTIONS FOR END USERS 

Backend Container

  • Base image used: node:20

  • Modifications done:

  • Created index.js implementing REST API endpoints for transactions, summary, and category-wise operations.

  • Initially used in-memory storage, later integrated with PostgreSQL for persistent storage.

  • Installed dependencies (express) via package.json.

  • Exposed port 5000.

  • Dockerfile created for containerization and image pushed to Docker Hub (yuvaraj015/expense-tracker-backend:v1.0.0).

  • Steps for end users:

  • Download the project folder with docker-compose.yml.

  • Run docker-compose up - the backend container will automatically pull the image from Docker Hub.

  • No modifications needed.


Frontend Container

  • Base image used: nginx:alpine

  • Modifications done:

  • Added static frontend files (index.html, dashboard.html, script.js, dashboard.js, style.css, config.js).

  • Configured nginx.conf to serve frontend and proxy API requests to backend.

  • Dockerfile created and image pushed to Docker Hub (yuvaraj015/expense-tracker-frontend:v1.0.0).

  • Steps for end users:

  • Container is automatically pulled by docker-compose.

  • Access the web app via browser on port 80.

Database Container

  • Image used: postgres:15 (official)

  • Modifications by developer:

  • Added initialization script init.sql for database and tables.

  • Configured persistent volume for data storage.

  • Steps for end users:

  • Database container automatically starts with Docker Compose.

  • Persistent data storage is set up — no manual configuration needed.


Summary:

  • All containers are pre-configured and tested by the developer.

  • End users only need to download the project and run docker-compose up, and the system is fully functional.



GITHUB LINK / DOCKER HUB LINK OF THE MODIFIED CONTAINERS

GitHub Repository

  • Link: https://github.com/yuvaraj-15/Expense-Tracker

  • Contains all the source files, Dockerfiles, and docker-compose.yml.

  • End Users: You only need to download the docker-compose.yml file to run the application. All containers are pre-built and available on Docker Hub, so no manual building is required.


Docker Hub Images



PROJECT OUTCOMES

  1. Full-Stack Application Development

  • Designed and implemented a complete Expense Tracker web application with a user-friendly interface.

  • Integrated essential features such as:

  • User authentication and session management

  • Transaction management (Add, Edit, Delete)

  • Real-time summary and category-wise expense analysis

  1. Containerization Using Docker

  • Successfully Dockerized all components of the application - frontend, backend, and database - into isolated containers.

  • Ensured reproducibility and simplified deployment across systems.

  1. Data Persistence and Reliability

  • Implemented persistent storage through PostgreSQL volumes to maintain user and transaction data across container restarts.

  • Ensured data integrity and consistent API performance during concurrent operations.

  1. Multi-Container Orchestration

    • Configured and deployed a multi-container environment using Docker Compose, demonstrating practical container orchestration skills.

    • Verified seamless inter-container communication between Nginx (frontend), Node.js (backend), and PostgreSQL (database).

  2. Image Management and Deployment

    • Built and published Docker images for frontend and backend services to Docker Hub, enabling easy access and redeployment.

    • Streamlined the deployment process by using prebuilt images instead of local builds.

  3. Functional Validation and Testing

    • Conducted end-to-end testing of all major workflows: user registration, login, transaction CRUD operations, and summaries.

    • Validated frontend-backend integration, API responses, and database persistence.



CONCLUSION

The Expense Tracker web application demonstrates the complete development and deployment of a full-stack system using Docker and Docker Compose. Starting from a backend service with temporary data storage, the project progressed to a fully integrated multi-container system with a frontend interface and persistent PostgreSQL storage.

Containerizing the frontend, backend, and database services, and publishing images to Docker Hub, ensures portability, reproducibility, and ease of deployment on any Docker-enabled system. Comprehensive testing of user flows, API endpoints, and persistent data management validates both functionality and reliability. Overall, this project has provided practical experience in containerization, orchestration, full-stack development, and documentation, equipping the developer with skills for real-world deployment and collaborative environments.

REFERENCES

  1. Original Sources of Docker Images

  1. Docker Tutorials

  • IIT Bombay Spoken Tutorial for Docker: 

https://spoken-tutorial.org/tutorial-search/?search_foss=Docker&search_language=English

ACKNOWLEDGEMENTS

I would like to express my heartfelt gratitude to Dr. Subbulakshmi T, my course instructor for BCSE408L – Cloud Computing at the School of Computer Science and Engineering (SCOPE), Vellore Institute of Technology, Chennai, for her valuable guidance and continuous support throughout the completion of this project. Her insights into cloud technologies and containerization have been instrumental in helping me understand the practical aspects of Docker.

I would also like to acknowledge the learning resources provided by VIT Chennai and the IIT Bombay Spoken Tutorial, which were immensely helpful during the development process. Finally, I extend my appreciation to my friends who helped clarify doubts and provided constant encouragement during this project.



- Yuvaraj U
Vellore Institute of Technology, Chennai

Comments