[Python | Flask] Simple expense tracker with dashboard
For the development we are using uv, an extremely fast Python package and project manager, written in Rust.
uv run main.pyFor the tailwind css we are using Tailwind Flask Starter. In order to use it, if not installed yet, run:
npm installThen run in the background:
npx tailwindcss -i ./app/static/src/input.css -o ./app/static/dist/output.css --watchRun the flask app:
uv run main.pyTo run the Flask app with Uvicorn, you can use the following command:
uvicorn main:app --reloadTo run the application with Docker, you first need to build the Docker image and then run the container.
1. Build the Docker image:
docker build -t flask-expense .2. Run the Docker container:
docker run -p 5000:5000 -e FLASK_APP=main.py flask-expenseTo run the application with Docker Compose, you can use the following command:
docker-compose upThis will build the image and run the container in one step. The application will be available at http://localhost:5000.
The docker-compose.yml file is configured to use a .env file for environment variables. You can create a .env file by copying the .env-sample file:
cp .env-sample .envThen, you can edit the .env file to set the necessary environment variables.
The app is deployed on Oracle Cloud Infrastructure using Coolify. The deployed link is https://budget.tomdcoding.net.
- Programming Languages: Python, JavaScript, HTML/CSS
- Frameworks & Libraries:
- Backend: Flask, Flask-SQLAlchemy, Flask-WTF, Gunicorn
- Frontend: Tailwind CSS, Flowbite, Chart.js
- Database: Neon Postgres
- Deployment: Docker, Docker Compose, Oracle Cloud Infrastructure, Coolify
- Package Management: uv, npm
The application uses a Neon Postgres database to store expense and income data.
erDiagram
IncomeExpenses {
Integer id PK
String type "default: 'income'"
Float amount
String category "default: 'salary'"
String description
DateTime date
}
This table stores the income and expense records.
| Column | Data Type | Description |
|---|---|---|
id |
Integer | Primary key for the table. |
type |
String | Type of the record, either 'income' or 'expense'. |
amount |
Float | The amount of money for the record. |
category |
String | Category of the income or expense (e.g., 'salary', 'groceries'). |
description |
String | A brief description of the record. |
date |
DateTime | The date and time when the record was created. |
-
Chart Data Mismatch: The income and expense category charts on the dashboard were not correctly displaying the data. The labels for the charts were hardcoded in
app/static/script.js, which caused a mismatch with the data coming from the database.Solution: The issue was resolved by dynamically passing the category labels from the backend to the frontend. The
app/routes.pyfile was modified to extract the category labels and pass them to thedashboard.htmltemplate. The template was updated to embed the labels as JSON data. Finally,app/static/script.jswas updated to use these dynamic labels, ensuring the charts accurately reflect the database records. -
Database Connection Errors: The application may encounter a
sqlalchemy.exc.OperationalErrordue to the database connection being closed by the server after a period of inactivity. This can result in anInternal Server Erroron the deployed page. The issue is resolved by refreshing the page, which establishes a new connection.Solution: To prevent this, the
pool_pre_pingsetting has been enabled in the SQLAlchemy engine options. This configuration tests the database connection for freshness before each use and re-establishes it if it has been closed, thus preventing the error.
- Flask - A micro web framework written in Python.
- Uv - A fast Python package and project manager written in Rust.
- Coding with Prince - Flask Dashboard - A helpful tutorial to build a dashboard with Flask.
- Flowbite: Gettting Started/Flask - instruction on how to install Tailwind CSS Flask and Flowbite
- Tailwind Flask Starter
- Chart.js - it's a JavaScript library for creating interactive charts and graphs on the web.
© 2025 Tomislav Dukez.
