Skip to content

PayUpPal is a full-stack Flutter & ASP .NET Core app that makes group expense sharing effortless. Create groups, add expenses, and let its smart debt-minimization algorithm simplify settlements.

License

Notifications You must be signed in to change notification settings

1180779/PayUpPal

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

6 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

💸 PayUpPal

Flutter Firebase ASP.NET Core C# License: MIT

📘 Table of Contents

  1. 📖 Overview
  2. 🎯 Features
  3. 🚀 Technologies Used
  4. 🏗️ Architecture
    1. 📱 Frontend
    2. ⚙️️ Backend
  5. 📦 Installation
  6. 🤝 Authors
  7. 💎 Assets and Attributions

📖 Overview

PayUpPal is a modern full-stack app designed to simplify group expense sharing 👥💰. Whether you're traveling with friends ✈️, living with roommates 🏠, or organizing events 🎉, PayUpPal helps you keep track of who paid for what, and who owes whom 💸.

Users can easily create or join groups ➕👫, add expenses 🧾, and let the system calculate how much each person owes. Thanks to its smart debt minimization algorithm 🤖📉, the app reduces the number of transactions needed to settle up, saving you time and awkward money talk 😅.

No spreadsheets, no confusion 🤯 – just simple, fair expense management ✨.

🎯 Features

Here’s what you can do with PayUpPal 💸✨:

👇 Click on any feature below to see it in action

👤 Personal Profile - Create your own profile with a name, photo

🏠 Home Screen - Stay on top of your recent activity and debts with the Home Screen

🤝 Friends System - Add and manage friends directly in the app
  •   Browse the Friends tab 👥
  •   Search for other users 🔍
  •   Send and accept friend requests 📩✅

👥 Group Creation - Create custom groups for trips, shared apartments, or events
  •   Create your own group 👥
  •   Set a name, description, and group photo 📝🖼️

🔍 Group Management - Easily manage group members

🔗 Join Groups Easily - Join groups using an invitation link 📬 or with a unique group code 🧩 – quick and simple!

🧾 Add & Track Expenses - Add shared expenses in a group, split them fairly, and keep everyone on the same page 💳📊

🤖 Smart Payment Optimization - Our transaction optimization algorithm reduces the number of money transfers needed to settle up. Less hassle, same results 📉🤯.
💵 Payment Requests System - Ask payments directly within the app

🚀 Technologies Used

📱 Frontend

  • Flutter, Dart, Firebase Authentication, BLoC.

⚙️ Backend

  • ASP.NET Core, C#, Entity Framework Core, SQL Server, Azure Blob Storage.

🏗️ Architecture

📱 Frontend

  1. 🗂️ Project Structure

    The frontend of PayUpPal was designed with modularity and scalability in mind. The project is divided into the main app code and two standalone Dart packages:

    • lib/: Contains app logic, pages, views, state management, and routes.
    • packages/api_client/: A reusable Dart package that defines all REST API communication.
    • packages/authentication_repository/: Encapsulates FirebaseAuth methods and exposes auth-related interfaces to the app layer.

    🔌 api_client package

    The api_client package is a self-contained Dart library that provides a modular, scalable, and strongly-typed interface for communicating with the PayUpPal backend API.

    It is responsible for:

    • ⚙️ Configuring secure HTTP communication,
    • 🔄 Transforming raw JSON responses into clean domain models,
    • 📦 Exposing high-level, app-friendly methods via repositories.
    ├───packages
    │   ├───api_client
    │   │   └───lib
    │   │       └───src
    │   │           ├───configurations
    │   │           │   └───converters
    │   │           ├───dtos
    │   │           ├───mappers
    │   │           ├───models
    │   │           ├───providers
    │   │           └───repositories
    Directory Description
    configurations/ Contains dio instance setup and request interceptors (e.g. JWT token injection).
    converters/ Houses custom serializers for types like Decimal or enums used across DTOs.
    dtos/ Data Transfer Objects generated using json_serializable and build_runner, which mirror the backend API schema.
    mappers/ Responsible for mapping between DTOs and Domain Models.
    models/ Clean, immutable domain models used by the app. Designed for presentation and business logic.
    providers/ Annotated API service definitions using retrofit. Maps HTTP verbs to methods.
    repositories/ High-level public API used by the Flutter app. Calls providers, applies mappers, and returns models.

    🔐 authentication_repository package

    The authentication_repository is a focused Dart package that encapsulates all logic related to user authentication within the PayUpPal ecosystem.

    It provides a unified API for signing in, signing up, signing out, and securely storing session data using firebase_auth, google_sign_in and native device mechanisms.

    ├───packages
    │   ├───authentication_repository
    │   │   ├───lib
    │   │   │   │   authentication_repository.dart
    │   │   │   └───src
    │   │   │       │   authentication_repository.dart
    │   │   │       └───exceptions
    │   │   └───test
    │   │           authentication_repository_test.dart
    Directory Description
    authentication_repository.dart Public API for auth logic (sign in/out, get user, register, etc.). Wraps lower-level Firebase calls.
    exceptions/ Defines domain-specific exceptions with readable messages.
    test/ Unit tests verifying repository behavior and exception handling.

    🗂️ lib/ overview

    The lib/ directory serves as the entry point for all business logic, UI rendering, and presentation logic in the PayUpPal frontend. It adheres to feature-first organization, ensuring scalability, modularity, and testability.

    ├───lib
    │   ├───configurations
    │   ├───core
    │   │   ├───services
    │   │   └───widgets
    │   │       ├───animations
    │   │       ├───display_messages
    │   │       └───forms
    │   └───features
    │       ├───authentication
    │       │   ├───login
    │       │   │   ├───bloc
    │       │   │   └───view
    │       │   ├───register
    │       │   │   ├───bloc
    │       │   │   └───view
    │       │   └───widgets
    │       ├───expenses
    │       │   └───create_expense
    │       ├───friendships
    │       │   ├───explore
    │       │   ├───friends
    │       │   ├───invitations
    │       │   ├───invitation_response
    │       │   └───request
    │       ├───groups
    │       │   ├───create_group
    │       │   ├───create_join_request
    │       │   ├───explore
    │       │   ├───invitations
    │       │   ├───invitation_response
    │       │   ├───memberships
    │       │   └───requests
    │       ├───group_details
    │       │   ├───balances
    │       │   │   ├───settle
    │       │   ├───expenses
    │       ├───group_settings
    │       │   ├───invites
    │       │   ├───members
    │       │   └───request
    │       ├───home
    │       ├───money_transfers
    │       │   ├───history
    │       │   ├───incoming
    │       │   ├───incoming_response
    │       │   └───outgoing
    │       └───profile
    Directory Description
    configurations/ Contains global app configurations such as asset paths (assets.dart), environment definitions (environment.dart), route settings (routes.dart), and dependency injection setup (service_registration.dart).
    core/services/ App-wide service classes like secure storage, image picker logic or snack bar service.
    core/widgets/ Shared UI components and layouts like custom app bars, drawers, and themed widgets. Subfolders include animations, reusable display messages, and form components.
    features/ Contains the domain-specific logic grouped by app features (e.g., authentication, groups, expenses). Each feature typically includes BLoC state management, pages, views and widgets.
  2. 🧠 State Management

    PayUpPal uses the BLoC (Business Logic Component) pattern to manage application state in a predictable and scalable way. State logic lives in each feature under features/<feature>/bloc/.

  3. 🌐 Networking & Data Layer

    All HTTP and data-mapping logic is encapsulated in the api_client package (under packages/api_client/), decoupling your UI from raw network calls.

  4. 💉 Dependency Injection

    PayUpPal uses get_it as its service locator. All app-wide services and repositories are registered once at startup.

  5. 🧭 Routing & Navigation

    Routing is handled by the declarative go_router package. All route definitions and guards live in configurations/routes.dart.

⚙️ Backend

PayUpPal's backend is built on ASP.NET Core and is logically divided into 5 projects, promoting a clean and maintainable architecture:

📡 API Layer

The heart of the PayUpPal backend is a clean, scalable, and secure RESTful API. It serves as the single entry point for the Flutter frontend, responsible for handling requests, validating input, and orchestrating business logic through a modern, decoupled architecture.

Key principles and technologies include:

  • CQRS with MediatR: We leverage the Command Query Responsibility Segregation (CQRS) pattern using the popular MediatR library. This decouples endpoint handlers from controllers; each API endpoint simply dispatches a specific Command (for write operations) or Query (for read operations) to its dedicated handler. This results in focused, single-responsibility handlers that are easy to test and maintain.

  • Robust Validation with FluentValidation: Data integrity is paramount. Every incoming request DTO is rigorously validated using the FluentValidation library. This allows us to define clear, strongly-typed validation rules that are applied automatically in the request pipeline, ensuring that only valid data reaches our business logic and providing clear error feedback to the client.

  • Seamless Mapping with AutoMapper: To prevent leaking our internal domain models and to shape data specifically for the client, we use AutoMapper. It handles the transformation between our core Entities and the Data Transfer Objects (DTOs) returned by the API, eliminating boilerplate mapping code and keeping endpoints clean.

├───PayUpPal.API
│   ├───Authentication
│   ├───Configurations
│   ├───Controllers
│   ├───DTOs
│   │   ├───Currencies
│   │   ├───Debts
│   │   ├───Expenses
│   │   ├───ExpensesSplits
│   │   ├───Friendships
│   │   ├───Groups
│   │   ├───Memberships
│   │   ├───MoneyTransfers
│   │   └───Users
│   ├───Enums
│   ├───Pagination
│   ├───Profiles
│   ├───Properties
│   ├───Requests
│   │   ├───Currencies
│   │   │   ├───Handlers
│   │   │   └───Queries
│   │   ├───Debts
│   │   │   ├───Commands
│   │   │   ├───Handlers
│   │   │   └───Queries
│   │   ├───Expenses
│   │   ├───Commands
│   │   ├───Handlers
│   │   └───Queries
│   │   ├───Groups
│   │   │   ├───Commands
│   │   │   ├───Handlers
│   │   │   └───Queries
│   │   ├───Memberships
│   │   │   ├───Handlers
│   │   │   └───Queries
│   │   ├───MoneyTransfers
│   │   │   ├───Commands
│   │   │   ├───Handlers
│   │   │   └───Query
│   │   └───Users
│   │       ├───Commands
│   │       ├───Handlers
│   │       └───Queries
│   ├───Types
│   └───Validators
│       ├───Debts
│       ├───Expenses
│       ├───Extensions
│       ├───Groups
│       ├───Memberships
│       ├───MoneyTransfers
│       ├───PipelineBehaviours
│       └───Users
Directory Description
Authentication/ Includes middleware and services related to JWT validation.
Configuration/ Service registration for cors and dependency injection.
Controllers/ Defines the RESTful API endpoints. Controllers are lightweight, responsible only for receiving HTTP requests and dispatching MediatR commands/queries.
DTOs/ Data Transfer Objects used for API responses. Shaped by AutoMapper to provide clean, client-friendly data structures.
Enums/ API-specific enumerations used in requests and responses.
Pagination/ Contains classes and helpers for handling paginated API responses.
Profiles/ Contains AutoMapper mapping profiles that define the conversion logic between entities and DTOs.
Requests/ Contains all MediatR Command and Query objects, along with their corresponding Handlers.
Types/ Custom API-level types.
Validators/ Houses all FluentValidation rule sets for incoming requests, ensuring data consistency before processing.

🌐 Core layer

This project defines the core domain entities and enumerations.

├───PayUpPal.Core
│   ├───Entities
│   └───Enums

💾 Persistence layer

The persistence layer of PayUpPal is built on a modern .NET stack, leveraging several key technologies and design patterns to ensure a clean, maintainable, and scalable data access layer.

├───PayUpPal.Persistence
│   ├───Configuration
│   ├───Data
│   ├───Migrations
│   ├───Options
│   ├───Pagination
│   ├───Repositories
│   ├───Scripts
│   └───Specifications
│       ├───Currencies
│       ├───Debts
│       ├───Expenses
│       ├───Friendships
│       ├───Groups
│       ├───Memberships
│       ├───MoneyTransfers
│       └───Users
  • ORM: Entity Framework Core (EF Core) is used as the Object-Relational Mapper, providing a powerful and flexible way to interact with the database using .NET objects.

  • Configuration over Convention: Instead of relying solely on EF Core conventions or data annotations, the project uses the Fluent API with IEntityTypeConfiguration<T> classes for each entity. This approach decouples the database schema configuration from the core domain models (POCOs), leading to cleaner entity classes and a more organized persistence layer.

  • Repository and Specification Patterns: Data retrieval logic is encapsulated using the Repository Pattern combined with the Specification Pattern, implemented by means of the Ardalis.Specification library. This allows for the creation of strongly-typed and reusable queries.

  • A Note on Coupling: It's important to recognize the pragmatic trade-offs made in this design. While the Fluent API decouples entities from the database schema details, the entity classes themselves still contain navigation properties (e.g., public User Admin { get; set; }). This intentional coupling is what allows EF Core to map relationships and enables the Ardalis.Specification pattern to build powerful and efficient eager-loaded queries using its Include methods. This avoids the overhead of maintaining separate persistence models and complex mapping logic.

Entity Relationship Diagram

The following diagram illustrates the relationships between the core entities in the PayUpPal database. The annotations on foreign keys (e.g., Requester, Addressee) directly correspond to the navigation property names in the C# entities.

erDiagram
   User {
      int Id PK
      string DisplayName
      string Email
   }
   Friendship {
      int Id PK
      int RequesterId FK "Requester"
      int AddresseeId FK "Addressee"
      FriendshipStatus Status
   }
   Group {
      int Id PK
      string Name
      int AdminId FK "Admin"
      int CurrencyId FK "Currency"
      GroupStatus Status
   }
   Currency {
      int Id PK
      string Code
      string Name
   }
   Membership {
      int Id PK
      int UserId FK "User"
      int GroupId FK "Group"
      GroupMembershipStatus Status
      decimal Balance
   }
   Expense {
      int Id PK
      string Name
      int GroupId FK "Group"
      int CreatedById FK "CreatedBy"
      decimal Amount
   }
   ExpenseSplit {
      int Id PK
      int ExpenseId FK "Expense"
      int DebtorId FK "Debtor"
      decimal Amount
   }
   Debt {
      int Id PK
      int FirstId FK "First"
      int SecondId FK "Second"
      decimal Amount
   }
   MoneyTransfer {
      int Id PK
      int RequesterMembershipId FK "RequesterMembership"
      int AddresseeMembershipId FK "AddresseeMembership"
      decimal Amount
      MoneyTransferStatus Status
   }

   User ||--o{ Friendship : "requests"
   User ||--o{ Friendship : "receives_request_from"
   User ||--o{ Group : "administers"
   User ||--o{ Membership : "has"

   Group ||--o{ Membership : "contains"
   Group ||--o{ Expense : "has"
   Currency ||--o{ Group : "is_used_by"

   Membership ||--o{ Expense : "pays_for"
   Membership ||--o{ ExpenseSplit : "owes"
   Membership ||--o{ Debt : "is_party_one_of"
   Membership ||--o{ Debt : "is_party_two_of"
   Membership ||--o{ MoneyTransfer : "sends"
   Membership ||--o{ MoneyTransfer : "receives"

   Expense ||--o{ ExpenseSplit : "is_split_into"
Loading

🔧 Infrastructure layer

This project contains various service implementations and providers.

├───PayUpPal.Infrastructure
│   ├───Configurations
│   ├───Providers
│   │   └───DateTimeProviders
│   ├───Services
│   │   ├───DebtServices
│   │   ├───PictureUploadServices
│   │   └───UniqueCodeServices
│   └───Storages
│       └───BlobStorages

🤖 Payment optimization algorithm

To optimize the number of transactions between group members, PayUpPal uses a debt simplification algorithm based on individual balances.

Here's how it works under the hood:

  1. Balance Calculation
    For each group member, we calculate their total balance by subtracting what they owe from what they paid.

    • Positive balance → the person is owed money 💰
    • Negative balance → the person owes money 🧾
  2. Heap Construction
    We build two priority queues (heaps):

    • One for users with negative balances (debtors) 🔻
    • One for users with positive balances (creditors) 🔺
      The top of each heap holds the person with the largest absolute balance.
  3. Transaction Matching
    We repeatedly take the top debtor and creditor from the heaps and create a transaction between them:

    • One of them will be fully settled in each step.
    • If the other still has a remaining balance, we push them back into the heap with the updated amount.
    • This continues until all balances are settled (both heaps are empty). ✅

This approach guarantees an optimized number of transactions while ensuring that everyone pays or receives exactly what they should – no more, no less 💸🔄

📦 Installation

Follow these steps to run PayUpPal locally:

  1. Clone the repository:

    git clone https://github.com/adamgracikowski/PayUpPal.git
    cd PayUpPal
  2. Configure Backend:

    📂 Enter /backend directory:

    cd backend

    📦 Restore NuGet packages:

    dotnet restore

    🔒 Configure user secrets:

    cd PayUpPal.API
    dotnet user-secrets init
    
    dotnet user-secrets set "Firebase:Authentication:ProjectId" "<your-firebase-project-id>"
    dotnet user-secrets set "Firebase:Authentication:Issuer" "<your-firebase-issuer>"
    dotnet user-secrets set "ConnectionStrings:DefaultConnection" "<your-database-connection-string>"
    dotnet user-secrets set "AzureBlobStorage:ConnectionString" "<your-blob-storage-connection-string>"
    dotnet user-secrets set "AzureBlobStorage:BlobContainers:UsersContainer" "<your-users-container-name>"
    dotnet user-secrets set "AzureBlobStorage:BlobContainers:GroupsContainer" "<your-groups-container-name>"
    Secret Key Description
    Firebase:Authentication:ProjectId Your Firebase project ID (appears in the Firebase Console URL).
    Firebase:Authentication:Issuer JWT issuer URI for your Firebase project (usually https://securetoken.google.com/<ProjectId>).
    ConnectionStrings:DefaultConnection A valid ADO.NET connection string pointing to your SQL database (e.g., local SQL Server or Azure SQL).
    AzureBlobStorage:ConnectionString The full Azure Storage connection string, including protocol, account name/key, and endpoint suffix.
    AzureBlobStorage:BlobContainers:UsersContainer Name of the blob container where user-related photos will be stored.
    AzureBlobStorage:BlobContainers:GroupsContainer Name of the blob container where group-related photos will be stored.

    🔄 Apply EF Core migrations:

    dotnet ef database update --project PayUpPal.Persistence

    ✅ (Optional) Run backend tests

    dotnet test

    ▶️ Start the API

    On Linux or macOS:

    dotnet run --project PayUpPal.API &

    On Windows:

    start dotnet run --project PayUpPal.API

    🔙 Return to root

    cd ../..
  3. Configure Frontend:

    📂 Enter /frontend folder:

    cd frontend

    📦 Install Dart & Flutter packages:

    flutter pub get

    📱 Select a device and run the app:

    flutter devices
    flutter run --device-id <DEVICE_ID>

You're all set! 🎉 PayUpPal should now be running on your machine. If you encounter any issues, double‑check your user‑secrets configuration and that your database migrations applied successfully.

🤝 Authors

This project was created by:

💎 Assets and Attributions

The current look could not be achieved without high quality assets. They are listed below with source and license type. We encourage you to check their creators via provided links.

asset Source License
images/circle_icons_profile.svg Elegant Themes GNU General Public License, version 2
images/circle_icons_money_return.svg svgrepo CC Attribution License
images/circle_icons_group.svg svgrepo MIT License
images/circle_icons_expense.svg flaticon Flaticon License
animations/money_animation.json lottiefiles Lottie Simple License
animations/money_animation.json lottiefiles Lottie Simple License

About

PayUpPal is a full-stack Flutter & ASP .NET Core app that makes group expense sharing effortless. Create groups, add expenses, and let its smart debt-minimization algorithm simplify settlements.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • Dart 49.8%
  • C# 42.7%
  • TSQL 2.8%
  • C++ 2.4%
  • CMake 1.9%
  • Swift 0.2%
  • Other 0.2%