Skip to content

[HARD][INVESTMENTS] Build concurrency-safe pool reservation and settlement workflow #83

Description

@Obiajulu-gif

Overview

Redesign the pool investment workflow so concurrent investors cannot oversubscribe a vehicle, spend the same wallet balance twice, or leave partially updated funding totals.

Problem

Vehicle and loan funding totals are denormalized, while investment records and wallet balances are stored separately. Two requests arriving at the same time can both observe available capacity and balance, then commit conflicting updates. This can create negative balances, overfunded vehicles, duplicate investments, or mismatched totals.

Scope

  • Introduce an explicit investment command/service with MongoDB transaction boundaries.
  • Add reservation states such as pending, reserved, settled, expired, cancelled, and failed.
  • Atomically validate investor balance, remaining pool capacity, pool/vehicle status, KYC eligibility, and amount limits.
  • Reserve capacity and funds using conditional updates or versioned documents.
  • Settle the reservation into an active investment and ledger/transaction records.
  • Release expired or failed reservations safely.
  • Add an idempotency key for retries from the frontend or API client.
  • Recompute or verify totalFunded, fundingProgress, and related cached values.
  • Fix the mismatch between the Investment TypeScript status union and schema enum.

Concurrency requirements

  • Two requests for the final available amount must result in only one successful settlement.
  • Retried requests with the same idempotency key return the original result.
  • A failed database operation must roll back wallet, reservation, investment, and funding-total changes.
  • Reservation expiry must not release funds already settled.

Suggested files

  • investment API routes
  • models/Investment.ts
  • models/Vehicle.ts
  • models/Loan.ts
  • models/User.ts
  • lib/services/investment.service.ts
  • background reservation-expiry worker

Test requirements

  • parallel requests against the last pool capacity
  • duplicate idempotency keys
  • insufficient balance under concurrency
  • transaction rollback after an injected failure
  • reservation expiry and release
  • pool status changes during reservation
  • invariant checks for total investments versus funded totals

Acceptance criteria

  • Pool capacity cannot be exceeded under concurrent requests.
  • Investor balance cannot be spent twice.
  • Investment state transitions are explicit and validated.
  • Retried requests are idempotent.
  • Failed/expired reservations release capacity exactly once.
  • A repair/check command detects funding-total inconsistencies.
  • Load/concurrency tests and standard quality commands pass.

Evidence required

  • Automated test running at least 20 parallel investment attempts
  • Output showing no negative wallet balance or overfunded pool
  • State-transition diagram or contributor documentation

Difficulty

Hard

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions