Skip to content

chepurisunil3/TransactionsProject

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

4 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Transactions Project

Transactions Project is a wallet and ledger application built with React, Express, MongoDB, and Mongoose. The interesting part of the project is not just CRUD around wallets and transactions, but the way the backend tries to preserve balance correctness while multiple updates target the same wallet.

Why this project is interesting

1. Per-wallet queue to reduce race conditions

The backend uses an in-memory queue-like structure in server/models/transactions.js through the transactionsInProcess object.

How it works:

  • Every incoming balance update is assigned a generated UUID.
  • That UUID is pushed into a per-wallet array.
  • Only the UUID at the head of the array is allowed to update the wallet balance.
  • Other requests wait and keep checking until they become the first item in the queue.

Why this matters:

  • Without ordering, two requests could read the same starting balance and both write conflicting results.
  • This mechanism serializes balance updates for a single wallet, reducing the classic read-modify-write race condition.
  • It keeps concurrency scoped per wallet, so unrelated wallets do not block each other.

In short, the project uses a lightweight FIFO coordination pattern so one wallet balance is updated in sequence instead of by overlapping writes.

2. Transaction-first write with rollback on balance failure

The transaction flow is designed as a two-step consistency pattern:

  1. Create the transaction document.
  2. Apply the balance increment to the wallet.

If the balance update fails, the backend removes the newly created transaction entry.

Why this is useful:

  • It avoids leaving an orphan transaction that claims money moved when the wallet balance did not actually change.
  • It acts like a simple compensating rollback without requiring a full database transaction.

This is a practical consistency safeguard for a small Express + MongoDB application.

3. Email-first authentication flow

The app now treats email as the primary unique identity for a wallet.

Highlights:

  • POST /auth/register creates a wallet only if the email does not already exist.
  • POST /auth/login checks whether the email already exists.
  • The API sends a nextAction hint (login or register) so the frontend can redirect users into the correct flow.
  • Email values are normalized to lowercase before lookup and storage.

This creates a cleaner real-world experience than forcing users to create a new wallet every time they want to access the dashboard.

4. Precision guardrails for money values

Both wallet setup and transaction creation validate numeric precision and reject values with more than 4 decimal places.

Why that matters:

  • It prevents accidental storage of overly precise floating-point values.
  • It keeps money-related inputs predictable and constrained at the API boundary.

5. Query design optimized for transaction history

The transaction history is not fetched with a naive full collection scan.

The backend combines:

  • a walletId index,
  • a compound index on walletId + date,
  • and an aggregation pipeline with $match, $sort, $skip, and optional $limit.

Why this stands out:

  • History is naturally wallet-scoped.
  • Results come back newest-first.
  • Pagination is already supported structurally.

6. Backward-compatible setup endpoint

The legacy POST /setup route still works, but internally it now delegates to the same registration logic as POST /auth/register.

That means:

  • old integrations are less likely to break,
  • while the new auth flow becomes the main path.

7. Automatic index migration on startup

On database connection, the app attempts to:

  • detect the old unique name index,
  • remove it if present,
  • and create the new unique email index.

This is a small but valuable operational touch because it aligns old data structures with the new login model without requiring a separate manual setup step first.

Backend architecture highlights

Request validation layer

The project uses express-validator to validate different request types centrally in server/validators/transactions.js.

This keeps controllers focused on business logic rather than repeating field validation everywhere.

Controller responsibilities

In server/controllers/transactions.js, the controllers:

  • normalize auth flow decisions,
  • validate decimal precision,
  • compute the post-transaction balance,
  • derive transaction type (CREDIT or DEBIT),
  • and shape API responses consistently.

Model responsibilities

In server/models/transactions.js, the model layer contains the main business behavior:

  • queue-based balance update coordination,
  • wallet creation and lookup,
  • transaction persistence,
  • compensating delete on failure,
  • and history retrieval using aggregation.

This separation makes the backend easier to reason about.

API Endpoints

Local base URL

http://localhost:3001

Authentication

  • POST /auth/login

    • Request: { email: "user@example.com" }
    • Response: { success, walletId, data, nextAction, errors }
  • POST /auth/register

    • Request: { name: "User Name", email: "user@example.com", balance: 5000 }
    • Response: { success, walletId, nextAction, errors }
  • POST /setup

    • Backward-compatible alias for registration
    • Request: { name: "User Name", email: "user@example.com", balance: 5000 }

Transactions

  • POST /transact/:walletId

    • Request: { amount: number, description: string }
    • Response: { success, data, errors }
  • GET /transactions?walletId=<id>&skip=0&limit=<optional>

    • Response: { success, data, errors }

Wallet

  • GET /wallet/:id
    • Response: { success, data, errors }

Data model summary

wallets

Fields:

  • _id: ObjectId
  • name: String
  • email: String
  • balance: Number
  • createdDate: Date

Indexes:

  • default _id
  • unique email

transactions

Fields:

  • _id: ObjectId
  • walletId: ObjectId
  • amount: Number
  • balance: Number
  • description: String
  • date: Date
  • transactionType: CREDIT | DEBIT

Indexes:

  • default _id
  • walletId
  • compound index: walletId + date(desc)
  • compound index: walletId + transactionType

Setup

  • Open the setup directory.
  • Run backend-setup.cmd.
  • Run frontend-setup.cmd.

Start server and website

  • Open the setup directory.
  • Run start-server.cmd.
  • Run start-website.cmd.

Main takeaway

The strongest backend idea in this project is its wallet-level serialized balance update flow. Instead of allowing concurrent requests to freely mutate the same balance, the app coordinates updates per wallet, then adds rollback protection if the balance write fails. That makes this project more than a simple CRUD wallet demo—it is a small ledger system with deliberate safeguards around correctness.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages