System should allow to add/edit and delete users
System should allow login of the users
System should allow users to link bank accounts/cards
System should be able to verify the identity of account holder
A verified user should be able to send money from or receive payment to pay account
User should be able to see the total balance and the transaction history
Able to send the payment
User should be able to receive payment
User should be able to select the payment mode
User should be able to select the currency
User should be able to get the notification of the transaction
System should send an alert in case if fraud is detected. For the sake of simplicity lets assume that a system detect fraud if user attempts to login with wrong password.
Lets suppose system has total 100 million users
10% of the capacity interact with the system on a daily basis
DAU -> 10 M
10% of DAU actually makes the transaction and rest just check their account
write ops -> 1 M
read ops -> 9 M
read/write = 9:1
Given 1M users actually does the transaction and each transaction makes entry for transactionid, sender, receiver , transactiontime, status etc. on an avg. total 1-2KB of data will be stored per transaction. Lets suppose each user may do 2-3 transactions and hence averaging to 1.5 of 1M would be total transactions
Per day storage requirement :
1M* 2KB * 1.5 = 3GB / Day
Per year storage requirement :
3GB * 365 = 1.1TB
Given the data retention of 7 years
Total Capacity requirement of trx data is
7.7 ~ 8 TB
For Ledger entries, capacity requirement would be 2* Transaction requirement = 16TB
TPS :
1M * 1.5 ~ 18 TPS avg
Peak = 2* 18 = 36
QPS:
9M * 3 = 27 Million reads/Day = 1500
Peak = 3000 QPS
Users API
An api to register user to the system
Signature : {baseuri}/api/v1/register
Method : POST
Request Body :
{firstname, lastname, email, mobile, country, address}
Once user is registered an email is send to validate the email
Validate API
Signature : {baseuri}/api/v1/validate
Once validated user is allowed to enter the password & confirmpassword
Set Password API
Signature : {baseuri}/api/v1/login
method : POST
Request Payload : { username : encrypted, password : encrypted }
Add card details API
Signature : /api/v1/addpay
POST
Request Payload : send payload of card details or payment data in encrypted format.
Q - which encrypted format to use?
Fetch Balance API
Signature : /api/v1/transaction?page=x&limit=100
Get
Response : list of transactions
Fetch Transaction Status
Sign : /api/v1/transaction/status?trxid = 111
Get
Response : {
currentStatus : "Success",
updatedDate:
}
Fetch Account Balance
Sign: /api/v1/account/fetchBalance
Get
Response : {
totalBalance : 121233
}
Initiate payment
Signature : /api/v1/pay
POST
requestpayload : {
senderid, receiverid, amount, currency, paymentmethodid, idempotencykey
}
In order to build an online payment system we will divide the system into 2 parts
Synchronous System -> In this a user interacts with the system and is expective an immediate response. The UI component will be hosted in S3.
In response, DNS service returns the internal URL of CDN which loads the app
A request to any of the backend server is routed to server via ALB. ALB efficiently forwards the request to the server. May be using round robin algorithm
A user request is served with various response which is capture by UI
One of the critical action that a user takes is payment initiation. Lets suppose user makes the transaction from his account to Receiver's account. If the account has sufficient fund then a confirmation popup is displayed and event for transaction is generated and send over a queue.
The system that process the fund is build using microservices. Since its a distributed system, we will use Saga design pattern. This design pattern will help in keeping the system fault tolerant. We will choreography instead of orchestrator. Each local transaction is either complete or failed. If completed then an event for next service is sent. If failed, then a compensating message / event is send back to the previous service. Hence, maintaining the atomicity.
Binding each service to a queue and setting redrive policy helps in building retry mechanism in the system. Also, each listener has a DLQ that ensures in case of failure message is not lost.
Once all the trx is complete an event is pushed for Notification service which then send email alert or SMS alert.
Each user event is captured and is send over apache kafka. Using sliding window algorithm those events are processed for any suspicious activity being carried out at the account level. Lets suppose an invalid password is entered against a username then after a certain retry, the user accoutn is blocked for atleast 24hrs. This avoid any fraud transaction.
There is also a scheduler running in the background which actually unblocks the blocked account which has been blocked for more than 24hrs.
For Storing The User Details
User Table
id
firstName
lastName
emailAddress
mobileNum
isKycConfirmed
isEmailValidated
isActive
createdDate
UpdatedDate
DeletedDate
Address Table
id
streetName
addressLine1
addressLine2
addressLine3
city
zip
state
country
createdDate
updatedDate
userId
PaymentMethods Table
id
userid
paymentMethod
cardtype
cardNum
validDate
cvv
upiid
transaction Table
trxId
senderId
receiverId
amount
isTrxSuccess
payMethodId
Since, its a payment system it is important that ACID principle is followed. Since relational database support ACID properties, choosing SQL would be a better approach. SQL database also supports in managing the concurrency and transactions are better handler in SQL database.
In order to design or build such a system we will take the help of 2 approach mentioned below
a ) Client-Server architecture - This helps in letting client interact with the platform. It will support different APIs that a client need in order to interact or make calls with the system.
This again is broken into 2 piece
1) UI -> Since I am familiar with Angular, I will choose this to build my UI. UI is deployed on an S3 storage in AWS. Couple of advantage that we get out of this is its very low cost to deploy the UI on S3. Also, we can place CDN in front to improve the overall load time and hence improving the user experience.
2) Backend - We deploy our containerized backend into EKS cluster. Again, since its a EKS, we can define the maximum number of replicas that should be spawned in case load comes. Also, we can configure our K8S to define the threshold that EKS engine will use to spawn the new pod.
b) Microservice architecture - This offloads the task that a user is not dependent upon . For ex - Notification service. Whenever any transaction happens, an event is pushed to a queue which is then listened by listener or consumer for sending the notification.
We will use Kubernetes as a platform to manage our containerized application. We can easily provision horizontal scaling in case of load shoot.
Couple of important aspects that before impl payment systems are below
Maintaining Atomicity : Since payment processing is a background process and its a distributed architecture, we will build it using Saga design pattern (Using choreography). Each service has its own dedicated database and each local transaction happens at the service layer. Once done, either a success message is sent to the next service or if failure happens then a compensating message is send back to the originating service which then does the compensating transaction. This ensures the overall transaction is atomic in nature.
Handling Gateway timeout : Trx may also fail because of the external service which the service connects for initiating the payment is getting timedout. This can be tackeled by incorporating retry mechanism. Payment service route will have a retry mechanism which allows the events to be processed twice. Since, system allows retry, its important that idempotency is brought into the picture. Each event is given a uniqueid which is saved in database to handle that a trx is done only once.
Handling Serialilization -> This is another aspect since there could be concurrent trx happening for the same account. To ensure, that each transaction happens in isloation we will use pessimistic locking.