System requirements


Functional:

  • Create account for users.
  • Create payment methods of the supported integration with card issuers.
  • Create the ability to create account keys to securely integrate in other platforms
  • Create payment links for users
  • Create payment forms for businesses which require website integrations
  • Create security and payment signing
  • Create expirations for the links
  • Users can see their history of transactions with their statuses.
  • The users should be notified about transactions statuses.
  • The users can add the correct currencies for card issuers/banks


Non-Functional:

Reliability is crucial for this type of platform since the users should trust that the payment is done successfully

Strong Consitency, and durability Is one of another key feature since a success or a failed payment should clearly indicate it and should be not lost.

Security should be strong to avoid unwanted payments. Encryption with expiration on the payment links should be included to be able to identify that the link is generated by the platform. Here the signing of the URLS should be included to assure authenticity including the expiration.





Capacity estimation

Let's suppose the system will have 1 million active users, that will generate about 10 payments links each.

=> payment link entity is about: 256 bytes each

payment Id: 8bytes

payment method: 2 bytes

userId: 8 bytes

card issuer: 8 bytes

realm: 8 bytes

amount: decimal (8 bytes)

date: (12 bytes)

currency: 2 bytes

signing: 30 bytes

status: 10 bytes

-> 10 million transactions daily results in 2.5 million KB -> 2.5 TB daily

resulting 950 TB of data yearly.

-> 10 million of users data growing in 2 years -> 2TB of data

Aprox 2 Petabytes of data in 2 years.



API design

->Post users: create a user account

{

username: "",

email: "",

date: "",

password: ""

} -> responds 200 OK with link of the resources created.


PUT /api/users to add the payments methods.

-auth header with JWT

{

paymentMethods: []

} -> responds with 200 OK, 401 if unauthorized


-> POST /api/payment

{

amount: decimal,

date: timestamp,

paymentMethod: string/enum.

currency: string/enum

realm: string,// to allow payments to be groupped (site name).

}

with auth header containing auth api key. and secret, only to be exposed in backend.





Database design

I can use PostgreSQL because of the strong consistency that is offers for the users management. For payments I will choose a database with built in sharding and scaling like DynamoDB. The partition key for this database will be account id, also the transaction logs involved in a payment will be stored in the database along with payments.






High-level design

Gateway to authorize requests and build

LB - to load balance between multiple instances of the same service: users microservice

User microservice: to allow user managements and user account details

Payment microservice to generate payment links, and update status, coordinate transactions.

Validate Payment microservice: validate the authenticity of the

Payment transaction microservice.

Fraud detection analytics: all the payments links created are going to analytics database via CDC streaming built-in in DynamoDB





Request flows

  • Create payment link hits apigateway, then LB, then payment links microservice then the database returning the signed payment link
  • Do payment: will hit the verification payment microservice the Update the payment status and coordinate transactions




Detailed component design

  • Sharding offered out of the box for payment service of the DynamoDb service.
  • The payment service will need to coordinate the transactions to subtract from users transactions and using a distributed locking for payment to prevent double payment, also DynamoDB offers transactional updates within a row so we can implement a optimistic locking.
  • Microservice architecture can be chosen to meet such scalability requirement, scaling each microservice individually


For the verification and creation of the links a cryptographic mechanism should be created to determine the authencity of the links. Private-public keys can be employed for this job, singing it with the public key and decrypt it with private. Shared secret can be used allowing only backend to backend communication




Trade offs/Tech choices

The tradeoff on using two for our system 1 for users PostgreSQL with offers strong consistency and one for payment and transaction logs which high volumes of data offering a boost of performance.

To scale the microservices Kubernetes can be used although the microservice architecture come with a lot of other challenges like distributed transactions (coordinate transactions).

A deduplication process need to be introduced for clients which may retry the payments.






Failure scenarios/bottlenecks

The common use case is the failing of the databases but since I try to use managed instances of DynamoDB and PostgreSQL in RDS.

Other failure I see a lot happening is the browser of the payer closes before the payment finishes.

Multiple retry of the same payments.

A rate limit can be also configured so the microservices are protected.

Since we are sharding by user account Id the problem o having a hot shard microservice





Future improvements

  • Fraud detaction algorithms using AI.