Skip to content

devxdh/finance-analyzer

Repository files navigation

finance-analyzer

Simple finance/transactions API built with TypeScript + Express + PostgreSQL.

What this project does

  • Auth
    • Register user (email + password)
    • Login to receive a JWT
    • Protected routes via Authorization: Bearer <token>
  • Transactions
    • Add a transaction
    • List transactions with filters (date range, category, sorting, pagination)
    • Delete a transaction
    • Summary + category + daily aggregations

Tech stack

  • Runtime: Node.js
  • API: Express
  • DB: PostgreSQL
  • Language: TypeScript (compiled to CommonJS output in out/)

Requirements

  • Node.js: 20+ recommended
  • PostgreSQL: 15+ recommended
  • Or use Docker + Docker Compose (recommended for easiest setup)

Environment variables

The app reads environment variables at runtime (see src/config/env.config.ts).

Required:

  • PORT: default "3000"
  • DB_HOST
  • DB_PORT (number, e.g. 5432)
  • DB_NAME
  • DB_USER
  • DB_PASSWORD
  • JWT_SECRET (required for login + auth middleware)

Example .env (local)

Create a file named .env in the repo root:

PORT=3000

DB_HOST=localhost
DB_PORT=5432
DB_NAME=finance
DB_USER=postgres
DB_PASSWORD=postgres

JWT_SECRET=change_me_in_production

Database setup (manual / local Postgres)

1) Create database

createdb finance

Or via psql:

psql -U postgres -c "CREATE DATABASE finance;"

2) Enable required extension

The schema uses gen_random_uuid() for primary keys, which requires the pgcrypto extension.

psql -U postgres -d finance -c "CREATE EXTENSION IF NOT EXISTS pgcrypto;"

3) Apply schema

Schema file: src/database/schema.sql

psql -U postgres -d finance -f src/database/schema.sql

Tables created

  • users
  • transactions (references users(id) with ON DELETE CASCADE)

Run locally (manual)

Install dependencies

npm install

Dev mode (watch)

Runs TypeScript directly with tsx:

npm run dev

Server will listen on http://localhost:3000 by default.

Prod mode (build + run compiled JS)

npm run build
npm start

This runs node out/index.js.


Run with Docker (recommended)

This repo includes Dockerfile + docker-compose.yml for the API + Postgres.

1) Start containers

docker compose up --build
  • API: http://localhost:3000
  • Postgres: localhost:5432

2) Set JWT_SECRET for Docker runs (important)

docker-compose.yml sets DB variables, but you must also provide JWT_SECRET for auth/login to work.

Options:

  • Option A (quick): export before running compose
export JWT_SECRET=change_me
docker compose up --build
  • Option B (recommended): add it to docker-compose.yml under services.app.environment
JWT_SECRET: change_me

3) Apply DB schema to the Docker Postgres container

The Postgres image does not auto-run this repo’s schema by default, so run it once:

docker exec -i finance_db psql -U postgres -d finance -c "CREATE EXTENSION IF NOT EXISTS pgcrypto;"
docker exec -i finance_db psql -U postgres -d finance < src/database/schema.sql

After this, the API endpoints can read/write data.

Stop containers

docker compose down

To also remove the database container data (destructive):

docker compose down -v

API

Base URL: http://localhost:3000

Auth routes (/api/auth)

POST /api/auth/register

Body:

{ "email": "test@example.com", "password": "password123" }

POST /api/auth/login

Body:

{ "email": "test@example.com", "password": "password123" }

Response includes:

  • login_token: JWT string

GET /api/auth/check (protected)

Header:

Authorization: Bearer <token>

DELETE /api/auth/delete (protected)

Header:

Authorization: Bearer <token>

Transaction routes (/api/transaction) (protected)

All transaction routes require:

Authorization: Bearer <token>

POST /api/transaction

Body:

{ "category": "food", "amount": 12.5, "note": "lunch" }

GET /api/transaction

Query params supported (all optional):

  • start: default 2000-01-01 (YYYY-MM-DD)
  • end: default 2100-01-01 (YYYY-MM-DD)
  • category: filter by category
  • sortBy: one of date | category | amount (defaults to date)
  • sortOrder: ASC or DESC (defaults to DESC)
  • limit: default 10
  • offset: default 0

Example:

curl -H "Authorization: Bearer $TOKEN" \
  "http://localhost:3000/api/transaction?start=2026-01-01&end=2026-12-31&sortBy=amount&sortOrder=DESC&limit=50&offset=0"

DELETE /api/transaction/:id

Deletes a transaction by id:

curl -X DELETE -H "Authorization: Bearer $TOKEN" \
  "http://localhost:3000/api/transaction/<transaction_uuid>"

GET /api/transaction/summary

Returns totals (sum/count/month-to-date).

GET /api/transaction/category

Returns totals grouped by category.

GET /api/transaction/daily

Returns totals grouped by date (YYYY-MM-DD).


Troubleshooting

gen_random_uuid() does not exist”

Enable pgcrypto in your database:

psql -U postgres -d finance -c "CREATE EXTENSION IF NOT EXISTS pgcrypto;"

Auth endpoints fail with JWT errors

Make sure JWT_SECRET is set in your environment (local) or container environment (Docker).

DB connection errors

Verify these match your Postgres instance:

  • DB_HOST, DB_PORT, DB_NAME, DB_USER, DB_PASSWORD

For Docker Compose, DB_HOST should be the service name db (this is already set in docker-compose.yml).

About

A better version of my project finance-analyzer which lets the user to authenticate, record transactions and perform analytics on those transactions. It utilizes Typescript, Express and Postgres SQL.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors