Skip to content

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

Β 

History

75 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

FinanceApp - Personal Finance Management

A full-stack personal finance management application built with Django REST Framework (backend) and Next.js (frontend).

Project Status

This project is not deployed and has no live demo. It is a portfolio/learning project that runs fully locally via Docker Compose (see Getting Started). The deployment notes below describe a plan and have not been tested in production.

Tech Stack

Backend

  • Django 5.0.6 - Web framework
  • Django REST Framework 3.15.2 - API framework
  • SimpleJWT 5.3.1 - JWT authentication (with token blacklist)
  • MySQL 8.x - Database (SQLite in-memory for tests)
  • django-filter 24.2 / drf-spectacular 0.27.2 - Filtering & API docs
  • gunicorn 26.2.0 + whitenoise 6.12.0 - Production server & static files
  • pytest + pytest-django + factory-boy + freezegun - Tests

Frontend

  • Next.js 14.2.3 - React framework (App Router)
  • TypeScript 5.5.4 - Type safety
  • Tailwind CSS 3.4.7 - Styling
  • TanStack Query 5.51.15 - Server state management
  • Zustand 4.5.4 - Client state management
  • React Hook Form + Zod - Form validation
  • Recharts - Data visualization
  • Vitest 5 - Unit tests (lib/utils)

Deployment (planned, not deployed)

  • Frontend: Vercel (Next.js)
  • Backend: Any container host with gunicorn + WhiteNoise (e.g. Render)
  • Database: Managed MySQL 8

Features

  • πŸ” Authentication - JWT auth (register, login, logout with real token revocation, refresh, change password, delete account)
  • πŸ’° Transactions - CRUD for income/expense transactions with year/month/type filters and a 6-month trend endpoint
  • 🏷️ Categories - Custom categories with icons & colors; unpaginated list; duplicate names rejected; deleting a category with transactions returns 409
  • πŸ“Š Dashboard - Monthly summary, 6-month trend chart (real data), category breakdown (per selected month)
  • πŸ“± Responsive - Mobile-first design

Project Structure

finance-app/
β”œβ”€β”€ backend/                 # Django project
β”‚   β”œβ”€β”€ config/             # Settings, settings_test, URLs
β”‚   β”œβ”€β”€ core/               # User model, auth views (register/login/refresh/logout/me/change-password)
β”‚   β”œβ”€β”€ transactions/       # Category & Transaction models, filters, trend endpoint
β”‚   β”œβ”€β”€ assets/             # Empty placeholder package β€” not in INSTALLED_APPS
β”‚   β”œβ”€β”€ tests/              # pytest suite (113 tests, SQLite in-memory)
β”‚   β”œβ”€β”€ requirements.txt    # Runtime dependencies
β”‚   β”œβ”€β”€ requirements-dev.txt # + pytest, factory-boy, freezegun, pip-audit
β”‚   β”œβ”€β”€ Dockerfile          # Dev image (runserver via entrypoint)
β”‚   β”œβ”€β”€ Dockerfile.prod     # Production image (gunicorn, non-root)
β”‚   └── manage.py
β”œβ”€β”€ frontend/               # Next.js project
β”‚   β”œβ”€β”€ src/
β”‚   β”‚   β”œβ”€β”€ app/           # App Router pages
β”‚   β”‚   β”œβ”€β”€ components/    # Reusable components
β”‚   β”‚   β”œβ”€β”€ lib/           # API client, utilities
β”‚   β”‚   β”œβ”€β”€ hooks/         # Custom React hooks
β”‚   β”‚   └── types/         # TypeScript types
β”‚   β”œβ”€β”€ package.json
β”‚   β”œβ”€β”€ tailwind.config.ts
β”‚   └── Dockerfile
β”œβ”€β”€ docker-compose.yml      # Local development
└── README.md

Getting Started

Prerequisites

  • Docker & Docker Compose
  • Node.js 20+ (for local frontend development)
  • Python 3.12+ (for local backend development)

Local Development with Docker

  1. Clone the repository
  2. Copy environment files:
    cp backend/.env.example backend/.env
  3. Start all services:
    docker-compose up --build
  4. Access the application:

Local Development without Docker

Backend

cd backend
python -m venv venv
source venv/bin/activate  # or venv\Scripts\activate on Windows
pip install -r requirements-dev.txt   # includes runtime + test deps
cp .env.example .env
# Edit .env with your database settings
python manage.py migrate
python manage.py seed_default_categories
python manage.py runserver

Frontend

cd frontend
npm ci
cp .env.example .env.local
# Edit .env.local with your API URL
npm run dev

Running Tests

Backend (no MySQL needed β€” tests use SQLite in-memory):

cd backend
pytest -q -p no:warnings          # 113 tests
python manage.py makemigrations --check --dry-run --settings=config.settings_test

