Skip to content

naw7az/fairshare-api

Repository files navigation

FairShare API

A robust expense management and debt simplification system

Split expenses fairly, track balances, and settle debts with ease

📱 View the FairShare Mobile Frontend Repo

NestJS TypeScript PostgreSQL Redis TypeORM


Table of Contents


Overview

FairShare is a production-ready expense management API built with enterprise-grade architecture patterns. Inspired by apps like Splitwise, it provides a robust backend for tracking shared expenses, managing group finances, and simplifying complex debt scenarios.

Why FairShare?

  • Financial Correctness First: Built as a financial ledger system, not just a CRUD app
  • Mobile-First Design: Idempotency keys protect against duplicate operations from network retries
  • Intelligent Debt Simplification: Automatically reduces the number of transactions needed to settle all debts
  • Enterprise Architecture: Clean domain-driven design with proper separation of concerns
  • Production Ready: Comprehensive error handling, validation, and transaction management

Key Features

Expense Management

  • Multiple Split Types: Equal, exact amount, and percentage-based splits
  • Multi-Currency Support: Handle expenses in different currencies
  • Flexible Participants: Add any group member to an expense
  • Real-time Balance Updates: Automatic balance recalculation after each expense

Group Collaboration

  • Group Management: Create and manage expense groups
  • Role-Based Access: Admin and member roles with appropriate permissions
  • Multi-User Support: Multiple users can manage expenses in shared groups
  • Audit Trail: Complete history of all expenses and settlements

Debt Simplification

  • Smart Algorithm: Reduces the number of required transactions
  • Balance Snapshots: Efficiently tracks who owes whom
  • Settlement Tracking: Record and track debt repayments
  • Historical Accuracy: Maintain complete financial records

Security & Reliability

  • JWT Authentication: Secure user authentication
  • Idempotency Keys: Prevent duplicate operations (24-hour window)
  • Transaction Safety: ACID-compliant database operations
  • Validation: Comprehensive input validation with class-validator
  • Error Handling: Graceful error handling with custom filters

Architecture Highlights

FairShare follows Domain-Driven Design (DDD) principles with a clear separation between:

  • Write Model: Expenses and settlements (source of truth)
  • Read Model: Balance snapshots (derived state)

Key Design Patterns

  • Strategy Pattern: Pluggable split calculation strategies (Equal, Exact, Percentage)
  • Domain Services: Pure business logic separated from infrastructure
  • Repository Pattern: Abstracted data access via TypeORM
  • Interceptor Pattern: Idempotency handling via NestJS interceptors
  • Guard Pattern: Authentication and authorization

Domain Invariants

The system enforces strict domain rules:

  • Balance snapshots are always consistent with expenses
  • All financial calculations are precise (no floating-point errors)
  • Users cannot create expenses in groups they don't belong to
  • Expense participants must sum to the total amount
  • No self-debt scenarios

Tech Stack

Core Framework

Database & ORM

  • PostgreSQL - Primary relational database
  • TypeORM - Object-relational mapping
  • Migrations - Version-controlled schema changes

Caching & Sessions

  • Redis - Caching and session storage
  • IORedis - Redis client

Authentication

  • Passport - Authentication middleware
  • JWT - JSON Web Token strategy
  • Local Strategy - Username/password authentication

Validation & Transformation

Testing

  • Jest - Unit and integration testing
  • Supertest - HTTP assertions

Code Quality


Getting Started

Prerequisites

  • Node.js (v18 or higher)
  • PostgreSQL (v14 or higher)
  • Redis (v6 or higher)
  • npm or yarn

Installation

  1. Clone the repository

    git clone https://github.com/naw7az/fairshare-api.git
    cd fairshare-api
  2. Install dependencies

    npm install
  3. Configure environment variables

    Create a .env file in the root directory:

    # Database
    DB_HOST=localhost
    DB_PORT=5432
    DB_USERNAME=postgres
    DB_PASSWORD=your_password
    DB_NAME=fairshare
    
    # Redis
    REDIS_HOST=localhost
    REDIS_PORT=6379
    
    # JWT
    JWT_SECRET=your_jwt_secret_key
    JWT_EXPIRATION=7d
    
    # Application
    PORT=3000
    NODE_ENV=development
  4. Run database migrations

    npm run migration:run
  5. Start the development server

    npm run watch

The API will be available at http://localhost:3000


API Features

Authentication

  • POST /auth/register - Register a new user
  • POST /auth/login - Login and receive JWT token

Users

  • GET /users/me - Get current user profile
  • PATCH /users/me - Update user profile

Groups

  • POST /groups - Create a new group
  • GET /groups - List user's groups
  • GET /groups/:id - Get group details
  • PATCH /groups/:id - Update group
  • DELETE /groups/:id - Delete group

Group Members

  • POST /groups/:id/members - Add member to group
  • GET /groups/:id/members - List group members
  • DELETE /groups/:id/members/:userId - Remove member

Expenses

  • POST /groups/:id/expenses - Create expense (requires idempotency key)
  • GET /groups/:id/expenses - List group expenses
  • GET /groups/:id/expenses/:expenseId - Get expense details
  • PATCH /groups/:id/expenses/:expenseId - Update expense (requires idempotency key)
  • DELETE /groups/:id/expenses/:expenseId - Delete expense

Balances

  • GET /groups/:id/balances - Get simplified balances for group
  • GET /groups/:id/balances/user/:userId - Get user's balances in group

Settlements

  • POST /groups/:id/settlements - Record a settlement (requires idempotency key)
  • GET /groups/:id/settlements - List settlements
  • PATCH /groups/:id/settlements/:settlementId - Update settlement (requires idempotency key)

Domain Model

Core Entities

User ─────┐
          │
          ├──→ GroupMember ──→ Group
          │                      │
          │                      │
          └──→ Expense ──────────┘
                  │
                  ├──→ ExpenseParticipant
                  │
                  └──→ BalanceSnapshot (derived)
                       
Settlement ────→ Group

Entity Descriptions

  • User: System users with authentication credentials
  • Group: Container for shared expenses
  • GroupMember: Association between users and groups (with roles)
  • Expense: Record of money spent with split information
  • ExpenseParticipant: Individual user's share in an expense
  • BalanceSnapshot: Derived state showing who owes whom
  • Settlement: Record of debt repayment
  • IdempotencyKey: Prevents duplicate operations

Development

Available Scripts

# Development
npm run watch              # Start with hot-reload
npm run start:debug        # Start with debugging

# Build
npm run build              # Compile TypeScript to JavaScript
npm run start:prod         # Run production build

# Code Quality
npm run format             # Format code with Prettier
npm run lint               # Lint and fix code with ESLint
npm run commit             # Commit with Commitizen

# Database
npm run migration:generate # Generate new migration
npm run migration:run      # Run pending migrations
npm run migration:revert   # Revert last migration

# TypeORM CLI
npm run typeorm <command>  # Run TypeORM commands

Testing

Running Tests

# Unit tests
npm run test

# Unit tests in watch mode
npm run test:watch

# E2E tests
npm run test:e2e

# E2E tests in watch mode
npm run test:e2e:watch

# Test coverage
npm run test:cov

Test Structure

  • Unit Tests: Located alongside source files (*.spec.ts)
  • E2E Tests: Located in /test directory
  • Test Setup: Automated test database setup with transactions

Documentation

Comprehensive documentation is available in the /docs directory:


Project Structure

fairshare-api/
├── src/
│   ├── main.ts                    # Application entry point
│   ├── app.module.ts              # Root module
│   ├── data-source.ts             # TypeORM configuration
│   │
│   ├── auth/                      # Authentication module
│   │   ├── strategies/            # Passport strategies
│   │   ├── guards/                # Auth guards
│   │   └── dto/                   # Auth DTOs
│   │
│   ├── users/                     # User management
│   ├── groups/                    # Group management
│   ├── group-members/             # Group membership
│   ├── expenses/                  # Expense management
│   │   └── split-strategy/        # Split calculation strategies
│   ├── expense-participants/      # Expense participant management
│   ├── balance-snapshots/         # Balance calculation
│   ├── settlements/               # Settlement tracking
│   ├── debt-simplifier/           # Debt simplification algorithm
│   ├── idempotency/               # Idempotency key handling
│   ├── redis/                     # Redis configuration
│   │
│   └── common/                    # Shared utilities
│       ├── decorators/            # Custom decorators
│       ├── dto/                   # Common DTOs
│       ├── entities/              # Base entities
│       ├── filters/               # Exception filters
│       ├── types/                 # TypeScript types
│       └── validators/            # Custom validators
│
├── migrations/                    # Database migrations
├── test/                          # E2E tests
├── docs/                          # Documentation
└── dist/                          # Compiled output

Contributing

Contributions are welcome! Please follow these guidelines:

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes using Commitizen (npm run commit)
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

Commit Convention

This project uses Conventional Commits. Use npm run commit to create properly formatted commits.


License

This project is licensed under the UNLICENSED license - see the LICENSE file for details.


Acknowledgments

  • Built with NestJS - A progressive Node.js framework
  • Inspired by Splitwise - The leading expense splitting app
  • Architecture patterns from Domain-Driven Design principles

Support

For questions, issues, or contributions:


Made with ❤️ by the FairShare Team

Star this repo if you find it helpful!

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages