Personal Website on DigitalOcean App Platform
Tags: dohackathon
Published: 2021-01-11 06:37:47

## What I built
A personal website with Node/Express/MongoDB I created to demonstrate my knowledge of web development and show off previous project experience.

### Category Submission: 
Personal Site/Portfolio

### App Link
https://smoran-dev-rewrite-7oeyl.ondigitalocean.app/

### Link to Source Code
[GitHub Repo](https://github.com/sdmoran/smoran-dev-rewrite)

### Permissive License
MIT License

### Description
I chose to use this Hackathon as an opportunity to give my personal website, [smoran.dev](https://www.smoran.dev), a makeover. By no means is it the most beautiful site, but I am nonetheless proud of the non-trivial technical achievement involved in its implementation. I'm particularly proud of the "admin" site, where I (or anyone else who clones the repository) can quickly and easily add information and images about projects and have them cleanly displayed on the public-facing site, complete with links to a GitHub repository or live instances of the project.

## Background
#### Motivation
I created the first iteration of my website about 2 years ago as an initial foray into web development. Though I learned a lot doing so, I've since had much more exposure to the technologies available for web development. I decided it was time to refresh my website so I can more effectively show off projects I've completed in the past.

In my site's first iteration, I used Django and Bootstrap because they're powerful frameworks that do a lot of the heavy lifting associated with web development. Django's built-in admin panel and ORM for managing a database was great for me because I didn't know much about security or SQL, and Bootstrap's prepackaged components made designing a workable UI quick and easy.

However, this time around, I chose to ditch Django and Bootstrap and start over from scratch. For a simple, mostly-static website like mine, I don't need a framework as powerful as Django; instead, I wanted something more flexible and customizable. I decided not to reuse Bootstrap again for the same reason.

Instead, I opted for a Node/Express/MongoDB stack, using TailwindCSS for styling. While I've done a little bit of work with Node/Express/MongoDB in the past and enjoyed it, I hadn't ever dedicated the time to create a larger and more robust site with these technologies, and this hackathon seemed like the right opportunity to explore them further. TailwindCSS had been on my radar for a while and I'd heard good things, but I'd never actually used it before. This hackathon was an opportunity for me to try out some new technologies and really see what I could do with them.

### How I built it 
Despite my intention to use my website as a public-facing portfolio for project work, I spent a great deal of time developing a robust backend that only I (or others who clone my code) will ever see, creating forms for adding, editing, and deleting projects in a straightforward and convenient matter. I built all the infrastructure involved in doing so from scratch, including implementing an API for handling image uploads to an Amazon S3 bucket and interacting with a MongoDB database. I'll be the first to admit that my UI design skills are not the strongest, but I nonetheless think the overall design is reasonably modern and visually appealing.

For dealing with credentials for the database and S3 bucket securely, I used environment variables. Things like the MongoDB and AWS URLs, usernames, and access keys are all set via corresponding environment variables. The exact variables that need to be set for the site to function correctly, should you want to clone it, are listed at the end of this post.

One unconventional design choice I made was to make the admin panel ONLY accessible in development mode. This is enforced by a custom Express middleware function I wrote. Before rendering a page on the "/admin" route, it checks the status of an environment variable, "MODE", which is set to "dev" on my local machine and "prod" on the DigitalOcean App Platform. If the value is not "dev", it displays the 404 page. This allows me to add and edit projects to my site ONLY from my local machine. This is very secure, but also inconvenient, so in the future, I think I'll add a way of logging into my website - probably with Passport.js - so I don't have to be at my computer to add or edit projects.

#### Technologies
##### Server: Node.js with Express
For the redesign, I chose to base my site on an Express/Node.js server. For me, Express has the right mix of functionality and flexibility. There are many packages and libraries available for Express that make things like uploading files and dynamically rendering HTML much easier, but unlike Django, it doesn't come with any by default, and in most cases there are multiple options, so it's overall less opinionated - and therefore more flexible.

##### Database: MongoDB
I chose MongoDB because it's a NoSQL, JSON-based database. In my opinion, this makes it ideal for storing information about things like projects, which may have various and inconsistent fields associated with them - for instance, for some projects, I have Github URLs that I want to link to, but not all. The number of paragraphs of description and images associated with each project also varies. While these structures could also be captured in SQL by nullable fields or one-to-many relationships, another advantage of MongoDB is that it natively supports data in JSON format, which makes it extremely easy to use alongside my Node.js backend.

##### File Serving: AWS S3
I have screenshots of most of my projects that I wanted to show off on my website, and I opted to use an S3 bucket to store and serve them because I felt it made the most sense; while I could have uploaded and served files myself, using S3 means that these images will be available in production as well as on my development machine. When a project is created or updated, any images associated with it are uploaded to S3, then the object URLs are stored in the database entry for that project and can be linked to from my website.

##### Render Engine: EJS
I used EJS as the render engine for my Express app, which allowed me to dynamically render HTML on the server-side of things. This was particularly helpful, for instance, when I wanted to render multiple similar objects like projects and their descriptions. Using EJS saved me from having to write queries from the frontend to API endpoints in order to retrieve and subsequently render data.


##### Deployment: DigitalOcean App Platform
I had an excellent experience deploying my app with DigitalOcean's App Platform; it was the easiest part of the whole process. Once I connected my App Platform project with the GitHub repository for my code and set the proper environment variables, deployment was as easy as clicking the "Deploy" button. Hooray!

### Screenshots
I'll skip over pasting many screenshots of the public-facing site here; you can check it out yourself [HERE.](https://smoran-dev-rewrite-7oeyl.ondigitalocean.app/)
Here's just one of the home page:
![Home Page](https://dev-to-uploads.s3.amazonaws.com/i/pmyn7t5rmhgsbtlqs62l.png)

Here are some screenshots of the admin part of the website, which isn't publicly accessible:

The list of all projects currently on the site. The "Delete" button will of course delete a project, while clicking on the "Edit" button will take you to a form which allows you to see the details of a project and make edits as you see fit.

![Admin All Projects](https://dev-to-uploads.s3.amazonaws.com/i/7k8zh58vujppchyrkbkh.png)

The form for adding and editing a project. There is only one EJS template for both adding and editing a project; for editing a project, the form is simply populated with the current state of the project.
![Edit Project](https://dev-to-uploads.s3.amazonaws.com/i/78u2k5q9brrm65bom6dz.png)


### Additional Resources/Info
If you're interested in playing around with my code or deploying it to the DigitalOcean App Platform for yourself, you'll need to set a few different environment variables for all components to work correctly. Here are a list of all of those: 

* DB_URL: The URL of a MongoDB database to store data about projects. I used one hosted in MongoDB cloud; it worked great!
* DB_USER: The username for your MongoDB database.
* DB_PASSWORD: The password associated with the username for your MongoDB database.
* DB_NAME: The name of your MongoDB database.
* AWS_ACCESS_KEY_ID: Exactly what it sounds like, the access key for your AWS IAM role / root user that has access to the S3 bucket you want to write to.
* AWS_SECRET_ACCESS_KEY: The access key associated with your access key ID.
* AWS_BUCKET: The name of the S3 bucket your images will be uploaded to.

Thanks for reading, and thanks to DigitalOcean/DEV for organizing  this hackathon! I had a lot of fun and learned quite a lot about the specific technologies I used, as well as web development as a whole. I'm most proud of the work I put into developing this site; I think it's the most feature-rich, technically robust, and visually appealing web project I've developed to date. I'm looking forward to continuing development and adding new features in the future!