Frontend:

cd frontend
npm run lint
npm run type-check
npm run test                      # vitest (lib/utils)
npm run build

Environment Variables

Backend (.env)

Variable Default Notes
DEBUG 0 Must be 1 for dev; when 0 the app fails fast without a secure SECRET_KEY + ALLOWED_HOSTS
SECRET_KEY β€” Required when DEBUG=0; must not start with django-insecure
ALLOWED_HOSTS β€” Comma-separated; required when DEBUG=0
DB_HOST / DB_PORT / DB_NAME / DB_USER / DB_PASSWORD localhost / 3306 / finance_db / root / root MySQL connection
CORS_ALLOWED_ORIGINS http://localhost:3000 Comma-separated allowlist
SECURE_SSL_REDIRECT 1 when DEBUG=0
SESSION_COOKIE_SECURE / CSRF_COOKIE_SECURE 1 when DEBUG=0
SECURE_HSTS_SECONDS 0 Raise to e.g. 31536000 once HTTPS is confirmed
BEHIND_PROXY 0 Set 1 behind a TLS-terminating proxy
ENABLE_API_DOCS β€” 1 exposes /api/docs even when DEBUG=0
THROTTLE_ANON_RATE / THROTTLE_USER_RATE / THROTTLE_AUTH_RATE 60/min / 300/min / 10/min Auth scope covers register/login/refresh/change-password
RUN_MIGRATIONS 1 0 skips migrations in the entrypoint
WEB_CONCURRENCY 3 Gunicorn worker count

Frontend (.env.local)

NEXT_PUBLIC_API_URL=http://localhost:8000/api

API Endpoints

Authentication (throttled: 10/min per IP by default)

  • POST /api/auth/register/ - Register new user (returns tokens for auto-login)
  • POST /api/auth/login/ - Login (returns access & refresh tokens + user)
  • POST /api/auth/refresh/ - Refresh access token
  • GET /api/auth/me/ - Get current user
  • PATCH /api/auth/me/ - Update profile (first_name, last_name, username, email β€” unique, case-insensitive email)
  • POST /api/auth/change-password/ - Change password (blacklists all refresh tokens, returns a new pair)
  • DELETE /api/auth/me/ - Delete account (body: { "password": "..." })
  • POST /api/auth/logout/ - Logout (blacklists refresh token)

Categories

  • GET /api/categories/ - List all categories (user + defaults, unpaginated)
  • POST /api/categories/ - Create category (duplicate name+type β†’ 400)
  • GET /api/categories/{id}/ - Get category
  • PATCH /api/categories/{id}/ - Update category (returns the full object)
  • DELETE /api/categories/{id}/ - Delete category (used by transactions β†’ 409)
  • GET /api/categories/summary/ - Category breakdown (?year=&month= optional, defaults to Jakarta current month)

Transactions

  • GET /api/transactions/ - List transactions (filters: category, category__type, date, search, ordering, page, year, month, type)
  • POST /api/transactions/ - Create transaction (amount must be > 0)
  • GET /api/transactions/{id}/ - Get transaction
  • PATCH /api/transactions/{id}/ - Update transaction (returns the full object)
  • DELETE /api/transactions/{id}/ - Delete transaction
  • GET /api/transactions/summary/ - Monthly summary (invalid year/month β†’ 400)
  • GET /api/transactions/trend/ - 6-month trend (?months=1..24&year=&month=, zero-filled, Jakarta timezone)

Deployment (untested plan)

These steps are a plan, not a record of a real deployment. Expect to adjust them.

Security Notes

  • Logout semantics: logout blacklists the refresh token, but the access token stays valid until it expires (at most 60 minutes). This is accepted.
  • Cookies are readable by JavaScript (XSS risk): access/refresh tokens are stored in regular cookies (HttpOnly not set) so middleware.ts can see them. An XSS vulnerability would allow token theft. Recommended next step: HttpOnly cookies via Next.js route handlers (backend-for-frontend pattern).
  • secure flag is production-only: a production build served over plain HTTP (e.g. a LAN IP) will not send cookies β€” production must use HTTPS.
  • Throttling cache is per-process (locmem): limits are per worker unless a shared cache (e.g. Redis) is configured.
  • API docs are hidden in production unless ENABLE_API_DOCS=1.

Future Enhancements

  • πŸ“„ Reports - PDF/Excel export
  • πŸ’° Budgeting - Monthly budget per category
  • πŸ”„ Recurring Transactions - Automatic recurring entries
  • 🌍 Multi-currency - Support multiple currencies
  • πŸ”” Notifications - Budget alerts, bill reminders
  • πŸͺ HttpOnly cookies via BFF - Move token storage server-side

License

MIT License - feel free to use this project for personal or commercial purposes.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages