{"id":17215583,"url":"https://github.com/paambaati/pickyourtrade","last_synced_at":"2026-01-19T06:01:47.183Z","repository":{"id":37716750,"uuid":"191369888","full_name":"paambaati/pickyourtrade","owner":"paambaati","description":"⚡️A portfolio tracker built on Node, TypeScript, Vue/Buefy \u0026 SQLite3","archived":false,"fork":false,"pushed_at":"2023-01-07T06:20:37.000Z","size":1377,"stargazers_count":3,"open_issues_count":36,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-04-06T07:29:09.858Z","etag":null,"topics":["buefy","bulma","koa","koa2","node","nodejs","pickyourtrail","sqlite3","typescript","vue","vue-router","vuex","webapp"],"latest_commit_sha":null,"homepage":"","language":"HTML","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"wtfpl","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/paambaati.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-06-11T12:45:17.000Z","updated_at":"2022-08-31T00:13:57.000Z","dependencies_parsed_at":"2023-02-06T13:46:23.321Z","dependency_job_id":null,"html_url":"https://github.com/paambaati/pickyourtrade","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/paambaati/pickyourtrade","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/paambaati%2Fpickyourtrade","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/paambaati%2Fpickyourtrade/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/paambaati%2Fpickyourtrade/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/paambaati%2Fpickyourtrade/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/paambaati","download_url":"https://codeload.github.com/paambaati/pickyourtrade/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/paambaati%2Fpickyourtrade/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28562237,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-19T03:31:16.861Z","status":"ssl_error","status_checked_at":"2026-01-19T03:31:15.069Z","response_time":67,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":["buefy","bulma","koa","koa2","node","nodejs","pickyourtrail","sqlite3","typescript","vue","vue-router","vuex","webapp"],"created_at":"2024-10-15T03:24:53.090Z","updated_at":"2026-01-19T06:01:47.140Z","avatar_url":"https://github.com/paambaati.png","language":"HTML","funding_links":[],"categories":[],"sub_categories":[],"readme":"# 💰 PickYourTrade\nA portfolio tracker built on Node, TypeScript, Vue \u0026 SQLite3.\n\nℹ Note that this project was **purpose-built for a coding challenge** (see [problem statement](PROBLEM-STATEMENT.md)), and isn't actually meant to be used as anything useful other than serving as boilerplate/example for a Node/Koa + Vue.js app.\n\n## ⚙️ Setup\n\n### Quick-Start\n\nJust paste these into your terminal console (you can substitute `npm` with `yarn` if you'd like).\n\n1. `git clone git@github.com:paambaati/pickyourtrade.git`\n2. \u003cdetails\u003e\n        \u003csummary\u003eDocker\u003c/summary\u003e\n\n        docker-compose up --build\n        # Now open http://localhost:2000\n    \u003c/details\u003e\n\n    \u003cdetails\u003e\n        \u003csummary\u003eNon-Docker\u003c/summary\u003e\n\n        cd pickyourtrade/app \u0026\u0026 npm install \u0026\u0026 npm run serve\n        # Open a new terminal\n        cd pickyourtrade/server \u0026\u0026 npm install \u0026\u0026 npm run debug\n        # Now open http://localhost:8080\n    \u003c/details\u003e\n\n### Running Tests\n\n1. `cd pickyourtrade/app \u0026\u0026 npm test`\n2. `cd pickyourtrade/server \u0026\u0026 npm test`\n\n### Developer Notes\n\nNote that the tests are not extensive. The current test suite covers all aspects of testing a Vue app, so it can be used as boilerplate to finish up the rest.\n\n## 👩🏻‍💻 Technology Choices\n\n### Why Node.js?\n\n1. Fully non-blocking \u0026 asynchronous.\n2. Not a CPU-intensive workload.\n3. Easy of use and wealth of community packages (for example, we use [Koa](https://koajs.com/) for the core API server).\n4. Same language as the frontend!\n\n### Why SQLite3?\n\n1. Embeddable, so portable and no additional setup.\n2. Very fast and capable \u003csup id=\"a1\"\u003e[[1]](#f1)\u003c/sup\u003e\u003csup id=\"a2\"\u003e[[2]](#f2)\u003c/sup\u003e for simple workloads (all the app uses is `SELECT` \u0026amp; `INSERT`).\n3. Has an in-memory mode too, which is _much_ faster than disk-backed mode.\n4. The database size is relative small (a million portfolio records occupies ~120MB of disk space).\n\n## 📈 Scale\n\nThe current version of the app is built on Node.js for the backend API, and uses SQLite3 for the database.\n\n### Benchmarks\n\n[`vegeta`](https://github.com/tsenart/vegeta#limitations) was used to benchmark a cold-started version of the app running SQLite in disk-mode. Write benchmark tries to send 1k `PUT` requests (1k `INSERT`s), and the read benchmark tries to send 1k `GET` requests (1k `SELECT`s) on sample data of 100 records.\n\nThe benchmarks can be recreated with [`benchmarks/run.sh`](https://github.com/paambaati/pickyourtrade/blob/master/benchmarks/run.sh).\n\n```\nINSERT Benchmark Results\n\nRequests      [total, rate]            1000, 1001.06\nDuration      [total, attack, wait]    999.401273ms, 998.943484ms, 457.789µs\nLatencies     [mean, 50, 95, 99, max]  1.273438ms, 519.687µs, 3.201523ms, 22.237725ms, 24.941809ms\nBytes In      [total, mean]            0, 0.00\nBytes Out     [total, mean]            285000, 285.00\nSuccess       [ratio]                  100.00%\nStatus Codes  [code:count]             200:1000\n```\n\n```\nREAD Benchmark Results\n\nRequests      [total, rate]            1000, 1001.07\nDuration      [total, attack, wait]    8.917441283s, 998.930366ms, 7.918510917s\nLatencies     [mean, 50, 95, 99, max]  4.807794447s, 4.746398003s, 8.281871586s, 8.332671972s, 8.34698592s\nBytes In      [total, mean]            0, 0.00\nBytes Out     [total, mean]            0, 0.00\nSuccess       [ratio]                  100.00%\nStatus Codes  [code:count]             200:1000\n```\n\nREAD Benchmark (Disk)      |  WRITE Benchmark (Disk)\n:-------------------------:|:-------------------------:\n![READ Benchmark Plot](benchmarks/results/read.png) | ![WRITE Benchmark Plot](benchmarks/results/insert.png)\n\nThese numbers show that the current version of the app _can_ scale to 1000 concurrent users.\n\n### Scaling Beyond 1k Users\n\nBefore we scale-up this solution, we'll need some numbers around usage characteristics —\n\n1. Is the app read-heavy or write-heavy?\n2. Do the read and write times deteriorate over time with more users onboarded? If yes, by how much? How many of the users are impacted by this? This is where baseline and periodic performance metrics help.\n3. What is the average size of a single row of data? What is the average size of a user's portfolio (`average row size * no. tickers average user has`)?\n4. What kind of data can be cached? If there's candidates for caching, it might be worthwhile building a cache layer (perhaps a in-memory cache or a lean K-V store like Redis).\n\nWith these numbers in place, we can then try to find performance bottlenecks. Possible bottlenecks are —\n\n| **Bottleneck** | **Causes** | **Solutions** |\n|---------------------------------|--------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------|\n| Slow DB read/writes. | 1. Slow disk. 2. Low free RAM (only in memory mode). | 1. Upgrade to SSD/NVMe/IOPS-optimized storage. 2. Upgrade RAM. |\n| Too many open HTTP connections. | 1. Long-running connections. 2. Too few open handles. | 1. Identify root cause for long-running connections and fix them. 2. Fine-tune `sysctl`. |\n| Memory leaks. | 1. Too many global variables. 2. Very big closures that cannot be GC'ed fast enough. 3. Unbound collections that can grow unchecked. | 1. Avoid global variables. 2. Use closures sparingly. 3. Always set upper bounds for any collection data structure. |\n| Segmentation faults and/or crashes. | 1. V8 is running out of memory to use, as it it's heap size is limited 1GB on 64-bit systems. | 1. Tune [`--max-old-space-size`](https://nodejs.org/api/cli.html) to make sure V8 can use all available RAM. |\n| Very high response latency and/or connection drops. | 1. User's data has grown too big. | 1. Lazy load (i.e. paginate data) on the frontend. |\n\n🚩 Some of the causes \u0026 solutions might be specific to Node.js.\n\n#### Horizontal Scaling \u0026 Choice of Database\n\nNote that most of the solutions discussed above are to vertically scale the app. In most cases however, the database is the biggest bottleneck of any app. As the app's userbase scales rapidly, it might be considering a **distributed** database. Based on the app usage metrics and our performance baseline metrics, an appropriate database can be chosen to replace SQLite; any database that can provide easy replication would let us horizontally scale.\n\n📣 A _personal_ recommendation would be [RethinkDB](https://www.rethinkdb.com/) — it is built from the ground-up for the real-time web (especially great for streaming data), and so would be a great match to build more features like a live updating ticker\u003csup id=\"a3\"\u003e[[3]](#f3)\u003c/sup\u003e. Out of the box, it has sharding/replication, fantastic documentation, a very well thought-out admin UI and a fun query language\u003csup id=\"a4\"\u003e[[4]](#f4)\u003c/sup\u003e that feels great to use in JS-land.\n\n## 📝 Footnotes\n\n\u003cb id=\"f1\"\u003e1\u003c/b\u003e [What are the performance characteristics of SQLite with very large database file?](https://stackoverflow.com/questions/784173/what-are-the-performance-characteristics-of-sqlite-with-very-large-database-file). [↩](#a1)\n\n\u003cb id=\"f2\"\u003e2\u003c/b\u003e [SQLite Limits](https://www.sqlite.org/limits.html). [↩](#a2)\n\n\u003cb id=\"f3\"\u003e3\u003c/b\u003e [RethinkDB Changefeeds](https://www.rethinkdb.com/docs/changefeeds/javascript/). [↩](#a3)\n\n\u003cb id=\"f4\"\u003e4\u003c/b\u003e [ReQL Ten-minute guide](https://www.rethinkdb.com/docs/guide/javascript/). [↩](#a4)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpaambaati%2Fpickyourtrade","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpaambaati%2Fpickyourtrade","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpaambaati%2Fpickyourtrade/lists"}