MVP of an API to create accounts with balances of different currencies, where the customers will be able to deposit, send funds to other customers and exchange ("swap") their funds between currencies.
- Install the libraries:
./mvnw install
- Run the unit tests:
./mvnw test
- Build a docker image:
docker build -t accounts/international .
- Run the docker container:
docker run -p 8080:8080 accounts/international
You can access swagger to check the API Documentation through http://localhost:8080/swagger-ui/index.html
The API allows the basic functionalities of an "Account" system where customers can create accounts, balances for those accounts, send funds between each other and exchange their own funds from one currency to another. It's important to notice that for this MVP I am not using authentication and are not actually persisting the data, I instead use an in-memory service to store the data while the api is running.
Also, for simplicity's sake I am using the customers' emails as an unique property and this email
field will be used as a key/id for the accounts.
Also to make it simple, I have limited the creation of balances for 3 currencies: USD, CAD and EUR.
Other than the documentation provided by Swagger, I have also provide provide a postman collection containing the endpoints with their payloads: international_accounts.postman_collection.json
PS: The Swagger api documentation could be a bit better documented but due to time constraints even though not ideal it will hopefully be enough to understand how to use the API.
POST /accounts/create
: Creates an accountPOST /accounts/create-balance
: Creates a balance for the account specified through the email field- PS: when creating a balance, we have defined a field
yearlyInterestRate
where we will be paying out a certain % over the funds the customer has in his balance at the beginning of every month.
- PS: when creating a balance, we have defined a field
POST /accounts/deposit
: Deposit funds into a customer's account balance, looking for an account that matches the email on the payload and a balance with a currency provided on the payloadPOST /accounts/send
: Allows the customers send money to each other with zero feePOST /accounts/swap
: Allows the customers to exchange funds between their own balances. for this service a % fee is charged. For that there is a variable defined on the application.properties:service.fee=0.01
GET /accounts/{email}
: given an email, Get the customer's account informationGET /accounts/{email}/transactions
: given an email, Get the customer's account transactions
the ScheduleTasks class is responsible to run all jobs on the server and as of now there is only one job.
the payoutInterestRates
method will run at the beginning of every month and will check whether the account balances were created more than a month ago
- if so the balances will receive the full interestRate for that month (considering the amount of the balance by the time this job runs),
- if the account is not older than 1 month, the customer will receive the interest proportionally (for example, if the balance was open for 15 days, he will get half of the interest).
- Code: The current version doesn't care if the user has added a bigger amount on the last day of the month and it would still pay him the interest on top of the current balance. I'd ideally want to pay the customer for the money that was there during the whole month, not only the last day, so it'd be better to keep track of any balance changes to then be able to know how long an amount of money was there for what period.
- Infrastructure: The first step to make this job more secure would be to extract this job from the api and run it on a different service.
Also, for simplicity's sake I have create a simple RatesService with hardcoded exchange rates that simulate an api call.
Once again, for simplicity's sake I have create a simple InMemoryService that will store accounts and transactions in memory while the api is running. the 2 main models are: Account and Transaction.
- Account: Responsible to keep the general information of the customer's account and also keep the balances for all currencies.
- PS: If getting out of the MVP, it could make sense to create snapshots to keep track of the events where the user change its balances.
- Transaction: Responsible to state when a user has done a transactions
- PS 1: If getting out of the MVP, it could make sense to have a transaction for each customer involved. for example a customer that will be receiving a "transfer" would have a
CREDIT
transaction related to him and the customer sending that "transfer" would have aDEBIT
transaction. This would make it cleaner to not only improve performance but also keep track of how much money was in and/or out of each user and also the system. - PS 2: It could make sense to keep a separate transaction everytime there is a fee to easily group fee transactions and easily identify how much is going to the platform. Maybe a platform Account would also make sense.
- PS 1: If getting out of the MVP, it could make sense to have a transaction for each customer involved. for example a customer that will be receiving a "transfer" would have a