{"id":13725501,"url":"https://github.com/jmgtan/stock_dashboard","last_synced_at":"2025-05-07T20:32:40.710Z","repository":{"id":39393394,"uuid":"207148857","full_name":"jmgtan/stock_dashboard","owner":"jmgtan","description":null,"archived":false,"fork":false,"pushed_at":"2023-01-06T02:08:11.000Z","size":4016,"stargazers_count":61,"open_issues_count":30,"forks_count":51,"subscribers_count":2,"default_branch":"master","last_synced_at":"2024-08-04T01:27:49.602Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","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/jmgtan.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}},"created_at":"2019-09-08T17:33:38.000Z","updated_at":"2024-03-31T08:46:26.000Z","dependencies_parsed_at":"2023-02-05T02:32:06.832Z","dependency_job_id":null,"html_url":"https://github.com/jmgtan/stock_dashboard","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/jmgtan%2Fstock_dashboard","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jmgtan%2Fstock_dashboard/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jmgtan%2Fstock_dashboard/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jmgtan%2Fstock_dashboard/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jmgtan","download_url":"https://codeload.github.com/jmgtan/stock_dashboard/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":224645391,"owners_count":17346141,"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-08-03T01:02:25.233Z","updated_at":"2024-11-14T15:31:23.954Z","avatar_url":"https://github.com/jmgtan.png","language":"JavaScript","funding_links":[],"categories":["JavaScript"],"sub_categories":[],"readme":"# Stock Monitoring Dashboard\n\n## Table of Contents\n- [Stock Monitoring Dashboard](#stock-monitoring-dashboard)\n  * [Components](#components)\n  * [High-Level Architecture](#high-level-architecture)\n  * [Installation Requirements](#installation-requirements)\n- [Deployment](#deployment)\n  * [Local Deployment](#local-deployment)\n    + [Install the Amplify CLI](#install-the-amplify-cli)\n    + [Clone the repo from GitHub](#clone-the-repo-from-github)\n    + [Initialize the Project](#initialize-the-project)\n    + [Deploy the Backend](#deploy-the-backend)\n    + [Install frontend dependencies](#install-frontend-dependencies)\n  * [Deploy Application using Amplify Console](#deploy-application-using-amplify-console)\n- [Setup the Data Feed Integration](#setup-the-data-feed-integration)\n  * [Where to get Config Values?](#where-to-get-config-values-)\n    + [Local Deployment](#local-deployment-1)\n    + [Amplify Console](#amplify-console)\n  * [Register for an API Key from the Data Feed Provider](#register-for-an-api-key-from-the-data-feed-provider)\n  * [Create Cognito User Pool Client for the Backend](#create-cognito-user-pool-client-for-the-backend)\n  * [Create Backend User](#create-backend-user)\n  * [Create Secrets Manager Entries](#create-secrets-manager-entries)\n  * [Configure the Backend Lambda](#configure-the-backend-lambda)\n  * [Deploy via CloudFormation](#deploy-via-cloudformation)\n- [Testing](#testing)\n\n## Components\n\nThis demo application consists of the following components:\n\n* The frontend is built using React JS\n* The backend is using AWS AppSync via AWS Amplify Framework\n* Authentication is done via Amazon Cognito\n* AWS Secrets Manager is used to store the API Keys that will be used to query the data feed.\n* AWS Lambda and Amazon CloudWatch Events are used to regularly fetch the latest Intraday prices from the data feed.\n* The data feed that this demo uses is from [Alpha Vantage](https://www.alphavantage.co)\n\n## High-Level Architecture\n\n![Image of High-Level Architecture](doc-images/blog_stock_dashboard.png)\n\n## Installation Requirements\n\n1. AWS CLI (\u003e= 1.16.234)\n2. Amplify CLI (\u003e= 1.11.0)\n\n# Deployment\nYou can either deploy it locally or use [AWS Amplify](https://aws.amazon.com/amplify/) to host the application for you. The succeeding sections describes both approaches so you only need to pick one.\n\n## Local Deployment\n\n### Install the Amplify CLI\n\n```bash\nnpm install -g @aws-amplify/cli\n```\n\n### Clone the repo from GitHub\n\n```bash\ngit clone https://github.com/jmgtan/stock_dashboard.git\n```\n\n### Initialize the Project\n\n```bash\ncd stock_dashboard\namplify env add\n```\n\nUse the following values:\n\n* Do you want to use an existing environment? No\n* Enter a name for the environment. You can just input \"local\"\n* Do you want to use an AWS profile? If you have a profile configured via the AWS CLI, you can reuse the same profile, otherwise choose No and configure accordingly.\n\n### Deploy the Backend\n\n```bash\namplify push\n```\n\nJust use the default answers and follow the instructions.\n\nThe push commands will create the following:\n* Cognito User Pool\n* DynamoDB\n* AppSync API\n\n### Install frontend dependencies\n\n```bash\nnpm install\n```\n\n## Deploy Application using Amplify Console\n\nExecute the following CloudFormation to create the `AmplifyBackendDeploymentRole` service role that would be used by Amplify.\n\n```bash\naws cloudformation deploy --template-file bootstrap/amplify-console-base-cf.yaml --stack-name StockDashboardBase --capabilities CAPABILITY_NAMED_IAM\n```\n\nAlternatively, you can go to the IAM console and create a new role that has the following permissions (make sure that it has a trust relationship with Amplify (amplify.amazonaws.com).):\n\n```json\n{\n    \"Version\": \"2012-10-17\",\n    \"Statement\": [\n        {\n            \"Action\": [\n                \"s3:*\",\n                \"codecommit:*\",\n                \"appsync:*\",\n                \"dynamodb:*\",\n                \"cloudformation:*\",\n                \"iam:*\",\n                \"cognito-idp:*\",\n                \"cognito-identity:*\",\n                \"sns:*\",\n                \"lambda:*\",\n                \"amplify:*\"\n            ],\n            \"Resource\": \"*\",\n            \"Effect\": \"Allow\"\n        }\n    ]\n}\n```\n\nLogin to your Github account and fork the repository:\n\n![Github Fork Repository](doc-images/github-fork-repo.png)\n\nAlternatively, you can clone the repository and push it to either Github or CodeCommit.\n\nGo to the AWS Management Console and then Amplify. Click \"Get Started\" under \"Deploy\", see following screenshot:\n\n![Amplify Overview](doc-images/amplify-overview-deploy.png)\n\nYou should be able to see a screen like the following:\n\n![Amplify Connect](doc-images/amplify-connect.png)\n\nOnce your repo has been selected, Amplify should automatically generate a build configuration. Make sure to select \"Create new environment\":\n\n![Amplify Build Settings](doc-images/amplify-create-env-service-role.png)\n\nSelect the role (`AmplifyBackendDeploymentRole`) that was created by the bootstrap CloudFormation template and then click \"Next\". This will automatically deploy both frontend and backend. You can keep track of the deployment process by drilling down and see the logs that are being streamed in.\n\nOnce the deployment finishes, there's one more step to make sure that the React Router works. Go to the \"Rewrites and redirects\" section:\n\n![Rewrites and redirects](doc-images/menu-rewrites.png)\n\nModify the default rule and change the \"Source address\" to `\u003c/^((?!\\.(css|gif|ico|jpg|js|png|txt|svg|woff|ttf)$).)*$/\u003e`, and the \"Type\" to `200 (Rewrite)`, it should look like this:\n\n![Rewrite Rule](doc-images/rewrite-rule.png)\n\n# Setup the Data Feed Integration\n\n## Where to get Config Values?\n\n### Local Deployment\nAfter running `amplify push` in the previous step, the `src/aws-exports.js` file would be generated. Refer to that file to get the config values for the data feed function.\n\n### Amplify Console\nSince the deployment is handled by the Amplify service, you won't have access to the config file. You would be able to get the config values by going to the different services that the app depends on. These are as follows:\n- Go to Cognito console to get the pool id.\n- Go to AppSync to get the endpoint url.\n\n## Register for an API Key from the Data Feed Provider\n\nGo to [Alpha Vantage](https://www.alphavantage.co), and get a free API key.\n\n## Create Cognito User Pool Client for the Backend\n\n```bash\naws cognito-idp create-user-pool-client --user-pool-id \u003cvalue of user pool id\u003e --client-name BackendClient --explicit-auth-flows \"ADMIN_NO_SRP_AUTH\"\n```\n\nTake note of the return payload, specifically the `ClientId`.\n\n## Create Backend User\n\nWe're going to create a new user in the user pool specifically for the use of the backend Lambda function to be able to call the AppSync mutation APIs.\n\n```bash\naws cognito-idp admin-create-user --user-pool-id \u003cvalue of user pool id\u003e --username \"\u003cemail of new admin user\u003e\" --user-attributes=Name=email,Value=\"\u003cemail of new admin user\u003e\" --message-action \"SUPPRESS\"\n\naws cognito-idp admin-set-user-password --user-pool-id \u003cvalue of user pool id\u003e --username \"\u003cemail of new admin user\u003e\" --password \"\u003cpassword\u003e\" --permanent\n```\n\nRemember the email and password for the admin user, the next step is to store these values in AWS Secrets Manager for the backend Lambda function to consume.\n\n## Create Secrets Manager Entries\n\nCreate entry for the backend user account\n\n```bash\naws secretsmanager create-secret --name \"stockMonitoring/\u003cenv\u003e/backend\" --secret-string '{\"username\": \"\u003cbackend username\u003e\", \"password\": \"\u003cbackend password\u003e\"}'\n```\n\nCreate entry for the data feed API key\n\n```bash\naws secretsmanager create-secret --name \"stockMonitoring/\u003cenv\u003e/datafeed\" --secret-string '{\"feed_api_key\": \"\u003cfeed api key\u003e\"}'\n```\n\n## Configure the Backend Lambda\n\nOpen the file `processors/GetIntradayPrices/config-exports.js`\n\nUpdate the following values:\n\n* `cognito_pool_id`: use the value from the file `src/aws-exports.js` in the `aws_user_pools_id` variable\n* `cognito_backend_client_id`: use the value from the `ClientId` of the backend client that was created in the previous section.\n* `cognito_backend_access_key`: value is `stockMonitoring/\u003cenv\u003e/backend`\n* `appsync_endpoint_url`: use the value from the file `src/aws-exports.js` in the `aws_appsync_graphqlEndpoint` variable\n* `appsync_region`: use the value from the file `src/aws-exports.js` in the `aws_appsync_region` variable\n* `data_feed_key`: value is `stockMonitoring/\u003cenv\u003e/datafeed`\n\n## Deploy via CloudFormation\n\nCreate S3 bucket to serve as the staging area for deploying the Lambda function. This will be used by the AWS CloudFormation package command.\n\n```bash\naws s3api create-bucket --bucket \u003cstaging bucket name\u003e --create-bucket-configuration LocationConstraint=eu-west-1\n```\n\nNext we should install the dependencies that the function requires, do the following:\n\n```bash\ncd processors/GetIntradayPrices\nnpm install\n```\n\nNext we package and stage the Lambda function\n\n```bash\ncd ..\naws cloudformation package --template-file cf-template.yaml --s3-bucket \u003cstaging bucket name\u003e --output-template-file packaged-template.yaml\n```\n\nOnce the command succeeds you can then execute the deploy command\n\n```bash\naws cloudformation deploy --template-file packaged-template.yaml --stack-name \u003cstack name\u003e --capabilities CAPABILITY_IAM\n```\n\nOnce deployment completes, going to the CloudFormation console and into the stack, you should be able to see the list of resources that were created\n\n![List of CloudFormation Resources](doc-images/cf-resources.png)\n\nClicking the Lambda function, you should be able to see the trigger, which is a CloudWatch scheduled event for every 30 mins.\n\n![Lambda Trigger](doc-images/lambda-trigger.png)\n\n# Testing\n\nIf you deployed the application locally, you can start the server using the following command\n\n```bash\nnpm start\n```\n\nThis command would automatically open the browser. \n\nAlternatively, if you deployed via the Amplify Console, you can open the application using the URL generated from Amplify Console.\n\nIf this is your first time accessing the application, you should create a new account and validate it. Once you're logged in you can start adding stock symbols to monitor. See the following screenshot:\n\n![Manage Stock Symbols](doc-images/manage-stock-symbols.png)\n\nYou can then either wait for the Lambda function to trigger to start populating the data, or you can manually trigger. See the following screenshots on how to manually trigger:\n\nGo to the console and look for the Lambda function that was created by the CloudFormation template, click test:\n\n![Click the Test Button](doc-images/lambda-console-test-btn.png)\n\nThe Lambda function doesn't really need any payload, so you can just pass in an empty JSON document\n\n![Lambda Console Test Form](doc-images/lambda-console-test-form.png)\n\nOnce the test event has been created, you can click the Test button again and it should trigger the function. If you have the application open in the browser, you should be able to see the data streaming in via the chart that are automatically updated. For example:\n\n![Application Dashboard](doc-images/app-dashboard.png)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjmgtan%2Fstock_dashboard","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjmgtan%2Fstock_dashboard","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjmgtan%2Fstock_dashboard/lists"}