Skip to content

WeSplit grew out of a common pain point: splitting costs fairly within groups is tedious, error‑prone, and often ends in disputes. Existing tools either focus on simple bill splitting without fine‑grained permissions, or they are too generic to model real‑world group dynamics.

Notifications You must be signed in to change notification settings

morshedalamdev/wesplit

Repository files navigation

WeSplit

WeSplit is a shared-expense tracking app for groups such as trips, households, and clubs. It helps members record expenses, see who owes whom, and settle balances—while enforcing role-based access control (RBAC) within each group.

The app is multi-tenant: a single user can belong to multiple groups, with different roles in each one.

Production deployment: wesplit-app.vercel.app


Key Business Benefits

  • Simplifies shared expense tracking
    Centralizes group expenses in one place and automatically calculates who owes whom.

  • Reduces reconciliation friction
    Clear, up-to-date balances and settlement history reduce confusion and disputes at the end of a trip or billing period.

  • Permissioned, auditable collaboration
    Role-based permissions prevent accidental edits and support a transparent, auditable history of changes.


Core Concepts

Users

  • Users authenticate into WeSplit with a personal account.
  • A user can belong to zero, one, or many groups.
  • A user can hold different roles in different groups.

User-related session handling lives in:

  • lib/session.ts – helpers for working with the authenticated user/session.
  • middleware.ts – protects authenticated routes (e.g. dashboard) and routes unauthenticated users to auth pages.

Groups

  • A group represents a shared context where expenses are tracked (e.g. “Spain Trip 2025”, “Apartment Roommates”, “Book Club”).
  • Each group has:
    • A name and optional metadata.
    • A list of members (linked to user accounts).
    • A role assignment for each member, defining what they can do.

Group-related state on the client is managed via:

  • contexts/groupContext.tsx – React context for the currently selected group, list of groups, and group-level operations.

Roles and Permissions (RBAC)

Roles are per group. A user’s role in one group does not affect other groups.

Typical roles:

  • Admin

    • Manage group settings and membership.
    • Invite/remove members.
    • Assign or change roles.
    • Add, edit, and delete any expenses.
    • Record settlements.
    • View all balances and history.
  • Editor

    • Add, edit, and delete any expenses in the group.
    • Record settlements.
    • View balances and history.
    • Cannot manage roles or membership.
  • Contributor

    • Add new expenses.
    • Edit or delete their own expenses (and optionally others’ depending on policy).
    • View balances and history.
    • Cannot manage roles, membership, or group-wide settings.
  • Viewer

    • Read-only access.
    • View expenses, balances, and settlements.
    • Cannot create, edit, or delete data.

RBAC and validation logic is represented in the server/domain layer through:

  • lib/types.ts – shared domain types (groups, expenses, roles, etc.).
  • lib/validation.ts – input validation schemas that also encode what fields and shapes are allowed for different operations.

All write operations in the app are expected to check:

  1. The user is authenticated (via lib/session.ts and middleware.ts).
  2. The user is a member of the target group.
  3. The user’s role in that group grants permission for the requested action.

Features

1. Group Management

  • Create and manage groups for different contexts (trips, households, clubs, etc.).
  • Invite members to a group and assign roles (Admin, Editor, Contributor, Viewer).
  • Switch between multiple groups from the dashboard.

Relevant code areas:

  • app/dashboard/* – main dashboard experience after login.
  • contexts/groupContext.tsx – group selection and group-level actions.
  • lib/dal.ts / lib/db.ts – server-side operations that persist groups and memberships.

2. Expense Tracking

  • Add expenses with:
    • Amount
    • Payer (who paid)
    • Participants (who shares the cost)
    • Split method (e.g. equal split; optional custom split)
    • Date
    • Category
    • Description/notes
  • Automatically split expenses and update everyone’s net position in the group.
  • Edit or delete expenses according to the user’s role and ownership rules.
  • Keep a chronological list of all group expenses.

Relevant code areas:

  • contexts/expenseContext.tsx – client-side state and operations for expenses.
  • lib/validation.ts – validating new and updated expense payloads.
  • lib/dal.ts – expense CRUD and balance-affecting operations.

3. Balances and “Who Owes Whom”

  • Compute a net balance per member inside each group:
    • Amount they owe vs. amount they are owed.
  • Show an easy-to-understand breakdown such as:
    • “You owe Alice $20”
    • “Bob owes you $15”
  • Provide aggregated views of total balances per member to simplify reconciliation.

Relevant code areas:

  • contexts/expenseContext.tsx – deriving per-member balances and exposing them to the UI.
  • lib/types.ts – defines the shapes of balance and summary objects.
  • lib/utils – balance and formatting helpers (e.g. currency, number formatting).

4. Settlements

  • Record settlements between members (e.g. one member paying another back).
  • Each settlement includes:
    • Payer and payee
    • Amount
    • Date
    • Optional note
  • Settlement records adjust the balances accordingly.
  • Display a settlement history for transparency and auditability.

Settlements reuse the same infrastructure as expenses:

  • Types and validation in lib/types.ts and lib/validation.ts.
  • State and views under contexts/expenseContext.tsx and app/dashboard/*.

5. Multi-Tenancy

  • A single user can:
    • Join multiple groups.
    • Have different roles in each group (e.g. Admin in one group, Viewer in another).
  • Data isolation:
    • Expenses, balances, and settlements are always scoped to a specific group.
    • Users can only see and act on groups where they are a member, with permissions enforced by RBAC and server-side checks.

This is reflected in:

  • Shared DAL methods (lib/dal.ts) that always include userId and groupId in queries.
  • Contexts (userContext.tsx, groupContext.tsx, expenseContext.tsx) that keep current user and group in sync.

6. Auditability & Safety

  • Critical operations (expenses, settlements, role changes, membership changes) are permission-controlled via RBAC.
  • Validation and parsing through lib/validation.ts ensures only well-formed inputs reach the database.
  • The app uses:
    • Centralized error boundaries: app/error.tsx
    • A 404 page: app/not-found.tsx
    • Loading and suspense handling: app/loading.tsx

Together, these improve resilience and clarity in the UI when something goes wrong.


Technical Overview

Stack

  • Framework: Next.js (App Router)
    • app/layout.tsx – root layout and providers.
    • app/page.tsx – public landing page / entry point.
    • app/(auth) – authentication-related routes.
    • app/dashboard – authenticated dashboard and main application views.
    • app/api/* – API routes/route handlers for server-side operations.
  • Language: TypeScript
  • Styling: Global CSS via app/globals.css plus component-level styles.
  • Data Layer:
    • lib/db.ts – low-level database client and connection handling.
    • lib/dal.ts – data access layer (groups, users, expenses, settlements).
  • Domain / Utilities:
    • lib/types.ts – shared domain and DTO types.
    • lib/validation.ts – validation schemas for inputs.
    • lib/utils.ts and lib/utils/* – shared utility functions.
    • lib/fetcher.ts – small abstraction around fetch for client-side calls.
  • State Management (React Contexts):
    • contexts/userContext.tsx – user-level state (current user, auth state, etc.).
    • contexts/groupContext.tsx – group selection and group-level operations.
    • contexts/expenseContext.tsx – expenses, balances, and settlements state.
  • Auth & Middleware:
    • lib/session.ts – session helpers (read current user, enforce login).
    • middleware.ts – route protection and request-time auth checks.
  • Config & Build:
    • next.config.ts, tsconfig.json, postcss.config.mjs, components.json.

Architecture

App Structure

  • app/
    • (auth)/ – login/registration/auth flows.
    • dashboard/ – authenticated area, including:
      • Group lists and selectors.
      • Expense and balance views.
      • Settlement flows.
    • api/ – server-side handlers for group/expense/settlement operations.
    • layout.tsx – wraps all pages with shared layout and providers (contexts, theme).
    • page.tsx – marketing or entry landing page.
    • error.tsx, not-found.tsx, loading.tsx – UX around errors and loading states.
  • components/ – shared UI building blocks (forms, tables, modals, layout).
  • contexts/ – React contexts encapsulating client-side domain state and operations.
  • lib/ – data access, domain logic, validation, and helpers.
  • public/ – static assets (icons, images, etc.).
  • docs/ – documentation sources; docs/diagrams contains system/architecture diagrams.

Domain Model (Conceptual)

The conceptual model aligns with the types defined in lib/types.ts. At a high level:

Users

  • Represent authenticated persons using WeSplit.
  • Types defined in lib/types.ts, sessions handled in lib/session.ts.

Groups

  • Shared context for expenses.
  • CRUD and membership handled through DAL methods in lib/dal.ts.

GroupMemberships

  • Link users to groups and store their role.
  • Used to implement multi-tenancy and RBAC decisions in both DAL and API handlers.

Expenses & Splits

  • Expense entities represent each expense inside a group.
  • ExpenseParticipant or equivalent defines how each expense is split among members.
  • Defined in lib/types.ts, validated via lib/validation.ts, persisted through lib/dal.ts.

Settlements

  • Represent recorded payments between members that reduce outstanding balances.
  • Types and validation live in lib/types.ts / lib/validation.ts.
  • Persisted and queried via lib/dal.ts.

RBAC & Authorization

RBAC is enforced at several layers:

  1. Middleware
    middleware.ts ensures that protected routes (e.g. /dashboard) are only accessible to authenticated users.

  2. Session Layer
    lib/session.ts exposes helpers to:

    • Read the active user.
    • Enforce login at the server-handler level.
  3. Data Access Layer
    lib/dal.ts always works with:

    • userId (from session).
    • groupId (from request/route).
      and cross-checks with group membership to ensure the caller is allowed to perform the operation.
  4. Validation & Types
    lib/validation.ts and lib/types.ts encode rules about what fields can be modified in which operations, helping prevent unsafe mutations.


Balances & Calculations

The logic for balances follows this conceptual flow:

  1. For each expense:
    • Credit the payer with the full amount.
    • Debit each participant by their share (equal or custom).
  2. For each settlement:
    • Debit the payer (fromUser) by the settlement amount.
    • Credit the payee (toUser) by the same amount.
  3. Aggregate these into a per-user net balance for each group.

Key places this appears:

  • contexts/expenseContext.tsx – deriving per-member balances and exposing them to the UI.
  • lib/utils – helpers for numeric calculations and display formatting.

API & Data Access

The app uses Next.js App Router app/api/* route handlers for server-side APIs. These:

  • Use lib/session.ts to authenticate the caller.
  • Delegate reads and writes to lib/dal.ts.
  • Validate inputs via lib/validation.ts.
  • Rely on lib/db.ts for low-level database access.

Common responsibilities:

  • Groups
    • Create/update groups.
    • List groups for the current user.
    • Manage memberships and roles.
  • Expenses
    • CRUD operations for group expenses.
    • Returning expense lists with computed splits.
  • Settlements
    • Record and list settlements per group.

On the client, these APIs are typically called through:

  • lib/fetcher.ts – a small abstraction for typed/fetch calls from the frontend.
  • Contexts in contexts/*.tsx, which coordinate state and server calls.

Development

Prerequisites

  • Node.js (LTS)
  • npm (or another package manager like pnpm / yarn, if you prefer)

Running Locally

From the project root:

npm install
npm run dev

Then open http://localhost:3000 in your browser.

Environment Variables

WeSplit expects environment variables (e.g. in .env.local) to configure:

  • Database connection (DATABASE_URL, etc., used by lib/db.ts).
  • Auth/session secrets.
  • Any third-party services (if configured).

Refer to your deployment or .env.example (if present) for the exact list.


Project Status

WeSplit is under active development. The structure in app/, contexts/, lib/, and docs/ is designed to support:

  • Extending RBAC rules.
  • Adding new settlement/expense types.
  • Iterating on the UX while keeping core domain logic centralized.

About

WeSplit grew out of a common pain point: splitting costs fairly within groups is tedious, error‑prone, and often ends in disputes. Existing tools either focus on simple bill splitting without fine‑grained permissions, or they are too generic to model real‑world group dynamics.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published