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 transaction
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.