System requirements
Functional:
List functional requirements for the system (Ask the chat bot for hints if stuck.)...
- Users should be able to transfer money from bank account into payment system and vice versa, as transaction.
- Users should be able to send money to other users in the payment system and vice versa, as transaction.
- Users should be able to add/edit their profile
- Users should be able to add and remove bank account.
- Users should be able to view historical transactions.
- The account will be highly secure: user identity can't be faked.
- The system will detect suspicious transactions and alert users, and may withhold the transaction until user approve.
- The transaction is highly consistent, user won't lose and get money out of nothing.
- Transaction will be denied if sender has insufficient fund.
- Receivers and senders of transactions can use different currency.
- How currency exchange rate is determined, is out of the scope.
- Authentication is super critical to the system, however it's domain specific and will be out of scope for the design.
- User will be able to view and edit their profile and account information. However it won't be the focus of the design, as it's quite general.
Non-Functional:
List non-functional requirements for the system...
- The system should support billions of users worldwide, with acceptable performance.
- The system should be able to process tens of billions of transactions each day with acceptable performance.
- All user data should be retained lifelong.
- The system is highly consistent, no data will be lost.
Capacity estimation
Estimate the scale of the system you are going to design...
- Data for Transactions
- Assume 10Billion transactions per day, and each transaction comprised of 100 byte of data; the estimation covers capacity for the next five years.
- Storage = 10 billion * 100 * 5 * 365 byte, which is roughly 2 Pera Bytes
- Data for User Profile:
- Assume 1 billion users, and each user consists of 1000 bytes of data(profile, contact, bank account, setting)
- Storage = 1 billion * 1000 byte, which is roughly 1 tera bytes.
API design
Define what APIs are expected from the system...
- Api Send Money : (send money to user in the system)
- Parameters:
- sender id
- receiver id
- amount
- time
- location
- Response:
- success or fail
- error message
- Parameters:
- Api Transfer Money(move money into or out of the system):
- Parameters:
- type: move out or move in
- user id
- account id
- amount
- Response:
- success or fail
- error message
- Parameters:
- Api add bank account:
- Parameters:
- user id
- bank account number
- bank routing number
- Response:
- success or fail
- error message
- Parameters:
- Api remove bank account
- Parameters:
- user id
- bank account id
- Response:
- success or fail
- error message
- Parameters:
- Api: get transaction history
- Parameters:
- user id
- time range
- Response
- List<transaction info >
- Parameters:
Database design
Defining the system data model early on will clarify how data will flow among different components of the system. Also you could draw an ER diagram using the diagramming tool to enhance your design...
- User Profile - relational db, shard by user id
- Schema
- user id - pk
- first name
- last
- phone
- address
- social security number - encrypted
- password - encrypted
- Schema
- User Account - relational db, shard by user id
- Schema
- user id - pk
- transaction id - pk
- start
- end
- amount
- timestamp
- currency
- Schema
- Bank Account - relational db, shard by user id
- Schema
- user id - pk
- account id - pk
- bank account number - encrypted
- routing number - encrypted
- currency
- Schema
- Transaction - relational db, shard by transaction id
- Schema
- transaction id- pk
- sender id
- receiver id
- location
- time
- amount
- type - user to user; user to bank; bank to user
- state
- Schema
High-level design
You should identify enough components that are needed to solve the actual problem from end to end. Also remember to draw a block diagram using the diagramming tool to augment your design. If you are unfamiliar with the tool, you can simply describe your design to the chat bot and ask it to generate a starter diagram for you to modify...
- API Services - responsible to take user request
- send money service
- transfer money service
- get transaction history service
- add/remove account service
- Storage - responsible to store data in Database design section
- User Account DB
- Bank Account DB
- Transaction DB - this will be critical piece of the system. As further post processing system read from and update this db to ensure data is consistent, even upon failure.
- Post Processing Service: based on state of transaction, execute the change and complete the transaction.
- Send money transaction processor:
- performs fund validation, fraud detection, deduct fund from sender, and add fund to receiver. If any of the step fails, it will keep retrying, leveraging transaction id for idempotency.
- if any of the step fails exceeding a threshold, issues a compensation transaction to undo the transaction.
- Upon each step, it updates transaction's state column in db, to ensure processing can be picked up from different sessions.
- Only one transaction can process one transaction, in other words, a transaction won't be processed by more than more processor each time. Implemented by db row locking mechanism.
- Fraud detection service: given a transaction information, performs prediction whether the transaction is likely to be fraud. Usually done by machine learning (regression for example).
- Transfer money processor handles
- transferring money from the system out into the bank
- as well as transferring money from external bank into the system
- The gist is the same as previous processing, aka executing transaction based on its state; update its state upon each execution; issue compensation transaction if transaction can't be finished.
- The difference is that the sender or receiver is an external bank system, and our system interact with it through api calls.
- Notification Service: consumes change from user account db and transaction db, in order to notify important changes to appropriate state holder
- Send transaction update (fraud validation, send money success, received money from XXX) to user, potentially in frequency based on users preference, to reduce spamming.
- Send alert to system admin, if compensation transaction fails; or system imposes abnormal behavior.
- Send money transaction processor:
Request flows
Explain how the request flows from end to end in your high level design. Also you could draw a sequence diagram using the diagramming tool to enhance your explanation...
- Send money (assume that the application already validates that sender id and receiver id is correct):
- online: user make request to the api server -> service creates a transaction -> notify user
- offline: processor verifies sender user account has sufficient fund deduct the amount (through transaction) -> passes fraud detection -> service adds the amount to receiver id -> server adds a record in transaction db -> server return success to user (or failure if account has insufficient fund
- offline: notify user of transaction completion or failure or being marked as fraud
- Get transaction history: get transaction history service get transaction ids from user account db -> reads transaction information from transaction db -> return information to user
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...
- Concurrency in Send money api: the service creates an entry in transaction db and get the transaction id back -> service . The execution of transaction is handled by transaction processor.
- Transaction processor checks user account making sure sender has enough fund before deducting the amount. However, the user might be sending current requests. Without any handling, the operations may interleave, an error could occur that would bring the amount to negative. The service instead, put the check funding and deduct from funding into one transaction. Hence making the request sequential. Similarly, when adding the amount to the receiver, it's also in a transaction.
- Once the update is done, notification service will pick up the change and send update to user with frequency based on their selection.
Trade offs/Tech choices
Explain any trade offs you have made and why you made certain tech choices...
- To mitigate concurrency issue in send money service, the system chooses transactions over other mechanisms for the ease of development.
- Instead of using a single value represent the balance of user account, we use an entry of account changes imposed by each transactions. This ensures the idempotency of the system.
- Instead of having the api service update account, we dedicate the work to an offline transaction processor, this enables more complex functionalities like performing fraud detection before executing the transaction.
Failure scenarios/bottlenecks
- There could be dead lock in send money service, where two users might be sending money to each other concurrently.
- Data could be in inconsistent state, if one of the operation in a transaction fails to execute. For example, receiver account fail to increment, while the money already gets deducted from user account. In this case, the get money service will issue an refund transaction. In case of refund transaction failing, this would trigger manual handling.
Future improvements
What are some future improvements you would make? How would you mitigate the failure scenario(s) you described above?
- For deadlock in send money service, the system could potentially add a timeout.