System requirements


Functional:

  1. User Account Management:
    • Users must be able to create, update, and delete their accounts.
    • Users should have options to manage personal information, linked bank accounts, credit cards, and security settings.
  2. Payment Processing:
    • Users should be able to send and receive payments seamlessly.
    • The system needs to support multiple payment methods, including bank transfers, credit/debit cards, and digital wallets.
    • It should also process transactions in various currencies and exchange rates.
  3. Transaction History and Reporting:
    • Users must have access to their transaction history, including details of payments sent and received.
    • The system should allow users to generate reports about their financial activities over specific periods.




Non-Functional:

  • System should handle 100M users, and 1million transactions per hour
  • We need strong consistency in terms of moving and keeping track of money.
  • We need durability also; transactions should not be lost. We need to support audit of transactions.
  • System should be highly secure, in terms of preventing fraud. Make sure users are robustly authenticated.
  • User interactions when making transactions should be real time. Less than 5s to complete a transaction.



Capacity estimation

Lets work with 100M users, and a peak of 1M transactions per hour.

Storing user data for 100M users, assuming 10kB each is 1TB.

1M transactions of 1kB each = 1GB per hour

1M transaction per second is about 300 operations per second.


API design

CRUD operations for User Profile

E.g.

POST /user -> user-id

{

name

email-id

}

POST /user/linked_accounts -> linked_account_id

{

bank-name

bank-routing-number

bank-account-number

bank-auth-token

}

GET /user -> UserData

{

name

email-id

accounts [

{

linked_account_id

bank-name

bank-routing-number

bank-account-number

bank-auth-token

},

...

]

}

POST /user/transaction -> server-transaction-id

{

client-transaction-id

other-user-id

amount

currency

}

GET /user/transactions?page=xxx?num_entries=yyy -> Transaction[]

Transaction {

type # send or receive

other-user-id

status

createdAt

updatedAt

amount

currency

}




Database design


User

  • user-id (primary-key)
  • user-name
  • password
  • balance


Linked-Account

  • user-id
  • linked-account-id (primary-key)
  • bank-name
  • bank-routing-number
  • account-number


Transaction

  • sender-client-transaction-id
  • server-transaction-id (primary-key)
  • sender-user-id
  • receiver-user-id
  • sender-linked-account-id
  • sender-linked-account-transaction-id
  • receiver-linked-account-id
  • receiver-linked-account-transaction-id
  • amount
  • currency
  • status
  • createdAt
  • updatedAt


High-level design

Clients connect to us via the API gateway load balancer into the front end service. front end service terminates these connections. It modifies the post crest database, or reach the post database for operations on user options and on linked accounts for transactions it sends request onto the kafka message queue. We have transaction workers that pick messages off of the queue and actually carry out the transactions. As they move the transactions through various states they update the transaction objects in the postgres database. To actually carry out the transactions, the transaction worker sends messages to the bank Gateway. The bank gateway is used to first move money from the senders account to our own account. Then it moves money from our own account to the receivers account.







Request flows

Let's talk about how transactions work. Clients send requests to the front end via the API Gateway. The front end and cues this request onto the message queue. The request is picked up by the transaction worker. now the transaction worker needs to carry out a number of steps. first it needs to move money from the senders account to our account. Then it needs to move money from our account into the receiving account. for each of these steps it sets a local timer and puts a message on the message Q for the bank Gateway to carry out the action and expects the bank Gateway to reply with success or failure. Since we have also set a timer, we handle timeouts as well. The state of the transaction is updated in postgres. The transaction worker also checkpoints all its progress for a given transaction back to the Kafka message q.





Detailed component design

Dig deeper into 2-3 components and explain in detail how they work. For example, how well does each component scale? Any relevant algorithm or data structure you like to use for a component? Also you could draw a diagram using the diagramming tool to enhance your design...






Trade offs/Tech choices

Explain any trade offs you have made and why you made certain tech choices...






Failure scenarios/bottlenecks

Front ends terminate connections from the client. If they fail, the client will reconnect to another front end. Transaction workers use a consumer group to pick up messages from Kafka for transactions to initiate the key we can use here is the user ID initiating the request. For each step of the transaction, the transaction worker needs to send messages via the car Q to the bank Gateway and get the reply back on Kafka as well. The transaction worker sets timers locally to ensure that these operations complete it also checkpoints its progress back to the Kafka queue, so that in case the transaction, workers fail and other member of the consumer group can pick up the work and can read the checkpoint at state of these transactions and resume the timeouts if needed.





Future improvements

What are some future improvements you would make? How would you mitigate the failure scenario(s) you described above?