Your payment model is probably lying to you

php dev.to

Every payment system starts the same way: one table, one provider, ship it.

Then the second provider arrives. Then retry logic. Then partial refunds. Then you realize the model you built on day one is lying to you.

I went through this — and instead of patching it, I started over with one question: what is a payment as a business concept?

The result is a domain model built around DDD and hexagonal architecture: Payment as intent, PaymentAttempt as action, channels (Card, Crypto, P2P, Cash) each with their own state machine, and provider ports that keep the domain clean.

Full writeup with code, diagrams, and the reasoning behind every decision:

👉 https://corner4.dev/reinventing-payment-how-i-evolved-a-domain-model-from-one-table-to-ddd

The code is open source: https://github.com/payroad/payroad-core

Source: dev.to

arrow_back Back to Tutorials