Polling Webapp written in React/Express/MySQL
Polling Webapp written in React/Express/MySQL
The main idea behind this project was to create a portal that allowed users to create polls and share them on their social networks in order to gather a crowdsourced opinion. Apart from that, the other goal of the project was to focus on the social aspect of the project where people can vote on polls on a feed and also be able to see data on their polls. A few other features were also added that enhanced the experience. The main goal was to make sure that a user can vote without having to login in order to encourage engagement and also make sure that each user gets only one vote. A wide range of metadata is collected just from the platform where the request originated. For eg. the IP address provides further information on the user’s location. In addition to that, device data and browser data and timestamp at when each event was recorded. There's a stat platform which includes all the stats like number of polls created, number of votes, number of events, number of distinct IPs, Browser data, device data, endpoints accessed, then data on how the poll attributes were entered, timeline of event creation and poll creation, division of tags and finally map of where the events occurred. Another feature was to decide tags based on a custom trained NLP model on DialogFlow.
The very simple purpose of the app is for a user to be able to get a crowdsourced opinion on a question. The news feed function is both a source of information and fun. There are multiple narrow scoped uses for our project. For eg, crowdsourcing is a very important part of Human-Computer Interaction and there is extensive scope in the research for how people respond/provide feedback depending on different stimuli offered. We also added a feature where the creator of the poll can set poll behavior. For example - show the status of the vote before the voter decides on a vote and see how popular vote sways the result as compared to a blind poll. Another important area of use could be corporations asking for feedback from their users to help them decide areas to focus on based on demand. There are some websites which have some overlap to what we plan to achieve. Doodle is the first result on a quick Google search on our idea and they provide a polling service to coordinate meetings which are very different from our original idea. The other websites that overlap are overly complicated and their designs seem like they haven't been updated since 2006 (when the use of Marquee wasn't ironic). We personally used the website to settle debates about whether Pineapple goes on Pizza and what the best operating system was.
Since the core of the project is surrounded by data, the application aims at collecting as much data as possible whenever users vote or create polls. At a high level, our application consists of the following data:
One of our main goals for this project was to allow voting without logging in. If login is mandated to vote it becomes easier to account for uniqueness but since we wanted to allow voting without logging in, we needed to account for a lot of things to ensure uniqueness. There are a few layers to each vote. Consider a scenario when a user first votes on a poll. After the vote is added, we use the browser’s persistent storage to log the poll_id and their selection. Next, we log in the IP address of the user and the poll_id in our activity table. Now there are a few possible ways for a user to be able to vote on the same poll again just based on these checks. If a user switches their network for example from their work to home, their IP address changes and so they would technically be allowed to vote again. Also, if a user uses a VPN to port their IP address to some other location they could technically be able to vote again. To account for these we used the following measures :
Another challenge we have is to account for incognito mode. Incognito mode prevents access to the same local storage as for the nonincognito mode and so all the checks for the network switch will be lost. In order to prevent multiple votes on the same poll from a user, we restrict voting on incognito mode. For this, we needed to be able to detect if a browser is being used in incognito mode. Another challenge here was that each browser is built differently so checking for incognito mode needed to be done in different ways based on what the browser was. For example, in Google Chrome on the desktop window.requestFileSystem returns false. After account for that, if the poll or feed is accessed in incognito mode, our website will detect that the user is browsing in incognito mode and display a message to switch back to normal mode in order to vote. Finally as an additional check, for the users that did log in, we kept a running count of all the IP addresses they have logged in with. This allowed us to check if a user is voting on another poll by switching browsers if they were on another one of their commonly used IP addresses. Also, we could make the feed personalized to a logged in user by showing them the polls that they haven’t voted on yet by joining the acti vity table and IPs table. Even for users that haven’t logged in, the feed can be tailored to their IP address based on if a vote has been logged in the activity table for that particular IP would be shown last.
We also created an event logger from scratch which accessed data about the browser and the user’s device. From the IP address we were able to obtain a user’s geographical location and finally, we logged in the time when it occurred. These loggers were placed in the constructors of various routes which were likely to be accessed the most and when hit, the event logger posted data to the events table. All the extensive data we collected combined with the various tables in our database to find out all the statistics that would be important from a developer’s point of view. The platform stats page shows :
We faced a lot of challenges during the course of this project. Initially, most of the challenges were because no one in the team had worked with React before and understanding it and getting it to do what we wanted was hard. Also deploying our app to cPanel was annoying because its interface is archaic so we moved to Heroku instead. Another problem we faced was with deploying our react app with node backend using the express framework. Our server was running on port 5000 and react ran on port 3000. Getting both the ports to communicate required adding a proxy to the React which took some time to figure out. After our template app was successfully deployed the form was the next challenge. We wanted the UI to be as seamless as possible while supporting thorough input validation so that our database doesn’t store corrupt data. These were mostly frontend based challenges that were cleared by reading articles online. Another problem we had was with the MySQL npm package we used. It requires the input in a certain way - for eg., table names need to be enveloped by apostrophes (‘poll’). If a user Added an apostrophe in their question or options, MySQL would throw a syntax error. To account for this we used RegEx to replace every apostrophe in the input with "§" and then replace it back again before displaying it on the frontend. Figuring out all the aspects of a unique vote without having to log in was challenging and we needed to do a lot of research on how browser APIs worked to be able to detect incognito mode and also how tech companies like Netflix detect VPNs in order to follow suit for our application. Logging through Facebook also caused significant grief. Since their data breach, they have only made oAuth accessible on SSL. We hosted our app using a dyno in order to add Facebook login. Another challenge was to create an embed endpoint in order to be able to embed a ballot poll anywhere on any website. This occurred because <i frame> basically embeds a webpage within another and for our case, we had a persistent login head from the Route.js page. It wouldn’t have context on another page and the app would crash. To account for this I added a handler function which was passed to the embed component on react and in the constructor I called the function which changed state in the parent. This allowed us to be able to embed polls within other websites.
Try it out