Skip to content

Repository files navigation

Envelope Budget API

A production-oriented envelope budgeting application built with Node.js, Express, PostgreSQL, and Sequelize ORM, paired with a vanilla JavaScript frontend styled after the Linear.app design system.

Node.js PostgreSQL Express License: MIT

Repository: github.com/Mahnoor-Zaffar/Envelope-Budget-API


Live Demo

Resource URL
App https://envelope-budget-api.onrender.com
Health https://envelope-budget-api.onrender.com/health
Swagger https://envelope-budget-api.onrender.com/api-docs

Free-tier services sleep when idle — first load may take ~30 seconds.


Table of Contents


Overview

Envelope budgeting allocates income into category-specific envelopes (groceries, rent, entertainment, etc.). Each envelope tracks an allocated budget and a spendable balance. When an envelope is depleted, spending in that category stops until funds are reallocated or new income is logged.

This project evolved from an in-memory Express prototype (Part I) into a persistent, database-backed API (Part II) with:

  • Full envelope CRUD and atomic fund transfers
  • A dedicated transaction subsystem that logs external expenditures and adjusts envelope balances
  • Swagger UI for interactive API exploration
  • Render-ready deployment configuration

Overview — Linear-inspired dashboard with budget distribution and recent activity

Envelopes — data-dense table with monospace balances and progress bars


Project Status

Phase Scope Status
Phase 1 Local PostgreSQL setup, .env configuration, database creation ✅ Complete
Phase 2 Sequelize models, envelope + transaction API, Swagger integration ✅ Complete
Phase 3 Local verification (health check, Swagger, curl/API testing) ✅ Complete
Phase 4 Frontend migration to /transactions API ✅ Complete
Phase 5 Production deployment on Render ✅ Complete
Phase 6 Part III — income/funding, transaction UI parity, integration tests ✅ Complete

See todo.md for the live task board.


Tech Stack

Layer Technology
Runtime Node.js ≥ 18
Web framework Express 4
Database PostgreSQL
ORM Sequelize 6
API docs Swagger UI (swagger-ui-express)
Security Helmet, CORS, in-memory rate limiting
Frontend Vanilla HTML / CSS / JavaScript (zero build step)
Deployment target Render (Web Service + Managed PostgreSQL)

Architecture

┌─────────────────────────────────────────────────────────────────────┐
│                         Browser Client                              │
│              public/index.html · styles.css · app.js                │
│                              │ fetch()                              │
└──────────────────────────────┼──────────────────────────────────────┘
                               │ HTTP / JSON
┌──────────────────────────────┼──────────────────────────────────────┐
│                        Express Server                               │
│  ┌──────────┐   ┌─────────────────────────────────────────────┐    │
│  │ server.js│──►│ Middleware: Helmet · CORS · Rate Limit · JSON│    │
│  └──────────┘   └─────────────────────────────────────────────┘    │
│         │                                                             │
│         ├── /api-docs ──────► Swagger UI (docs/swagger.json)         │
│         ├── /health ────────► Health check                           │
│         ├── /envelopes ─────► envelopeRoutes → envelopeController    │
│         └── /transactions ──► transactionRoutes → transactionController│
│                                          │                            │
│                              ┌───────────▼───────────┐               │
│                              │   Sequelize ORM        │               │
│                              │  Envelope · Transaction│               │
│                              └───────────┬───────────┘               │
└──────────────────────────────────────────┼───────────────────────────┘
                                           │ SQL (pooled connection)
                              ┌────────────▼────────────┐
                              │      PostgreSQL         │
                              │  envelopes · transactions│
                              └─────────────────────────┘

Design principles

  • Layered MVC — routes, controllers, and models are decoupled; controllers own validation, models own persistence.
  • Database transactions — fund transfers and transaction writes use sequelize.transaction() with row-level locks to preserve atomicity.
  • Defensive validation — every request is validated at the controller layer before hitting the database.
  • Uniform API contract{ data: ... } on success, { error: "..." } on failure.
  • Environment-driven config — connection strings and pool settings resolve from environment variables; SSL is enabled automatically in production.

Data Model

[ Envelope ] 1 ──── * [ Transaction ]

Envelope

Column Type Constraints
id Integer Primary key, auto-increment
title String(128) Required, unique
budget Decimal(12,2) Required, ≥ 0
balance Decimal(12,2) Required, ≥ 0

Transaction

Column Type Constraints
id Integer Primary key, auto-increment
date Timestamp Required
amount Decimal(12,2) Required, > 0
recipient String(256) Required
envelopeId Integer Foreign key → envelopes.id (CASCADE on delete)

Domain rules:

  • Creating a transaction deducts amount from the linked envelope's balance.
  • Deleting a transaction refunds amount back to the envelope.
  • Updating a transaction recalculates balances safely when amount or envelopeId changes.
  • Envelope balances cannot drop below zero.

Project Structure

personal-budget-expressjs/
├── config/
│   ├── constants.js          # Ports, paths, status codes, error messages
│   └── database.js           # Sequelize connection pool + SSL config
├── controllers/
│   ├── envelopeController.js # Envelope CRUD + transfer handlers
│   └── transactionController.js
├── models/
│   ├── index.js              # Associations + initDatabase()
│   ├── envelope.js
│   └── transaction.js
├── routes/
│   ├── envelopeRoutes.js
│   └── transactionRoutes.js
├── utils/
│   └── controllerHelpers.js  # Parsing, formatting, error mapping
├── docs/
│   └── swagger.json          # OpenAPI 3.0 specification
├── public/                   # Vanilla frontend (Phase 4 migration in progress)
├── server.js                 # Express entry point
├── .env.example              # Environment variable template
├── render.yaml               # Render Blueprint (IaC)
├── DEPLOYMENT.md             # Production deployment guide
├── PRD.md                    # Product requirements (Part II)
├── todo.md                   # Kanban task board
└── README.md

Getting Started

Prerequisites

  • Node.js ≥ 18
  • npm ≥ 8
  • PostgreSQL ≥ 14 (local install or Docker)

1. Clone and install

git clone https://github.com/Mahnoor-Zaffar/Envelope-Budget-API.git
cd Envelope-Budget-API
npm install

2. Configure environment

cp .env.example .env

Edit .env with your local PostgreSQL credentials:

PORT=3000
NODE_ENV=development
DATABASE_URL=postgresql://YOUR_USER@localhost:5432/envelope_budget

.env is gitignored and never committed. Only .env.example is tracked.

3. Create the database

createdb envelope_budget
# or: psql postgres -c "CREATE DATABASE envelope_budget;"

Ensure PostgreSQL is running:

pg_isready

4. Start the server

# Development (auto-restart on file changes)
npm run dev

# Production
npm start

On successful startup:

✓  PostgreSQL connected and models synchronized.
✦  Envelope Budget API listening on http://localhost:3000
   Envelopes:    /envelopes
   Transactions: /transactions
   Swagger:      /api-docs
   Health:       /health

Environment variables

Variable Default Description
PORT 3000 HTTP port
NODE_ENV development Set to production on Render (enables DB SSL)
DATABASE_URL Required. PostgreSQL connection string
DB_POOL_MAX 5 Max connections in pool
DB_POOL_MIN 0 Min idle connections
DB_LOGGING false Set to true to log SQL queries

API Reference

All endpoints accept and return JSON. Base URLs:

Resource Base path
Envelopes /envelopes
Transactions /transactions
Health /health
Docs /api-docs

Envelopes

Method Endpoint Description
POST /envelopes Create envelope (title, budget)
GET /envelopes List envelopes (?page=&limit=) + aggregated totalBudget
GET /envelopes/:id Get envelope by ID
PUT /envelopes/:id Update title, budget, and/or balance
DELETE /envelopes/:id Delete envelope (cascades transactions)
POST /envelopes/transfer/:fromId/:toId Atomic fund transfer (amount)
POST /envelopes/distribute Distribute income proportionally by budget allocation
POST /envelopes/:id/fund Add funds to a single envelope balance

Create envelope example:

curl -X POST http://localhost:3000/envelopes \
  -H "Content-Type: application/json" \
  -d '{"title":"Groceries","budget":500}'

Transfer example:

curl -X POST http://localhost:3000/envelopes/transfer/1/2 \
  -H "Content-Type: application/json" \
  -d '{"amount":50}'

Transactions

Method Endpoint Description
POST /transactions Log expenditure; deducts from envelope balance
GET /transactions List transactions (?page=&limit=)
GET /transactions/:id Get transaction by ID
PUT /transactions/:id Update transaction; recalculates balances
DELETE /transactions/:id Delete transaction; refunds envelope balance

Reports

