Submission By Erik Montag
GitHub Username: emontag47
Link to the private repository
Link to my GitHub profile page
- Frontend: React, TypeScript, React Testing Library, Jest
- Backend: Python, Flask, Pytest, MongoDB
Clone the repository to a directory of your choice
cdinto thefront-endfolder- Run
npm cito install the necessary dependencies - Run
npm startto spin up the program onhttp://localhost:3000 - To run the test library, run
npm testin the terminal window
cdinto theback-endfolder- Run
pip install -r requirements.txtto install the necessary dependencies - run
python app.pyto spin up the backend onhttp://127.0.0.1:5000 - To run the test library, run
python -m pytestin the terminal window
- Install and run MongoDB via the instructions here (MAC)
- This brings up an instance
MongoDBonmongodb://localhost:27017/. I then created and used a db namedNewRelicand a collection namedCustomerData- I used
ChatGPTto generate amongoshcommand to insert random data into the database following the model{ firstName: string, lastName: string, companyName: string }
- I used
At this point, you should be able to navigate to the frontend link in your browser and view the functional program.
* With every assumption or choice made, I would ask the Product Owner and Designer additional questions before programming, or run the choice by them to get their thoughts and feedback.
- With no specific design requirements, I decided on a simple layout with a dark background and white text for ample contrast.
- Additionally, I have chosen to display the results as a table with a column for first name, last name, and company, believing this is a clear way to display all of the data from the database.
- I would work with the PO and/or designer to rework any of these design choices to ensure the best user experience. I would also work with them to determine if this is the information we want displayed.
- I implemented options A and B from the spec. I have situated them next to each other with the results displaying directly below them, fairly similar to the GitHub UX mentioned in the spec.
- For option A, I created the
SearchBarcomponent to allow users to search for customer information by name. The component allows for user text input and when the user clicksSearch, the component sends the search term to theSearchComponentcomponent, which I will discuss below. A call to the backend is made and information tied to any customer with a first or last name that matches the search term is displayed below the search bar.- The query is sent to the backend via this url:
http://127.0.0.1:5000/customers?search={searchTerm}.
- The query is sent to the backend via this url:
- For option B, I created the
CompanyDropdowncomponent to allow users to filter customer records by their company. When the component renders, with the help of theuseEffecthook, the program makes a call to the backend/companiesendpoint to receive a list of distinct companies that are present in the database. The component then displays these companies as options in the dropdown element. When a user chooses a company from the list, the company name is sent to theSearchComponentcomponent, which I will discuss below. A call to the backend is made and information tied to any customer with a company that matches the chosen company is displayed below the dropdown element.- The query is sent to the backend via this url:
http://127.0.0.1:5000/customers?filter_by_company={companyName}.
- The query is sent to the backend via this url:
- To display the results, I created the
SearchResultscomponent. The results are passed from theSearchComponentcomponent as a prop and then displayed as a table. The results list is of typeCustomer[], which I created for the use of this project. If there are no results, the text "No Results Found" appears. Otherwise, the table of results has a header row with columns titled "First Name", "Last name", and "Company". The rest of the table is populated with the results. I have this component become scrollable when it reaches a certain height. Of course, with very large datasets, pagination may be preferable, as mentioned in the spec as a possible next step during future interviews. - To house the above components and drive much of the backend API calls, I created the
SearchComponentcomponent. This component has the above three as child components and receives information from them, such as the search term and company name for the search or filter options. When a search term from theSearchBarcomponent is received, it makes a call to the backend with the query url above with the relevant query parameter. When it receives a company name from theCompanyDropdowncomponent, it does the same. When a response comes back after either of these requests, theresultsstate variable is set, which is passed as a prop to theSearchResultscomponent and the results are displayed. - Overall, I followed what I believed to be straightforward architecture. A component for each information retrieval option (A and B), a component to display the results, and a component to tie them all together and drive the necessary code. At first, I had the
SearchBarandCompanyDropdowncomponents making the API calls, receiving the results, and rendering theSearchResultscomponent themselves, but then assumed the task was to build a more unified experience, and refactored the code to have theSearchComponentcomponent handle much of this and render one instance of theSearchResultscomponent. I also believe, how I have implemented theSearchResultscomponent would allow me to implement the sorting feature from option C simpler, should it come up in future interviews.
- For the backend, I followed the Controller Service Repository architecture.
- For the controller layer, I have two
GETendpoints that support the frontend. The first is the/customersendpoint, which can be called to receive specific customer records. The relevant service functions are called based on the query parameter received as part of the request. The second is the/companiesendpoint, which can be called to receive a list of the distinct companies in the database. This controller also calls the relevant service function. These controllers are the gateways into the backend and leave the logic/functionality to the service layer and repository layer. - The service layer has a few functions that are called by the controllers, as mentioned above. They call the repository layer with the parameters passed from the controller layer. For this project, this layer does not require much logic, making it fairly lightweight. A service function built to support option C would have more as it would do the sorting and ordering necessary after receiving the specified N elements from the repository layer.
- The repository layer is where the backend interacts with the
MongoDB. It houses a few functions that help retrieve the information needed based on incoming requests. The first is thefind_customers_by_name()function, which takes in a name as a string and queries the database to retrieve any record where the first or last name matches that string exactly (case insensitive, but a search term of "John" would not return "Johnson"). Next, thefind_customers_by_company()function takes in a company name as a string and queries the database to retrieve any record with the company. If the incoming company name is "All Companies", it retrieves every record in the database. Finally, thefind_all_companies()function retrieves a list of all the distinct companies present in the database. - I used
MongoDBas my database because I find it simple to set up and integrate with Python.
- I wrote relevant tests for each frontend component and backend layer. They are housed in their respective directories.
- Apart from the next possible steps mentioned in the spec, I would plan some of the next steps to focus on authentication. Assuming a real-world implementation of this application would house sensitive data, we would need authentication on both the back and front ends. The backend could use token-based authentication to ensure only authorized users have access to the endpoints. Similarly, the frontend could have an authentication/login page to ensure that only authorized users can access the UI. All together, these would keep the customer data accessible by this project much safer.
- Phone Number: (404) 680-0544
- Email: erikmontag@gmail.com
- LinkedIn profile