Up to now, and maybe without realizing it, you have been developing the server side (backend) of a web application. In this checkpoint, you will give your project a frontend (AKA - a client side implementation)! A frontend allows for an end user to access your project through a user interface (UI). The previous two checkpoints (C1 and C2) built the backend of your application and although your tests can access your methods, it would be hard for a user (like a parent or friend) to use them. In C3, you will complete your application by building a frontend to allow easy access to your backend endpoints (addDataset, removeDataset, listDataset and performQuery).
In this checkpoint, there are two phases. Note, you can and may want to work on elements of Phase 2 during Phase 1. For example, you can begin implementation of the required user story and initialize your chosen frontend. If choosing a frontend that you are less familiar with it might be worth doing a proof of concept to make sure implementation will go smoothly.
05-11-2021:
Added Note to "One Required User Story" section to emphasize the server component.
Updated "Submitting your user stories" section to include more detail on how to edit a Github Issue and added a screenshot to the end of this document of the edit button.
Choose the type of frontend you will build
Write and submit three user stories (graded)
One required user story has required contents and two custom user stories will be designed by your team.
VERY IMPORTANT: We will use the acceptance criteria of these users stories to grade your C3 implementation.
Implement the required user story. (graded by AutoTest, smoke tests provided)
Implement your custom two user stories.
Demo your application to your TA during your final lab (graded)
ATTENDANCE TO YOUR FINAL LAB IS NECESSARY TO RECEIVE A C3 GRADE.
The schedule contains the due dates for Phase 1 (User Story Submission) and for Phase 2 (Demo).
You can choose any frontend for your project! Have some fun, go a little wild! The only requirement is that all frontend code resides in a /frontend directory in your project_teamXXX repository. We will be providing starter code for a basic Web frontend and Braxton has built starter code for a Discord frontend. Both frontends require installing new node packages and similarly, you can install additional packages as needed by your own frontend of choice! You can also choose any language for your frontend.
You should select your frontend before writing your custom user stories, as it will provide context for how your end user will access your application.
If you select the Web as your frontend and choose to use our Bootstrap, you will build a website using HTML, CSS and plain JavaScript which will send REST commands to your server. You can demo your website locally, by starting the server and clicking elements in the UI to perform a task for your end user. If you select Discord as your frontend, your end user will interact with your server via Discord! They can send messages, which will be listened for by your Discord bot and then forwarded to your server. There will be more implementation details on both of these frontends in the Implementation section.
Disclaimer! TAs are only familiar with the Web frontend, as that has been used in previous semesters. The TAs will not be able to provide the same level of support for alternate frontends.
During the first phase of C3, you will write user stories that outline how your end user can use your web application to get desired outcomes. In the second phase, you will then design and implement the code to realize your user stories.
You are required to provide a minimum of three user stories. The first one is given to you, and the remaining two you should come up with involving the frontend UI. Though you're free to write and implement more than two custom user stories, you will be graded based on just two of them.
A user story should describe the type of user, what the user wants to do with your application, and for what benefit.
Note: A user story should be in general be agnostic of your frontend of choice. It should encode "what" the user can do with your application, not "how". The "how" belongs to the Definitions of Done (more about this in next section). Simply put, if you find yourself describing your UI in a user story, be aware!
You should use the Role, Goal, Benefit framework:
As a [role], I want to [goal], so that [benefit].
[role]: Who is using this?
[goal]: What is the user trying to achieve?
[benefit]: Why does the user want to achieve this?
For each user story, you will write definitions of done (DoD) that define the conditions your application must meet before it is accepted by the user of the story. In other words, DoDs are agreement between you and your user about when an application feature is considered “done”. For each user story, the DoDs should describe "how" your application supports the user in achieving the said goal. When demo-ing your user stories during the final lab, we will use these DoDs to grade your project. Please think of both the successful and failure cases.
Your DoD should follow the Given/When/Then framework:
Scenario: The name for the behaviour that will be described
Given: Some initial application state (precondition)
When: The user do some action
Then: Some outcome state is expected (post-condition)
As an example, for a user story, “As an online bank user, I want to be able to log into my account, so that I can access my banking information online,” you may have these DoDs:
Scenario 1: Correct credential
Given: The user is on the login page
When: The user enters a valid card number and password pair and clicks “Log in”
Then: The application logs the user in and presents the dashboard page
Scenario 2: Incorrect credential
Given: The user is on the login page
When: The user enters an incorrect card number and password pair and clicks “Log in”
Then: The application remains on the login page and shows an error in red telling the user to try again
User story: As the client application, I should be able to carry out all the standard operations (add/remove, list, perform query) on my dataset using the REST APIs, so that I can construct a remote frontend.
Note: This user story only pertains to the server (being able to access it via REST calls), there is no client application built yet. The user wishes to build a client (frontend) application, and requires the server (backend) be complete.
Definition of Done:
You will write this part yourself and in the Given/When/Then framework described above. The details of the expected behaviour are outlined in the implementation part of this specification document. You may need multiple Given/When/Then scenarios. Don't forget about the failure cases!
You will write two custom user stories which will be implemented and demo-ed at the end of the semester. We will provide feedback on your user stories and it is important that you take that feedback into consideration for your implementation.
Each custom user story should follow the format outlined in the above section: Role, Goal, Benefit and Given/When/Then.
The scope of a user story is subjective, so to receive full marks your user story must:
Solve a use case for the user. For example, a user that loves sushi would like to see the best sushi restaurants in Vancouver.
Be end-to-end. It must pass through the entire stack and provide feedback to the user. A user story must be evoked by a user interacting with your UI, which causes a request to the server. The server then responds and updates the UI with visual feedback. For example, when I click “search” in Google, I expect to see a list of search results.
Make sure your user story follows the INVEST principles!
Note: we are not marking the aesthetics of your frontend (rounded corners, pretty colours). The marks will be based on satisfying your DoDs.
Below is a list of things you CAN do in your custom user stories:
Use the endpoints provided by the required story. For example, you can use the endpoint to list the results of a general or specific query.
Create a new server REST endpoint.
Create a new controller to add a new method for a new endpoint. However, you cannot alter the IInsightFacade interface in any way. You must create a new class/file if you'd like to add a new method for an endpoint.
Below is a list of things you CANNOT do in your custom user stories:
alter the IInsightFacade interface
re-create the Campus Explorer UI (JSON query text input with a table output)
In your team's repository, there will be a new Github Issue created by autobot called “<LXX>-team<XXX> C3 User Stories”. Please edit the existing issue's body with the required sections with your user stories. Please edit the template given in the issue to make your submission.
You can edit the user story by clicking the three dots in the upper right-hand corner of the issue and clicking "Edit". There is an image of this menu at the end of the spec (Google Sites does not allow text and images, grrr).
We will be providing some bootstrap code for a Web and Discord frontend, but you are welcome to choose any frontend you like! The only requirement is that all frontend code resides in a /frontend directory in your project_teamXXX repository.
There will be an optional pull request from autobot for the web frontend. We’ve provided a simple implementation that contains a button that when clicked shows an alert.
You will also need to uncomment the following line in your Server.spec.ts file:
this.express.use(express.static("./frontend/public"))
This line is what servers your frontend to the root of your application.
The subdirectory public contains the static sources that will be hosted by your Web app:
index.html contains the starter HTML code for the UI. This file is hosted by the GET/ endpoint of your REST server. This will already be implemented in the bootstrap as well.
style.css contains the styles for the UI.
frontend.js will contain the logic to listen to the button click event and show an alert.
There are two new aspects to the Web frontend that you haven't seen in early checkpoints:
Plain JavaScript. While it is theoretically possible to develop in TypeScript on the frontend as well, using plain JavaScript has the advantage that you won't have to build/compile your project when you work on the frontend.
Browser. You will dive into the world of browsers with your frontend implementation. Your frontend code will be run client-side in the browser and will communicate with your Web server via REST/Ajax calls. This means also that you will have the global window, document and XMLHttpRequest objects from the browser available anywhere in your code.
Please checkout the starter code in this repository: https://github.com/braxtonhall/bot-starter.
It may also be useful to view the discord.js package: https://www.npmjs.com/package/discord.js
In order to respond to requests from your frontend UI, you will complement your backend with a web server that surfaces your InsightFacade methods.
Once you merge the pull request from Autobot, you'll have three new files in your project associated with the implementation of a Web server:
src/App.ts contains the source code for starting the application and initializing the server. This will be given to you for free.
src/rest/Server.ts contains the logic for your server.
test/rest/Server.spec.ts contains the tests for your server.
Both the Server.ts and Server.spec.ts files will contain some sample code to point you in the right direction. We will use express as a REST server library. Please refer to its documentation first whenever questions arise.
You will adapt your existing InsightFacade to also be accessed using REST endpoints. Both InsightFacade and the REST endpoints must continue to work independently.
Your Web server will need to provide the following REST endpoints exactly as they are specified, because your client will leverage on these endpoints to build their frontend for the Required User Story.
PUT /dataset/:id/:kind allows one to submit a zip file that will be parsed and used for future queries. The zip file content will be sent 'raw' as a buffer, you will need to convert it to base64 server side.
Response Codes:
200: When InsightFacade.addDataset() resolves.
400: When InsightFacade.addDataset() rejects.
Response Body:
{result: arr}: Where arr is the array returned by a resolved addDataset.
{error: err}: Where err is a string error message from a rejected addDataset. The specific string is not tested.
DELETE /dataset/:id deletes the existing dataset stored. This will delete both disk and memory caches for the dataset for the id meaning that subsequent queries for that id should fail unless a new PUT happens first.
Response Codes:
200: When InsightFacade.removeDataset() resolves.
400: When InsightFacade.removeDataset() rejects with InsightError.
404: When InsightFacade.removeDataset() rejects with NotFoundError.
Response Body:
{result: str}: Where str is the string returned by a resolved removeDataset.
{error: err}: Where err is a string error message from a rejected removeDataset. The specific string is not tested.
POST /query sends the query to the application. The query will be in JSON format in the post body.
NOTE: the server may be shutdown between the PUT and the POST. This endpoint should always check for a persisted data structure on disk before returning a missing dataset error.
Response Codes:
200: When InsightFacade.performQuery() resolves.
400: When InsightFacade.performQuery() rejects.
Response Body:
{result: arr}: Where arr is the array returned by a resolved performQuery.
{error: err}: Where err is a string error message from a rejected performQuery. The specific string is not tested.
GET /datasets returns a list of datasets that were added.
Response Codes:
200: When InsightFacade.listDatasets() resolves.
Response Body:
{result: arr}: Where arr is the array returned by a resolved listDataset
In addition to the above endpoints, you’re free to add more as you need to implement your two custom user stories.
The :id and :kind portions above represent variable names that are extracted from the endpoint URL. For the PUT example URL http://localhost:4321/dataset/mycourses/courses, mycourses would be the id and courses would be the kind.
Note: Those of you paying attention in lecture may notice that this is not a very RESTful API. As an exercise, consider how you could modify one of the endpoints to make a more RESTful API!
The same libraries and frameworks as before (Mocha, Chai) will be used for testing. This time, however, your tests will have to send requests to your backend and check the received responses for validity. The bootstrap code in test/Server.spec.ts will point you in the right direction.
Note: The response formats for the 2XX and 4XX cases may look slightly different. You should use the debugger to inspect the responses to determine where to find the values you want to test.
To run the smoke tests, you can call AutoTest with @autobot #c3 on the commit of interest on the master branch.
A new yarn command yarn start will be available in your project through a change to package.json. It will essentially run App.js as a node application. Once you have started the server, you'll be able to access the app in the browser at http://localhost:4321. Please note that your datasets must be available for the UI to work. You could find a way to call addDataset using one of your endpoints, or keep a cached copy of your data around and just paste it into your ./data folder so the server can load it from disk.
Your final project grade consists of 1. Final check-in test score 2. User stories & demo.
This is the AutoTest-tested portion of your project grade, which evaluates C1, C2 functionalities cumulatively. For C3, the required story's implementation (REST APIs) is tested by AutoTest and will also contribute to this portion.
Phase 1: User Story Submission (5%)
Required user story (1%)
Custom user story one (2%)
Custom user story two (2%)
You will receive a 0, 0.5 or 1 for each user story. 0 = no effort, 0.5 = missing key element, 1 = wahoo!
We will not be accepting LATE submissions. You will not get feedback from your TA or a grade if you submit late.
Phase 2: Demo (15%)
Custom user story one (7.5%)
Custom user story two (7.5%)
For your custom user stories, you will receive a 0, 0.5, or 1 for each user story. 0 = no effort, 0.5 = missing implementation or major bug, 1 = wahoo!
There is no best way to get started, but a few hints may help you:
Create the big picture of your project in your mind. Use pencil and paper and draw some diagrams. Where is what component and how do they interact with each other? What's on the client and what's on the server?
For selecting a frontend - what frontends are both yourself and your partner familiar with? If choosing a frontend other than web, it may be worth doing a small proof of concept to ensure you can successfully complete C3.
The two parts in this checkpoint (server, frontend) should be implemented and tested independent from each other. They are only hooked together with Ajax requests going from the frontend to the server but all parts are designed to be implemented and tested independently.
Good luck and we sincerely hope you'll also have some fun implementing this checkpoint!
Q. How can I make sure my backend already has datasets that my frontend can query?
You could of course implement the ability for an end user to add a dataset from the frontend UI, but this is sometimes complex (and may not be one of your user stories). For all frontends it is not necessary to provide a way to upload a dataset. Instead you can start your server with pre-existing datasets in your /data directory to load it into your InsightFacade instance.
Q. I'm still working to finish C1/C2, how would these checkpoints affect my C3?
C3 is can be almost entirely independent from C1 and C2, except for the required REST endpoint user story. Here, in order to test your endpoints, the client can use functionalities from C1/C2 to interact with your backend. However, your two custom user stories can be designed such that only pre-implemented parts of your C1/C2 will be used.
The below image demonstrates how to edit the GitHub issue for submitting your User Stories.