Wallet simulation
Prequisite
- This application use Node 14.
- SQLite (included)
First start
- Run
yarn install
- Run
npx sequelize-cli db:migrate
to migrate the database - Run
npx sequelize-cli db:seed:all
to seed base data
Start up the application
You can either run node ./src/app.mjs
or yarn dev
. This will start up the application in dev mode
TODO:
- Add currency conversion method with external API
- Allow cross currency transfer with conversion fee
- Specs
API Documentation
This application use GraphQL as an API layer and can be reach on path /graphql
All amount in this application stored as Integer. To be able to display properly, please divide by 100 when trying to display
Query
Accecssing User Information
user(id: ID!): User
Return user attributes, including cards and wallet as a graph node
Example:
query($id: ID!) {
user(id: $id) {
name
wallets {
id
balance
currency
}
cards {
id
cardNumber
currency
ccv
status
}
}
}
----------
{
"id": 1
}
View Ledger
ledger: [Transfer]
Allow accessing list of all transaction made by the application.
Example:
query {
ledger{
timestamp
transferedAmount
originCurrency
targetCurrency
conversionFee
originEntityType
originEntityId
targetEntityType
targetEntityId
}
}
Mutations
Create a wallet
createWallet(user: ID!, currency: CurrencyEnum): Wallet
Variables:
userId
: ID of the usercurrency
:CurrencyEnum
(usd|eur|gbp)
Output: Wallet
Description: This method allow user to create a wallet with a starting amount of 0.
Query Example:
mutation($user: ID!, $currency: CurrencyEnum!) {
createWallet(user: $user, currency: $currency) {
id
currency
balance
isMasterWallet
}
}
--------
{
"user": 1,
"currency": "EUR"
}
Create a card
createCard(walletId: ID!): Card
Variables:
walletId
: The related wallet to create card from
Output: Card
Description: This method generate a card and activate it by default with a blance of 0.
Query Example:
mutation($walletId: ID!) {
createCard(walletId: $walletId) {
id
status
balance
currency
cardNumber
ccv
status
}
}
------------
{
"walletId": 3
}
Transfer money between any pair (Wallet, Card)
loadMoney(amount: Int!, fromType: entityTypeEnum!, fromId: ID!, toType: entityTypeEnum!, toId: ID!): Transfer
Variables:
amount
: Amount in cent. 1$ = 100.fromType
:entityTypeEnum(card|wallet)
fromId
: Source wallet / card to transfer fromfromType
:entityTypeEnum(card|wallet)
toId
: Target wallet / card to transfer to
Output: Transfer
Description: Transfer money from Wallet / Card to another Wallet / Card
Query Example:
mutation($amount: Int!, $fromType: entityTypeEnum!, $fromId: ID!, $toType: entityTypeEnum!, $toId: ID!){
loadMoney(amount: $amount, fromType: $fromType, fromId: $fromId, toType: $toType, toId: $toId) {
timestamp
transferedAmount
originCurrency
targetCurrency
conversionFee
originEntityType
originEntityId
targetEntityType
targetEntityId
}
}
--------
{
"amount": 100,
"fromType": "wallet",
"fromId": 1,
"toType": "card",
"toId": 1
}
Block a card
blockCard(id: ID!): Card
Variables:
id
: Card Id
Output: Card
Description: Block a card from being able to transfer money
Query Example:
mutation($id: ID!) {
blockCard(id: $id) {
id
status
}
}
--------
{
"id": 1
}
Type definitions
type Card {
id: ID!
wallet: Wallet
currency: CurrencyEnum
balance: Int
cardNumber: String
exp: String
ccv: Int
user: User
status: Boolean
}
enum CurrencyEnum {
usd
eur
gbp
}
enum entityTypeEnum {
card
wallet
}
type Mutation {
createWallet(user: ID!, currency: CurrencyEnum): Wallet
createCard(walletId: ID!): Card
loadMoney(
amount: Int!
fromType: entityTypeEnum!
fromId: ID!
toType: entityTypeEnum!
toId: ID!
): Transfer
blockCard(id: ID!): Card
}
type Query {
user(id: ID!): User
ledger: [Transfer]
}
type Transfer {
id: ID!
timestamp: Int
transferedAmount: Int
originCurrency: CurrencyEnum
targetCurrency: CurrencyEnum
conversionFee: Int
originEntityType: entityTypeEnum
originEntityId: ID
targetEntityType: entityTypeEnum
targetEntityId: ID
}
type User {
id: ID!
name: String
wallets: [Wallet]
cards: [Card]
}
type Wallet {
id: ID!
balance: Int
isMasterWallet: Boolean
currency: CurrencyEnum
company: String
}