{"id":16409687,"url":"https://github.com/coderatio/exclusible","last_synced_at":"2026-05-14T21:02:06.823Z","repository":{"id":114097941,"uuid":"559504378","full_name":"coderatio/exclusible","owner":"coderatio","description":"A technical challenge from the Exclusible team","archived":false,"fork":false,"pushed_at":"2022-11-03T19:17:25.000Z","size":2330,"stargazers_count":0,"open_issues_count":0,"forks_count":2,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-01-06T00:30:57.005Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/coderatio.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-10-30T10:25:47.000Z","updated_at":"2022-11-03T16:56:10.000Z","dependencies_parsed_at":"2023-06-12T20:30:29.138Z","dependency_job_id":null,"html_url":"https://github.com/coderatio/exclusible","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coderatio%2Fexclusible","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coderatio%2Fexclusible/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coderatio%2Fexclusible/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coderatio%2Fexclusible/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/coderatio","download_url":"https://codeload.github.com/coderatio/exclusible/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":240405244,"owners_count":19796154,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-11T06:20:51.860Z","updated_at":"2025-11-14T22:14:26.396Z","avatar_url":"https://github.com/coderatio.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Exclusible Project\nThis project is a simple microservice architecture with two services(exchange rate and user api).\nThe services communicate through a message broker like Redis PubSub.\n\n### High-level Architecure\n![Architecture Diagram](https://i.imgur.com/erkLB4k.png)\n\n### Problem\nWhen building software solutions, it's good to understand the underlying problem. \nThis understanding enable us to build resilient and effective applications\nthat are easy to use, maintain and scale.\n\nFor this technical task, I see a problem with administrators of a system finding it\ndifficult to update rates and let user be aware of these changes in realtime.\nI also see an existing pattern of updating rates on a system that needs to be better.\n\n### Solution\nFor a task like, I'm tasked with the responsibility to provide a solution. And here are a few steps I'm taking.\n- Service that stream live rates from CoinmarketCap or Kraken Exchange\n- A service that shares these rates with another services where users' information are stored\n- A service that gets notified of new rates\n- A service that provides an endpoint for admin to add spread to exchange rate\n- Websocket with subscription for Exchange rate on the FE (connecting to\nexternal API or websocket)\n\nThese solutions are my assumptions and not what may seem!!\n\n### Technologies\nFor every problem given to an engineer, there will be tools needed to help them solve those problems.\nHere are the technologies used for this task.\n- JavaScript (Language)\n- Node.js (Run-time)\n- MySQL (Datastore)\n- Typescript (Typing)\n- Redis (Caching \u0026 PubSub)\n- Adonisjs (Framework)\n- Jest (Testing)\n- Japa (Testing)\n- Docker (Virtualization, Contanerization, Orchestration)\n- Socket.io (Websocket)\n\n### The Services\nAs earlier mentioned and seen on the high-level architecture above, we need two services, and they\nshould be able to communicate effectively with each other. Here are the services:\n1. #### Exchange Rate\n    - This service is responsible for getting rates from Kraken exchange via a websocket connection \n    - Publishing the rates to Redis\n    - Providing an endpoint to get rates via http\n2. User Api\n    - The service enable users to register, login and logout\n    - It's responsible for getting rates published by the exchange rate service through subscription\n    - It stores spread values on a DB table\n    - It provides an endpoint an Admin user to update rates\n    - It creates Websocket connection for the Frontend to stream live rates from\n    - It broadcasts live rates to the frontend\n    - It provides an endpoint for the frontend to get rates + spread via with http\n\n### How to use\n1. **Running Services**\n    \n    The two services and other depencies like MySQL and Redis, are all bundled into a docker container.\n    This means, we only need `Docker` on a machine to run the services. \n\n    1. You can run the services by executing the docker command below:\n    ```shell\n      docker compose up\n    ```\n   As soon as the container is running, you may run the command below to `ssh` into the services\n    ```shell\n      # Exchange rate\n      docker exec -it exchange-rate-service sh \n      \n      # User Api\n      docker exec -it user-api-service sh\n    ```\n   You need to `ssh` into the services to be able to run migrations and seeders. Here are the commands:\n    ```shell\n      node ace migration:\n   \n      # To Seed data on User Api, run this command\n      node ace db:seed\n    ```\n2. **API Documentation** \n\n    The documentation for all API endpoints are found on the link below:\n    [https://documenter.getpostman.com/view/6955209/2s8YY9vmW9](https://documenter.getpostman.com/view/6955209/2s8YY9vmW9)\n\n3. **Collection**\n   \n   Find link to the postman collection for all endpoints below:\n\n   [Exclusible Postman Collection](https://speeding-water-9901.postman.co/workspace/My-Workspace~0606ae7e-d708-4487-8d3b-046b2d7b854e/collection/6955209-92da7511-f31e-46a8-ad5d-ff32c883d342?action=share\u0026creator=6955209)\n### Websocket\nThe websocket server is accessible on the link below:\n```shell\nws://127.0.0.1:3334\n```\nAs soon as the `user-api-service` is running, you can make websocket connection the link above.\n1. **Websocket payload**\n```js\n{\n   BTC_USD: {\n      original: { buy: 20249, sell: 20249 },\n      withSpread: { buy: 20699, sell: 20682 },\n      currentSpread: { buy: 450, sell: 433 }\n   }\n}\n```\n2. **Websocket event**\n  \n   All rates are broadcasted through the `rates:live` event.\n### Misc\nI created a frontend page to demo rate streaming. You may access the page by visiting the link below. \nDo not forget to check out to the `ws-client-test` branch.\n```shell\nhttp://127.0.0.1:3334/ws-test/\n\n# Ensure you switch branch to \"ws-client-test\"\n\n```\n![Websocket Test](https://i.imgur.com/39J3CKW.png)","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcoderatio%2Fexclusible","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcoderatio%2Fexclusible","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcoderatio%2Fexclusible/lists"}