{"id":46089127,"url":"https://github.com/julzerinos/velo-frontend","last_synced_at":"2026-03-01T17:15:45.523Z","repository":{"id":109709041,"uuid":"505808820","full_name":"julzerinos/velo-frontend","owner":"julzerinos","description":"The frontend application for the Bachelor's Thesis project \"Velo\" - a cycling-dedicated analysis platform POC.","archived":false,"fork":false,"pushed_at":"2022-06-24T12:14:25.000Z","size":1976,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2024-01-27T12:09:43.754Z","etag":null,"topics":["account-management","analysis","athletics","bachelor-project","bachelor-thesis","cycling","d3","d3-visualization","javascript","password-reset","performance-analysis","power-curve","strava-api","user-scripts","vue-router","vue2","vuejs","vuex"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":false,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/julzerinos.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,"governance":null}},"created_at":"2022-06-21T11:12:23.000Z","updated_at":"2022-08-03T10:29:46.000Z","dependencies_parsed_at":"2023-04-21T17:46:53.234Z","dependency_job_id":null,"html_url":"https://github.com/julzerinos/velo-frontend","commit_stats":{"total_commits":107,"total_committers":4,"mean_commits":26.75,"dds":"0.14953271028037385","last_synced_commit":"97bb908fab288bcc58307a9fb0f024960767c46e"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/julzerinos/velo-frontend","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/julzerinos%2Fvelo-frontend","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/julzerinos%2Fvelo-frontend/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/julzerinos%2Fvelo-frontend/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/julzerinos%2Fvelo-frontend/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/julzerinos","download_url":"https://codeload.github.com/julzerinos/velo-frontend/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/julzerinos%2Fvelo-frontend/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29976273,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-01T16:35:47.903Z","status":"ssl_error","status_checked_at":"2026-03-01T16:35:44.899Z","response_time":124,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5: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":["account-management","analysis","athletics","bachelor-project","bachelor-thesis","cycling","d3","d3-visualization","javascript","password-reset","performance-analysis","power-curve","strava-api","user-scripts","vue-router","vue2","vuejs","vuex"],"created_at":"2026-03-01T17:15:44.965Z","updated_at":"2026-03-01T17:15:45.510Z","avatar_url":"https://github.com/julzerinos.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Velo \n\n###### This repository stores the frontend component, for the backend component please visit [velo-backend](https://github.com/Kornelos/velo-backend).\n\nVelo is the fruit of labour project created for [Kornel](github.com/Kornelos/)'s and [Julian](github.com/julzerinos/)'s Bachelor's Thesis. The application is a standalone atheltic performance anaylsis platform targeted towards cyclists.\n\nDue to strict regulations involving the copyright of the work created under the watchful wing of the University, the code is shared under an equally strict [CC BY-NC-ND 4. license](https://creativecommons.org/licenses/by-nc-nd/4.0/). Please review the license before using the source code. \n\nThe following sections contain paraphrased excerpts from the Thesis to provide insight for the technical project.\n\n## Application summary\n\nVelo is a web application created for the use case of advanced, customizable and extendable\nanalysis of cycling training by cycling coaches and/or cyclists themselves. The application should\nallow user profile creation which will be used by both athletes and coaches. The coach may\nsubscribe to an athlete (after their permission has been received) which grants access to athlete\ntraining data.\n\nThe coach may use predefined formulae and data visualization blocks to analyze training\nprogress. These may include (among others) a single training view, averages over a selected time\nperiod and the training power curve. Various data visualization tools will be used (line charts,\ngraphs, raw data extracts).\n\nThe coach is permitted access to a scripting module which they may use to define custom\nscripts for the data visualization blocks or create variations of the existing predefined scripts.\nThe coach is allowed (under the condition that he is subscribed to multiple athletes) to overlay\nand/or compare the data visualization results of multiple athletes. This will be used by cycling\nteam coaches for contextual data analysis.\n\nThe athlete is allowed to manually upload data or connect external data collection APIs\n(eg. Strava) which will allow for automated data ingestion by the application without requiring\nathlete prompting.\n\nThis application will store the data it collects to allow for a faster and easier data processing\nflow. The calculations for the specific data scripts in the application (selected by the user) will\nbe performed on the client-side (i.e. frontend).\n\n## Deployment details\n\nTo deploy the frontend application, clone/download the repository and run `npm i` or `yarn` (depending on preference).\n\nThe application may be run with `npm run serve` or `yarn serve`. The backend server has to be deployed seperately.\n\n## About the frontend application\n\nOur main goal was to create a webpage for desktop users - we use the Vue framework to provide a reactive single page application. We wanted to adhere to the modern design standards, that is why apart from Vue, we use Vuetify to provide a familiar and standardized design style.\n\nAnother library we used is D3. D3 is a high-performance tool for creating data presentation objects like graphs, charts or plots. What makes D3 unique is the low-level approach of the library. It allowed us to create a system where the user can design their own plot without any limitations. \n\nOur frontend application communicates with the backend and external services over REST API interfaces. Below, we will present an overview of the configuration of current frontend components.\n\n### Vue views\n\nThe views described in the following sections are made accessible to the user. The content of the page (i.e. views) changes by the control of vue-router.\n\n#### Landing Page/Data Bricks Page\n\nThis is the centerpiece of the entire application, although it is unavailable until a user logs in. Once there is a user logged in (assuming they are subscribed to an athlete/themselves with available data), they may interact with the creation menu.\n\n![databricks](https://raw.githubusercontent.com/julzerinos/velo-frontend/assets/data%20brick.png)\n\nThe vue structure for this component is\n\n```\nLayout.vue\n  DataBricksLayout.vue\n    DataBricksSetup.vue\n      DataBricks.vue\n      DataBrick.vue\n      DataBrick.vue\n      DataBrick.vue\n      ...\n```\n\nThe flow (triggered on load, add/remove databrick) for this component is\n\n  1. DataBricks.vue triggers `loadWorkout()`. A time range union is calculated for the current\ndata bricks.\n  2. DataBricks.vue moves into loading state and each child DataBrick.vue component is shown\nas visually loading. `refreshWorkouts()` is triggered to REST GET the requested workouts\nfrom the server.\n  3. Once the request is completed, DataBricks.vue returns to initial state. This triggers each\nDataBrick.vue to run the data manipulation script on its respective slice of the new dataset.\n\n#### Scripting Page \u0026 Module\n\nThe main goal of the scripting module is to allow the user to define their own scripts for generating D3 charts or other data visualization objects based on athlete workout data. The tree structure for this component is displayed below.\n\n```\nLayout.vue\n  DataBricksLayout.vue\n  Scripting.vue\n    ScriptSetup.vue\n    ScriptEditor.vue\n    ScriptSave.vue\n```\n\n![scripts](https://raw.githubusercontent.com/julzerinos/velo-frontend/assets/scripting.png)\n\nIn the first section, ScriptSetup.vue, the user supplies the name and type of the script, whereas the last section, ScriptSave.vue, is only used for committing the created script to the repository. The middle section, ScriptEditor.vue, is the core of the module. \n\nWe decided to use ace-editor for the code editor, as it focuses foremost on performance and being light-weight. The rather modern and sleek design is an added bonus which works well with the artistic vision of the application.\nWithin the code editor namespace, the user has access to three objects which may be used throughout the process of scripting. The recommended preamble for each script is used to initialize the code editor. It is displayed and explained below.\n\n```js\nconst d3 = args.d3\nconst svg = args.svg\nconst athletes = args.athletes\n```\n\nThe d3 object contains the entire D3 library. From this object, the user may access any\nof D3's functions. The svg object is the container for storing objects created with the help of\nD3 (this is a reference to the html svg object). `athletes` is an object which\ncontains the requested data of athletes and their workouts from a given time range. At the point\nof writing the script, the user should assume that they are receiving the data they are expecting.\nAbove the code editor is a select element from which they may select an existing script in the\nscripts repository. The code editor is then re-initialized with the selected script. Each script is\ncommitted to the repository with a unique ID, by which it may be requested. This is done so\nthat data brick configurations do not contain copies of the string literals, but rather a reference\nthey may use to request the script with.\n\nAt any point the user would like to test their script, they may use the testing section below\nthe code editor. The script is run with a set of mock data, which contains more than one athlete\nand a couple of workouts each. The test section is in reality just a simplified data brick. To fully\nunderstand the process of how a script is executed within a data brick, we shall begin with the\npresenting the key code fragment below.\n\n```js\ncallConfiguration : (code , args) =\u003e new Function ('args', code) (args)\n```\n\nThe above callConfiguration is an anonymous function used for executing\na script stored within a string literal. Choosing an anonymous function over a normal function\nlimits the scope of what the user has access to, providing a lighter as well as safer interface\nto work with. The lambda takes two arguments, code, being the string literal storing a script\nand args. \n\nThere is a strong debate on the validity and safety of using run-time compiled code in the programming community and there is\nno denying the potential dangers it brings along. In the end, the application is as safe as the most\nmalicious end user is able to interact with ill intentions. Nevertheless, this is a key Velo feature,\nand while the security risks will be ever present, we can address them in various methods.\nFirstly, the assumption is that all data available to the user in local application state is data\nwhich is inherently permitted for the user. There is no data in the application layer (as well as\ndata stored from the server) which the user would not be able to access without malicious intent.\nScripts are only executed in the scope of the local state, which makes their security risk equal to\nscripts run through the browser console.\n\nSecondly, the backend acts as a middleman between the potentially nefarious user and the\ndatabase. All frontend-to-database requests must have the appropriate tokens or metadata and\nmust go through very specific endpoints controlling the flow of information. These restrictions\nvery strongly limit the potential risks of malevolent users.\nAs for the method of run-time code execution, we have selected new Function() over the\ninfamous eval() due to the former being more clear and transparent in the code-base, a\ncharacteristic which is very valuable during code maintenance.\n\n#### Profile Page\n\nThe Profile page is, for all intents and purposes, the entry into the Velo ecosystem for its\nusers. As long as the user is not logged in, the page acts as a hub for signing in or signing\nup. The structural setup of the Profile page while the user is not logged in, is displayed by the\nfollowing tree.\n\n```\nLayout.vue\n  Profile.vue (signed out)\n    SignIn.vue\n      PassResetModal.vue\n    SignUp.vue\n      Captcha.vue\n```\n\n![profile](https://raw.githubusercontent.com/julzerinos/velo-frontend/assets/profile.png)\n\nThe Profile page after logging in (i.e. when a profile is successfully loaded from server and\nstored in local state) is more complex. The tree structure is displayed below.\n\n```\nLayout.vue\n  Profile.vue (signed in)\n    ProfileManagement.vue\n      ProfileCard.vue\n      Subscriptions.vue\n        Athletes.vue\n        Coaches.vue\n          CoachByEmail.vue\n      FileUploadCard.vue\n```\n\n#### Password Reset Module\n\nThe password reset module is more subtle compared to the others, as this is a component\nwhich will never be used if all goes well. The user requests a password reset for the email they used to register with. Sendgrid API is used to generate an email with a link. The link transfers the user back to the Velo ecosystem to a component `PassReset.vue` which is otherwise\ninaccessible. The token (embedded in the link) is used to authorize\nthe password reset. After submitting, the user may use their new password, if they received\npositive feedback via a web application alert.\n\n#### Alerts Module\n\n![alert](https://raw.githubusercontent.com/julzerinos/velo-frontend/assets/alert-success.png)\n\nThere is an alert module present in the web application. The\nerror message displays the \"blame\" (in which component/pro-\ncess the error appeared) and the error message itself, which\nis most cases is sourced from the server.\n\nThe modal is embedded in the layout and messages are processed in local state, allowing global\naccess to the module. Race conditions are addressed by using publication-subscriber (pub/sub)\ndesign principles - the latest message according to timestamps is shown.\n\n#### Testing\nOn the frontend we provide unit tests validating logic of the single components. Unit tests on\nthe frontend are very similar to tests in the backend, we are testing http requests module which\ncommunicates with backend and storage which persists data within the user’s browser.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjulzerinos%2Fvelo-frontend","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjulzerinos%2Fvelo-frontend","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjulzerinos%2Fvelo-frontend/lists"}