Method Endpoint Description
GET /reports/monthly?year=&month= Monthly spend summary by envelope

Auth (Part IV foundation)

Method Endpoint Description
POST /auth/register Create account (email, password) → JWT
POST /auth/login Login → JWT
GET /auth/me Current user (requires Authorization: Bearer)

Create transaction example:

curl -X POST http://localhost:3000/transactions \
  -H "Content-Type: application/json" \
  -d '{
    "date": "2026-06-25T12:00:00.000Z",
    "amount": 42.50,
    "recipient": "Whole Foods",
    "envelopeId": 1
  }'

Error responses

{ "error": "Descriptive error message." }
Status Meaning
400 Validation failure, insufficient funds, overdraft
404 Envelope or transaction not found
429 Rate limit exceeded
500 Unexpected server error

Interactive Documentation

Full OpenAPI 3.0 specs with request/response schemas are served at:

http://localhost:3000/api-docs

Use Swagger UI to explore all endpoints, payload shapes, and status code variations without leaving the browser.


Frontend

The client lives in public/ and is served as static assets by Express. It provides:

  • Sidebar navigation with Overview, Envelopes, Activity, and New & Transfer views
  • Data-dense envelope table with monospace balances, progress bars, and Add funds action
  • Transaction ledger with edit/delete, payee, date, amount, and category micro-badges
  • Distribute income across envelopes proportionally by budget allocation
  • Create, edit, delete, transfer, and spend flows via flat modals and border-aligned inputs
  • Toast notifications and keyboard-accessible modal dialogs
  • Linear.app-inspired dark theme with lavender accent (#5e6ad2)

Phase 4 — API alignment (complete)

Feature Endpoint
Record spending POST /transactions
Edit / delete transaction PUT / DELETE /transactions/:id
View history GET /transactions
Distribute income POST /envelopes/distribute
Add funds to envelope POST /envelopes/:id/fund
Envelope CRUD + transfer /envelopes

Testing

Integration tests use Node.js built-in node:test and supertest. Tests run against a separate database ({your_db}_test by default, or set TEST_DATABASE_URL).

# Create a test database (once)
createdb envelope_budget_test

# Run the suite
npm test

Coverage includes envelope CRUD, transfers, income distribution, fund top-ups, transaction balance deduction/refund, and insufficient-funds rejection.


Deployment

Production deployment targets Render with a managed PostgreSQL instance.

Live application: https://envelope-budget-api.onrender.com

Resource URL
Frontend https://envelope-budget-api.onrender.com
Health check https://envelope-budget-api.onrender.com/health
Swagger UI https://envelope-budget-api.onrender.com/api-docs

Render injects DATABASE_URL automatically when the database is linked to the web service. Set NODE_ENV=production to enable SSL for database connections.

Render free-tier caveats

Limit Impact
Web service sleep ~30s cold start after inactivity
Free Postgres expires in 30 days Export or upgrade before data loss
One free DB per account Blueprint/manual setup must reuse or upgrade

See DEPLOYMENT.md for redeploy steps and custom domain setup.


Design System

The UI follows the Linear.app aesthetic. Full visual specs are in linear.app/DESIGN.md.

Token Value Usage
Canvas #010102 Page background
Surface 1 #0f1011 Panels and cards
Hairline #23252a Borders and dividers
Ink #f7f8f8 Primary text
Primary #5e6ad2 CTAs, focus rings, active states
Success #27a644 Positive balances

Typography uses Inter for UI and JetBrains Mono for numeric values. Spacing follows a 4px grid. Depth is carried by surface lift and hairline borders — not drop shadows.


Related Documentation

Document Purpose
DOCS.md Documentation index — all PRDs and guides
PRD.md Product requirements — Part II scope and acceptance criteria
PRD-PART-III.md Part III scope — income, UI parity, tests
PRD-PART-IV.md Part IV — auth, pagination, reports, CI
todo.md Kanban board — current task status
DEPLOYMENT.md Render deployment, redeploy, custom domain
docs/swagger.json OpenAPI 3.0 specification
linear.app/DESIGN.md Linear.app design system reference
CONTRIBUTING.md Commit format and local checks
LICENSE MIT license

License

This project is licensed under the MIT License.

About

Build a RESTful API using Node.js and Express to manage a personal budget based on Envelope Budgeting principles. The API will enforce data validation to track envelope balances and prevent overspending.

Topics

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages