--- title: Assignment 1 | Nodes tags: assignment --- #### [⬅️ Return to course website](https://cs1951v-2023.vercel.app/) # <span style="font-size: 50px;">**Assignment 1: Nodes**</span> :::info **Released: September 13th, 2023** **Due: September 27th, 2023 at 11:59 PM ET** ::: <!-- INFO BOXES :::success GREEN This is for any step by step instructions that students should follow. ::: :::info BLUE This is for important assignment information throughout the assignment: **Released: September 8th, 6:00pm ET** **Due: September 15th, 11:59pm ET** ::: :::warning YELLOW Use this info box for disclaimers. ::: :::danger Use this info box for important points that students should not miss! ::: :::spoiler Dropdown list Use this ::: --> <!-- TYPESCRIPT CODE BLOCKS ```typescript const list = [10, 20]; console.log(list.map(x => (x * x))) ``` --> <!-- HOW TO CHANGE COLOR IN MARKDOWN <span style="background:aliceblue">some text with a **lightblue** background</span> <span style="color:red">some **red** text</span> --> <!-- These are a list of shortcuts available. --> *[HTML]: Hyper Text Markup Language *[W3C]: World Wide Web Consortium *[NPM]: Node Package Manager *[IDE]: Integrated Development Environment *[MERN]: MongoDB, Express, React, NodeJS *[Yarn]: Yet Another Resource Negotiator # **Introduction** Having collected all the necessary ingredients by completing the setup assignment, and all the donut know-how in the lab, you are finally ready to make the dough—the most important step of all! In this assignment, you will be building upon your Lab 1 code to create a complete node file system—a standard way of managing and navigating between hypertext nodes. At the end, you will have built a full-stack application that will allow users to create, read, update, delete, and move hypertext nodes via the frontend. You will be graded on the functionality of your frontend via manual review and your backend via an automatic test suite. You will make the node file system using the full-stack technologies that you installed in Assignment 0: MongoDB, Express.js, React.js, and Node.js. This programming assignment contains three parts: the ***database***, the ***backend***, and the ***frontend***. We will start with an overview of the assignment specifications and the general design features of the file system you are creating. Then, we will delve into how to work with each part of the MERN stack to get the whole file system working. **Keep in mind the 30-minute rule: if you can’t get something that appears straightforward to work in 30 minutes, it may not be your problem. Don’t be afraid to send a message in Slack or go to TA hours if something unexpected comes up.** :::warning **Lab 1 is an important precursor to this assignment!** This assignment builds directly on the work in Lab 1. It's crucial that you go through Lab 1 in its entirety before starting Assignment 1! ::: :::success **Note**: Assignment 1 uses the same codebase as Lab 1 ::: ## **Checklist** **Database:** - [ ] Create Mongo database **Backend (BackendNodeGateway):** - [ ] createNode [Implemented in `Lab 1`] - [ ] getNodeById - [ ] deleteAll - [ ] deleteNode - [ ] moveNode - [ ] addChild - [ ] removeChild **Frontend (NodeView):** - [ ] createNode [Implemented in `Lab 1`] - [ ] content [Implemented in `Lab 1`] - [ ] title - [ ] breadcrumb [[What is a breadcrumb?](https://semantic-ui.com/collections/breadcrumb.html)] - [ ] delete - [ ] move **Deployment:** - [ ] Deploy the backend to Render - [ ] Deploy the frontend to Vercel # Demo :::warning Note: The demo may take up to 30 seconds to load due to the free backend we used for hosting. Additionally, you might notice some strange behavior if there are multiple students interacting with the demo at the same time. ::: You can find a demo of the MyHypermedia application [**here**](https://assignment-one-demo.vercel.app/). # Syntax Guides You'll be working with several languages and libraries in this assignment. Here are some syntax guides to serve as a reference: - [CSS](https://devhints.io/css) - [TypeScript](https://devhints.io/typescript) - [React](https://devhints.io/react) - [JSX](https://www.codecademy.com/learn/react-101/modules/react-101-jsx-u/cheatsheet?utm_source=pepperjam&utm_medium=affiliate&utm_term=159404&clickId=4089918208&pj_creativeid=8-12462&pj_publisherid=159404) # Database In the first lab, we provided you with a URI for a database that the TAs had made for the class to share. But now that you are working on you own hypertext system, it's time to create your own database! ### Step 1: Creating a MongoDB account Create/log into your MongoDB account [**here**](https://account.mongodb.com/account/login). ### Step 2: Creating a free shared cluster Create a new organization and project if necessary, then proceed to create a new database deployment. <div style="text-align:center; margin-bottom: 20px"><img style="border-radius:10px; width:600px" src="https://i.imgur.com/BfdTgJC.png" /></div> Select the M0 free shared option. ### Step 3: Configuring a new cluster <div style="text-align:center; margin-bottom: 20px"><img style="border-radius:10px; width:600px" src="https://i.imgur.com/o4Nz45a.png" /></div> Ensure that the following options are selected: 1. Cloud Provider & Region: `AWS, N. Virginia (us-east-1)` 2. Cluster Name: `cs1951v` (technically, this field can be named whatever you want) Click `Create`. ### Step 4: Creating a database user and configuring access After clicking `Create`, you should see a page like this: ![](https://i.imgur.com/VHh4MMT.png) For the section: How would you like to authenticate your connection?: 1. Select `Username and Password`. 2. Create a Database User: create a username and password that you will remember. This username and password is what will be used in your MongoDB URI to connect to this new cluster. 3. Click `Create User`. Scroll down to the next section which should look like this: ![](https://i.imgur.com/gb4Whzb.png) For the section: Where would you like to connect from? 1. Add a connection IP address: select `My Local Environment` and enter in `0.0.0.0` IP address as your whitelist. 2. Click `Add Entry`. Now Click `Finish and Close`. ### Step 5: Getting the connection string You should now be redirected to the overview page of your new database deployment! 1. Click the `Connect` button beside the cluster name. 2. Under `Connect to your application` choose the `Drivers` option. 3. copy the connection string (you can ignore all other steps on this page). ### Step 6: Adding the URI to your `.env` file Navigate to the `.env` file you made in Lab 1: `cd server/.env`. Update the URI with the new URI we just copied from Step 5. :::warning **Remember to:** 1. replace `<password>` in the URI with the password you created in Step 4. 2. in between the last slash and the question mark, add the name of your database: `cs1951v-database`. 3. add quotation marks `""` around your new URI ::: This is an example of what the line should look like in your `.env`: ```bash DB_URI="mongodb+srv://username:password@cs1951v.39y6kas.mongodb.net/cs1951v-database?retryWrites=true&w=majority" ``` Great! You successfully connected your backend to your own MongoDB cluster! ### Step 7: Testing your database connection :::info **TODO:** 1. Start your server using `cd server` and `npm install` (or `npm i`) and `npm run dev` 2. Start your React service using `cd client` and `npm install` (or `npm i`) and `npm run dev` 3. Go to http://localhost:3000/ and create a node. 4. Check your `cs1951v-database` dashboard (`nodes` collection) - you should see a new entry. If you don't see any new entries in your `nodes` collection, please reach out to the TAs via Slack or in Hours! ::: :::warning **Note:** We could send a POST request at `/node/create` via Postman to simulate our frontend actions here. ::: Awesome! Now that we have verified that our database is properly connected, let's move onto the backend portion of this assignment. # Backend ## `BackendNodeGateway.ts`: In this assignment you will be tasked with writing methods in `BackendNodeGateway.ts` to reach full functionality of our node file system. You will need to implement the following methods: ***~~createNode~~*** (already implemented in lab) - One of the core functionalities that we are expecting you to have is the ability to create nodes. This method should create a node in the database. ***getNodeById*** - We want to retrieve nodes from the database. The `findNodeById` function allows users to retrieve a node given the ID. ***getNodesById*** - We want to retrieve all nodes from the database that have an ID that is in the input list of ID's. ***deleteAll*** - This method should delete all documents in the MongoDB `nodes` collection. This method won't be needed much for production use but rather use for testing. ***deleteNode*** - Now that we can create and retrieve nodes, we want to allow users to delete nodes. This method should allow users to delete a node *and its children* from the database given a particular `nodeId`. ***moveNode*** - In order to have a fully functioning file system, we must be able to move nodes around. You need to implement a function which takes in two `nodeId`s, `nodeToMove`'s `nodeId` and `newParent`'s `nodeId`. The function should then verify if the move is valid and move the node in a way such that `nodeToMove` becomes a child of `newParent`. ***addChild*** - This method takes in a `childId` and `parentId` and update's a parent's `filePath.children` array with a new child `nodeId`. This is mainly used as a helper method for other functions. ***removeChild*** - This method takes in a `childId` and `parentId` and remove's `childId` from the parent's `filePath.children` array. This is mainly used as a helper method for other functions. ## Helper Methods: ### `NodeCollectionConnection.ts` & `BackendNodeGateway.ts` The methods in `NodeCollectionConnection.ts` and `BackendNodeGateway.ts` that we have already implemented for you should help you implement the methods above. For more practice with MongoDB queries, you can also use [Mongo playground](https://mongoplayground.net). ### `server/src/types` We also recommend looking at `server/src/types` as this folder includes important information on how we have set up the schema of `INode`, `IServiceResponse`, etc. These files also include type-checking functions such as `isINode()` which will be very helpful for error-checking in this assignment. ### Custom helper methods: Of course, you can write as many of your own helper functions and are not required to use the ones we provide. As long as you pass our tests, we have a pretty liberal stance on what you can and cannot do! **Note:** Because next assignment's stencil code will use the same `server/src/types` defined in Assignment 1, it would be wise to **NOT** add custom code to `server/src/types` just yet. ## Testing To test that your backend functions work as intended, you can run the test suite by running `npm test` (or `npm run test`) from the `server` folder. # Frontend For the frontend portion of this assignment, you will be building a React component (`NodeView.tsx`) that renders a node's data in a user-friendly UI. We will start with just `image` and `text` nodes, and will add more types of nodes as the course progresses. Your create node modal functionality should be working from the lab. One thing to note is that when creating an image node, the "Choose file" browse option will not work until after you deploy your site (Imgur doesn't work on localhost). Once you deploy, Imgur uploading should work automatically. In the meantime, you should paste an image url into the textbox. This a chance to exercise your design skills and creativity: your `NodeView` can look however you want it to! However, there are some functional requirements that your NodeView must fulfill. Use `Cmd + Shift + F` and search for "TODO" to find all the places you need to edit code! Or, use the "Todo Tree" extension's panel in VSCode to see a tree view of all the TODOs. ## Requirements for your NodeView: - [ ] It should clearly display the `title` of the node - [ ] It should clearly display the `content` of the node - i.e. the image for an image node, and the text for a text node - [ ] It should include a ["breadcrumb"](https://semantic-ui.com/collections/breadcrumb.html) - A ***breadcrumb*** is a UI element that shows the user where they currently are in a hierarchical structure, like a website or file system - For instance: - `Coursework > Fall 2021 > CS1951v > Assignment 1` - See `NodeBreadcrumb.tsx` to see which data you will have access to as `props` **Note:** Clicking on a part of the breadcrumb does **NOT** need to take the user to that node like in the demo. - [ ] It should include a delete button that deletes the node when clicked - We have provided a stub for `onDeleteButtonClick` in `MainView.tsx`, which we call an *event handler* since it handles the user clicking on the delete button - You will then want to pass this event handler to the `onClick` field of a `<button />` (We provide a simple `<Button />` React component that you should feel free to edit) - Here's an example of this pattern: ```tsx /** * This React component renders a button that logs "Hello, world!" * to the console when clicked */ function HelloWorldButton() { const handleClick = () => { console.log('Hello, world!'); } return ( <button onClick={handleClick}> Click me to log Hello, world! </button> ) } ``` - [ ] It should include a move button that opens the `MoveNodeModal` when clicked, allowing a user to move a node to a different parent node. - Use the `onMoveButtonClick` prop that is passed in to open the moveNodeModal! The specification on this document is very broad! The TODOs in the code provide more detail. In general, when implementing a React component, think about how you can go from the input (`props`) to the output (what you want to render). ## Design In addition the functionality of your `NodeView`, it is important that it is well-designed. This will be true for the rest of the assignments in this course, and any software you build after the course concludes. What does "well-designed" mean? In short, a potential user should feel that the interface is intuitive, clear, and enjoyable to use. For instance, buttons should do what they seem like they do, and important information should be presented prominently. Essentially, we want to see that you have given significant thought to the usability and styling of your UI. Feel free to check out [The Basic Principles of User Interface Design](https://www.uxpin.com/studio/blog/ui-design-principles/) or other online resources, or ping in the ==#assignments== channel if you have questions! :::info Check out the `globalCssVariables.scss` file, where you can change some of the global colors that are used throughout the system. Feel free to change this as much as you would like to! ::: ## Debugging We highly recommend having your webpage running in your browser as you're working on the frontend, and incrementally checking that each feature you add appears and works as intended. Below we have some debugging options you may consider using. **Print Statements** `console.log('Insert message')` is a Javascript function that prints a message to the web console. To open the web console, double click/right click on the webpage, click "Inspect Element", and go to the console tab. **VSCode Debugger (Frontend)** You can debug with breakpoints directly in VSCode! Debuggers for Chrome and Edge are built in, and you can find an extension in the store for Firefox. Select the `Run and Debug` tab on the left side of the editor. The first time you setup debugging for your repository, you will need to `create a launch.json file`. On the dropdown list that opens, select `Web App (Chrome)` or whichever other browser you prefer to debug with. To start debugging, go to the "Run and Debug" sidebar (Shortcut: `Ctrl + Shift + D`) and click the play button beside `Launch chrome against localhost`. <div style="text-align:center; margin-bottom: 20px"><img style="border-radius:5px; width:300px" src="https://i.imgur.com/GeM3KV1.png" /></div> This will open `localhost:3000` in Chrome, where you have access to all of the Chrome debugging tools as well. Now, the useful part of using the VSCode debugger, adding `breakpoints` to your code! Let us say that we are in `ImageContent.tsx` and we are having issues accessing the anchors that we should render on our node. We want to know what `startAnchor` is and what `anchor` is in the following snippet of code for `displayImageAnchors`. <div style="text-align:center; margin-bottom: 20px"><img style="border-radius:5px; width:600px" src="https://i.imgur.com/jm2OThQ.png" /></div> Spot the 🔴 next to line `106`. What that means is that we have set a breakpoint at that line in our code. You can add new breakpoints by click next to the line number. Now when we run our code in the debugger and go to an image, your web app will freeze at that point. <div style="text-align:center; margin-bottom: 20px"><img style="border-radius:5px; width:600px" src="https://i.imgur.com/SpUj89X.png" /></div> You can see that it has frozen at line `108`. The menu at the top of the following screenshot (next to the `ImageContent.tsx` tab) can be used to `Continue`, `Step to next line`, `Stop`, `Restart`, etc. When we are frozen at a breakpoint we can open the `Debug Terminal` and get really valuable insights as to what the variables are. <div style="text-align:center; margin-bottom: 20px"><img style="border-radius:5px; width:800px" src="https://i.imgur.com/AUtQYm9.gif" /></div> **VSCode Debugger (Backend)** You can also debug backend Node.js applications in VSCode. To do this, you will create a "JavaScript Debug Terminal", and you will run your backend from this debug terminal instead of your traditional terminal. There are two methods for launching a JavaScript Debug Terminal: - On the terminal bar at the bottom of the editor, click the arrow beside the `+` icon to add a new terminal. In the dropdown, select "JavaScript Debug Terminal". - Press `Control + Shfit + P` (or `Command + Shift + P`) to open the command palette, and select "Debug: JavaScript Debug Terminal". Then you can run `npm run dev` from this debug terminal, and you will be able to add breakpoints to your backend code in the same way as shown above. # Deployment Once you have finished implementing all the steps of this assignment, follow the instructions linked [**here**](https://hackmd.io/@CS1951V-2023/deployment) to deploy your project! <!-- After you've completed coding your system, it is time to deploy it to remote servers so everyone with internet can access it. To introduce you to different technologies, we are going to deploy the backend to Heroku, and the frontend to Google Firebase. Feel free to share the deployment link (*not the code*) with family and friends, or you may even want to showcase it on your resume! ## Deploying Backend First, we'll want to deploy our backend service to Heroku. The first step is to register an account and install Heroku CLI. To do that, please follow the link here: [Getting Started on Heroku with NodeJS](https://devcenter.heroku.com/articles/getting-started-with-nodejs). :::success **Setting up the environment** - Complete the "Introduction" and "Set up" portion of the [tutorial](https://devcenter.heroku.com/articles/getting-started-with-nodejs) only. - Login to Heroku CLI with your account. ::: Now you should have the Heroku environment ready to go. We can start deploying our backend code. Since we have our server and client in one repo, it's crucial that we only deploy a subfolder of the whole repository. :::success **Creating instance and deploying** - Create a new Heroku instance with `heroku create` - Commit your changes - In the root directory of the repository, deploy the `server` subfolder to Heroku instance: `git subtree push --prefix server heroku master` ::: We have deployed our code to Heroku! But now it will not work yet, because we have not configured environment variables and our application does not know what port to start on. :::success **Configuring environment variables** - Login to Heroku web portal: https://id.heroku.com/login - Navigate to the instance you just created, and select *Settings* tab. - Navigate to `Config Vars` section, and click `Reveal Config Vars`. - Fill the table with your own `DB_URI`, keeping everything else the same as the image below. ::: ![Config](https://i.imgur.com/XL6wYaR.png) Now, if you refresh your backend instance, you should see that "MyHypermedia Backend Service" is rendered on the DOM. :::warning **Commonly Asked Questions** *Q: What if I already have a Heroku account? Do I need to create a new one for this course?* A: No, you can use your personal account for Heroku. If you run out of your instance limit, consider registering a new account. *Q: The app works locally but Heroku says "Application Error". What's wrong?* A: Go to Heroku dashboard and select your instance. Click `More` button and select `View logs` option. You will see the console output and debug from there. Check whether you have configured environmental variables (config vars) correctly. Note that Heroku does not install `devDependencies` if you have used your own npm package; consider moving it to `dependencies` in `package.json`. *Q: I'm getting the error `fatal: 'heroku' does not appear to be a git repository`. What should I do?* A: Try running `heroku git:remote -a herokuAppName` ::: :::success **TODO:** Put your backend Heroku URL in the assignment `README.md` ::: Moving on to deploying the frontend! ## Deploying Frontend We will be deploying our frontend using Firebase, a Google service. Before we start, we need to change the endpoint in the frontend codebase to point to the backend service we just deployed. Let's do it! :::info **Where can I find my backend deployment link?** Click the "Open App" button in Heroku instance page, your backend app will open in a new window. ::: The first step is to change the endpoint in Frontend to point to the remote backend service. :::success **Changing the endpoint** - Navigate to `FrontendNodeGateway.ts` - Update the `baseEndpoint` variable on line 14 to point to your backend deployment. - Don't include the trailing `/` in the URL. - For example, `baseEndpoint = 'https://vast-caverns-62320.herokuapp.com'` - On line 12, change `process.env.REACT_APP_BACKEND_ENV` to `process.env.NODE_ENV` - Commit your changes ::: The second step is to install the Firebase CLI. :::success **Installing Firebase CLI** Follow the instruction [here](https://firebase.google.com/docs/cli) to install Firebase CLI. ::: Next, let's log into the Google Firebase using your personal Google Account. :::warning The account you use **must not be affliated with Brown University**. Use your personal Google Account, or register a new one. Brown University accounts does not allow users to create Firebase apps. ::: After we log in, it is time to create and configure the Firebase app! :::success **Create Firebase app on the web console** - Go to the [Firebase console](https://console.firebase.google.com/) and select "Create a project" or "Add project" (depending on if you have created a project before). - Enter a unqiue project name. Note this project name will be part of the URL of your deployed frontend - don't include your name, since we grade anonymously. - Be sure to check both boxes to agree to the terms. - Switch off Google Analytics for this project and click "Create project". **Configure Firebase app with the CLI** - Navigate to `client` folder in terminal. This is important! - Create an Firebase app using `firebase init` - When CLI prompts: `Are you ready to proceed?`, enter `Y` and hit enter - In the next step, use up/down arrow and space to select option `Hosting: Configure files for Firebase Hosting and (optionally) set up GitHub Action deploys` - In the next step, select `Use existing project` and select the project you created on the web console. - Specify your project id and project name. - When CLI prompts: `What do you want to use as your public directory?`, enter `build`. - When CLI prompts: `Configure as a single-page app?`, enter `Y`. - When CLI prompts: `Set up automatic builds and deploys with GitHub?`, enter `N`. - Wait for the initialization to complete. ::: Now we have created a Firebase instance on the cloud! Since we are deploying our React application, we will use the `production` version of React. How do we do that? :::success **Build production React and deploy** - Navigate to `client` folder in terminal. - Build production version of React using `npm build`. This would compile your React to HTML and JS files to a folder called `build`. We will deploy `build` folder. - Deploy your compiled frontend to Firebase using `firebase deploy`. ::: All done, have fun! If everything runs smoothly, you should be seeing your app deployed on Firebase. Firebase would give you the URL of the app upon successful deployment. You just deployed a fully-fledged hypertext system. **Open your frontend deployment, and test it as a user!** :::success **TODO:** Put your frontend Firebase URL in the assignment `README.md` ::: --> # Conceptual Questions :::warning **These questions are required for students taking the course as graduate-level or capstone.** For non-capstone 1000-level students, you can complete these questions for a maximum of 15 extra credit points (5 per question). ::: These questions are supposed to help you make good design decisions and get you to consider how we will be expanding this assignment to build a hypertext application over the course of the semester. :::success Answer these questions in the repositories `README.md` file ::: 1. Suppose that in addition to storing nodes in a file system you want to store nodes on an unbounded 2D-canvas (similar to what you’ve seen in Dash demos during class). Explain how this feature would be implemented across each component of the MERN stack. Specifically: a. Write a MongoDB database schema that could support this. Justify your design. b. Identify at least one potential npm React library that you could use to avoid building the entire 2D canvas UI component from scratch. 2. Imagine you want to implement an authentication and authorization workflow to protect access to certain nodes. Specifically each node should specify access level for every user and group, with access levels being: read, write, annotate, and admin. Assume for each user session that you have secure access to an accurate user-identifier and an array of group-identifiers that that user belongs to. Explain in 3-5 sentences how you would add support to the BackendNodeGateway so that it returns the node only if the current user has proper access to the requested node. 3. Finally, imagine you want to persist user trails. Specifically, you want to track the path that a user takes through the hypertext corpus. In this case, since each node has a unique url, each path can be represented as an array (of linked list) of urls. Explain in 3-5 sentences how you might add support for storing and then effectively accessing old trails. In your response, you may choose to focus on the frontend (around how you would make trails into a compelling user experience) or on the backend (around how you would make this data persistent as well as how you would query it). # Handin :::warning **Please ensure that all the sections in the `README.md` are filled out.** ::: You'll be submitting all your assignments for CSCI1951V through Gradescope, and you'll receive all your grades and feedback through Gradescope too. Once you have successfully created a Gradescope account using your Brown email address you can enroll in our Gradescope course by clicking the "Gradescope" tab on Canvas. You should submit your project to the `Assignment 1: Nodes` assignment in Gradescope by linking your GitHub repository as follows: <div style="text-align:center; margin-bottom: 20px"><img style="width:400px" src="https://i.imgur.com/St6TsIe.png" /></div> # Grading For students taking this course as a capstone or graduate level course, the assignment is out of 125 points. For students not taking this course as a capstone or graduate level course, the assignment is out of 110 points. ## Linting - 5 Pts (autograded) | Task | Grade | | ----------- | ----------- | | No ESLint or Prettier warnings | 5 Pts | Run `npm run lint` on the `server/` and `client/` directories to run the linter locally and fix any issues before you submit! ## Backend - 45 Pts (autograded) | Task | Grade | | ----------- | ----------- | | Implement src/nodes/BackendNodeGateway.ts | 45 Pts | Run `npm test` on the `server/` directroy to run the test suite locally and fix any issues before you submit! ## Frontend - 50 Pts (TA will grade) | Task | Grade | | ----------- | ----------- | | Clearly display the `title` and `content` of the node | 10 Pts | | Includes a breadcrumb | 10 Pts | | Includes a delete button that deletes the node | 10 Pts | | Includes a move button that opens the moveNodeModal | 10 Pts | | Design: usability and style | 10 Pts | ## Deployment - 10 Pts (TA will grade) | Task | Grade | | ----------- | ----------- | | Backend deployed successfully | 5 Pts | | Frontend deployed successfully | 5 Pts | ## Conceptual Questions - 15 Pts (TA will grade) | Task | Grade | | ----------- | ----------- | | Question 1 | 5 Pts | | Question 2 | 5 Pts | | Question 3 | 5 Pts |