VinFlix

Full stack, single page, pixel perfect recreation of Netflix.com

User Authentication

VinFlix uses custom frontend routes and real-time error handling to prevent access to any feature without verification

Upon account creation, passwords are hashed using the BCrypt function and a randomized session cookie is stored on the client-side browser. When logging in, the user sends a request to the server with the non-plaintext password in the header. If the password and browser cookie match, they are granted access. Passwords are never stored in plaintext and the cookie is reassigned at every login. Shown below is the User model and the different methods attached to each instance.

class User < ApplicationRecord 
	validates :email, :password_digest, :session_token, presence: true 
	validates :email, :session_token, uniqueness: true validates :password, length: { minimum: 4, maximum: 60, allow_nil: true } 
	validates :email, format: { with: /\A[\w+\-.]+@[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i, on: :create } #Uses regex to validate email format 
	
	attr_reader :password
	after_initialize :ensure_session_token 
	
	def self.find_by_credentials(email, password) 
		user=User.find_by(email: email)
		return nil unless user && user.is_password?(password)
	end 
	
	def password=(password) 
		@password=password
		self.password_digest=BCrypt::Password.create(password) 
	end 
	
	def is_password?(password)
		BCrypt::Password.new(self.password_digest).is_password?(password) 
	end 
	
	def reset_session_token!
		self.session_token=SecureRandom.urlsafe_base64(16) 
		self.save! 
		self.session_token 
	end 
	
	private 
	def ensure_session_token 
		self.session_token ||=SecureRandom.urlsafe_base64(16) 
	end 
end

React/Redux

The user interface is managed via a collection of React.js components each with their own individual state. Redux.js is used to direct the global state of the web application as well as pass pertinent information to specific components. Shown below is the VideoIndex component and it's respective subcomponents.

When changes are made to the global state, I implemented the five step Redux cycle. First, I coded a backend utilities file which would perform an Ajax request in order to receive information stored in the database. Second, based on the user's interactions with the UI, I designed and dispatched an action. Third, my thunk middleware intercepts every action. If the action is a function (Ajax request), it is sent to my backend. If the action is an object, a "promise" is returned and sent to my reducer. Fourth, I structure a reducer which receives dispatched actions and acts as the blueprint of how the store should be changed. Fifth and finally, I create a store to, quite literally, store my global state.


Amazon Web Services/Heroku

As a data-heavy application, I chose to use AWS S3 to store my large video files. I started by creating a S3 bucket, filling it with mp4 files, configuring the security policies, and writing a seed file that links mp4 files with specific database entries. Afterwards, I installed the "Active Storage" gem, migrated changes to my database to allow files stored in the cloud to be attached to Rails models, and updated my app's credential file with my key. Shown below is my VinFlix-dev bucket. No, it's no longer public.

After downloading the CLI, migrating my static assets to a Asset Pipeline, installing webpack, and ensuring my application is production-ready, I used Heroku to host my application. I frequently monitor the metrics and Heroku logs to check on my baby.


Custom Video Player

When a video is selected, Vinflix's custom video player is opened. Using JavaScript event listeners, React refs, and the HTML5 video element, the player features volume toggling, custom seeking (fast-forward/rewind) functionality, an input bar to represent your place in the video, and a dynamically changing UI based on how user's interact with the video.


Modern Styling

Using the most up-to-date CSS3 tools and the WebKit rendering engine, VinFlix attempts to replicate Netflix's extravagant styling down to the pixel. While styling, user experience was placed on the forefront. Complex add-ons like automatically zooming in and playing videos upon hover, adding a scroll bar to see each video in a specific category, video information popping up when a video is paused, and real-time error handling all add a professional element to how a user can interact with the application. Shown below are some of my favorites.