Home Projects Portfolio Dashboard Export PDF Log in

Preventing Invalid States with Repository Pattern Logic

Introduction

In the North-South project, managing the lifecycle of payment transactions is critical. A common challenge in complex systems is ensuring that domain objects do not transition into invalid states—such as creating a payment after a transaction has already been cancelled or completed.

The Problem

We identified a potential race condition and logic gap where payment services were inadvertently allowing the creation of new payment records for orders that were already finalized. Allowing these operations creates data inconsistencies and complicates the financial reconciliation process. Relying on client-side checks alone is insufficient; we must enforce these business rules at the persistence layer.

The Solution: Repository Guarding

To address this, we updated our payment service and corresponding repository logic to validate the state of the parent entity before allowing any new payment records to be persisted. Think of the repository as a security guard at a building entrance: it doesn't just store records; it checks if the 'request' is valid before allowing access to the database.

async createPayment(orderId: string, paymentData: PaymentDTO): Promise<Payment> {
  const order = await this.repository.findById(orderId);

  if (order.status === 'CANCELLED' || order.status === 'COMPLETED') {
    throw new Error('Cannot add payment to a finalized order');
  }

  return await this.repository.save(paymentData);
}

In this approach, the service acts as the orchestrator that validates the current state of the order object before delegating the persistence task to the repository. This encapsulates the business logic cleanly, ensuring that state integrity is maintained regardless of where the creation request originates.

Ensuring Reliability with Testing

To guarantee that these constraints remain in place as the codebase evolves, we utilize Cypress for end-to-end testing. By simulating user interactions that attempt to bypass these checks, we ensure that the application gracefully handles restricted state transitions. Consistent testing acts as our safety net, catching regressions before they reach production.

Key Takeaway

Do not rely on the UI to enforce state integrity. Move your critical business validations into your service or repository layer to ensure that invalid operations are rejected at the source. If you find yourself repeatedly handling state-based errors in the UI, move that validation logic to the backend today.


Generated with Gitvlg.com

Preventing Invalid States with Repository Pattern Logic
RIVAS SALTOS DANIEL RUBEN

RIVAS SALTOS DANIEL RUBEN

Author

Share: