All endpoints are in this link
Auth service is designed to seperate user authentication credentials from the user detail that might increase in the future. NoSQL database will be used in this service since the data is very simple, and to be flexible for any change in the future.
-
Schema
authId email password ObjectId string string required required required
User service is designed with NoSQL database to be flexible for any features in the future. For example, users might have connection or friends with other users, which will be store in graph data structure.
-
Schema
authId email name walletAddress ObjectId string string string required required required allowNull
The transaction data should be stored in SQL database due to the structure itself, especially with double-entry bookkeeping for full tracebility.
-
ER Diagram
-
Schema and example of tables storing data
Suppose there are 3 users: A, B, and C.
- User A connect with wallet WA01
- User B connect with wallet WB02
- User C connect with wallet WC03
After that
- User A transfers 200 GEM to User B --> returning TX1 hash
- User C transfers 100 GEM to User A --> returning TX2 hash
Tables will look like this
authId | walletAddress |
---|---|
A | WA01 |
B | WB02 |
C | WC03 |
hash | from | to | method | amount | gas | block | blockHash | nonce |
---|---|---|---|---|---|---|---|---|
TX1 | WA01 | WB02 | Transfer | 200 | 178920 | 213344 | BX213 | 33 |
TX2 | WC03 | WA01 | Transfer | 100 | 165433 | 213345 | BX214 | 34 |
userAuthId | txHash | isCredit | accountType |
---|---|---|---|
A | TX1 | true | Revenue |
B | TX1 | false | Cash |
C | TX2 | true | Revenue |
A | TX2 | false | Cash |
- Client creates account by
POST /api/v1/auth/signup
, using email, receiving back JWT token - Frontend attach the token to header.
- Client creates user connected to the
authId
, add name, and maybe other attributes in the future. UsingPOST /api/v1/user/
in user service.
- Frontend
GET /api/v1/user/message
to get certain message from the backend, pop up it to metamask, and let user sign the message to get thesignature
. - Frontend
POST /api/v1/user/connectWallet
withsignature
and client'swalletAddress
- Backend will verify that the client is the real owner of
walletAddress
, and update the database of the client withauthId
attached inJWT token
- User service then publishes
UserUpdatedEvent
. - Transaction service listens
UserUpdatedEvent
and create the user in it own database.
Once user connect wallet to our platform, they are allowed to do transaction (in fact, the platform will not record the transaction in the database because I don't really know how to prevent them from doing transaciton outside the platform, since it's blockchain).
-
From the assignment, it said in the endpoint example that
User able to transfer GEM to another user with correct permissions
-
After doing researches, I've found 4 approaches,
- Backend calls
transfer
with user private key - Let user approve and Backend use
transferFrom
with my hardcoded private key. - Frontend let client sign
transfer
transaction and send back to Backend to proceed. - Frontend let client call
transfer
themselves and send backtxHash
to Backend to proceed.
- Backend calls
-
However, approach
i
is impossible since the private key should not leave the client. Approachii
requires trust from client. Approachiii
This seems to be great approach since the signed transaction cannot be manipulated by anyone. Unfortunately, I can't figure out how to do it right now. Therefore, approachiv
is the only possible approach that I found and can use in this assignment. -
So, after client transferred token, browser wallet will return transaction hash. Then, Frontend can send the hash to backend, using
POST /api/v1/transaction
to proceed.
- Backend extract the transaction receipt from the hash. Check if those two users who did the transaction are in the platform or not. If not, it will not write the data in the database. If yes, proceed to the next step.
- For
double-entry bookkeeping
, transaction detail will be stored inTransaction
table, and theTransaction_Record
will seperate the transaction detail into two sides which are theFrom
side and theTo
side, and store with their owndebit/credit
andaccountType
.
node
docker
kubernetes
skaffold
skaffold dev
- Get pods
kubectl get pods
- Map port from the pod inside kubenetes cluster to your local machine
kubectl port-forward <pod> <outsidePort>:<insidePort>
skaffold dev --port-forward
- port 3001 - auth-service
- port 3002 - user-service
- port 3003 - transaction-service
*cd to each directory seperately first
-
Install dependencies
npm install
-
Run locally
npm run local
**Note that npm run local
will by pass database and nats environment vaiables and their connection, but you still can connect to the database with your own credentials and remove the bypass line.
*cd to each directory seperately first
npm run test
Since the project is not entirely considered finished. Here's the todo list of what I intended to do
- Write and end-to-end test to test that all services can work together with frontend.
- Implement Redis for transaction service.
- Fix CI test of transaction. It is broken because it cannot connect to postgres, I remove it for now.
- The app could be deploy in any cloud provider. I implemented
logger
which will write the logs in tolog
folder inside each service. So we could grab the file from the cloud provider and debug as it increases in complexity. - In the future, I expect that there will be more transaction type where users are not only transfer token but do something else as well. The transaction service is designed to be able to keep track of many
TransactionMethod
andAccountType
. In addition, for full accounting system, we could implement a balance sheet for tracebilty as well. - As the number of user increases, we can implement caching for other services, proxy and load balancing.