Crafting Memories: A Graduation Gift for Friends
My final graduation gift – for a select group of friends
As graduation approaches, I wanted to create a site to share some of my fondest memories for a select group of friends. The idea is that each friend would receive an access code in the goodie bag I prepared. Scanning it will redirect them to the site, containing memorable images/moments and videos of me and the said person.
My main mission is to not spend a single dime and rely on ways to make this application free. The last thing I want to do is spend money for graduation.
The Site (though you can't do much because you don't have an access code)
In this blog post, I'll run you through my thought process, splitting into ideas and then bringing everything together with conclusions and what I've actually learned.
~ Starting off with how I would like to 'design' the access code for each individual.
Ideas for an access code
The access code plays an important part. Each person will receive a unique access code. Initially, I came up with the idea to use pass-phrases such as shuffle-playing-encircle-thickness
. But then, I want the access codes to be personalized for each person.
And that's where the idea came in! I can just use their name followed by adjectives. Such as jane-the-broccoli
or jack-the-OG
.
After all, personalization is really my thing ✨
Okay, where do I store these images and videos?
I sat down and thought of ways to host images and videos for free. Each person averages 3 pictures, showing my fondest memories with them throughout my 4 years in poly.
First, I thought of using AWS S3 Free-Tier. It was generous and also I have used it during my internship. But then, I don't want to spend time learning it again – I totally forgot how to upload assets to S3 programatically. Moreover, I want the site to be up and running. Graduation is coming in two weeks!
I sat down and realized I can use Imgur and unlistied YouTube videos!
I got the assets sorted... What framework should I use for the site?
Okay, now that assets will be handled by Imgur and YouTube. I need a framework that can help me get the site running in no time. Something that, perhaps, have simple hosting solutions (that are also free!) Sounds familiar? – was it Next.js?
Apart from Next.js being the fastest framework I can use to get the site up and running, other considerations such as easiness of spinning up an API route and Server-Side Rendered (SSR) pages are why I chose Next.js
Anyways, in a later section, SSR will play a huge role. Keep this in mind!
Designing the data structure
Again, I want it to be fast, not in terms of speed of the site but the development time. By now, graduation is about 10 days away. The first thing that came to my mind is JSON! Why not, they're easy to access anyways. That is when I designed the following data structure:
Let's say John is a really great friend of mine, here's how his data will look like:
"john-the-og": {
"name": "John",
"content": "Thanks John!",
"images": [
{
"url": "https://image.com/img.jpg",
"desc": "Us in class"
}
],
"videos": [
{
"yt_embed": "9D0Sjd99J",
"desc": "A song that reminds me of you"
}
],
}
Ah, that makes it simple. Each person will have it's access code as the key and the data as the value of the object.
Now... where do I store all these?
Storing the data
Okay, call me wild, but for the sake of development speed, I initially wanted to just have a data.json
file containing all the data and access code in the structure shown above. But after some thinking, I didn't want the codebase to have any traces of anyone's data – not that it contains personal data. It's just that I want to make it as 'modular' as possible.
I guess deadlines do make one think of crazy things.
If you're thinking "Why not just spin up an AWS RDS instance or a Supabase project?", you'd be half-right. While they're fast to spin up, I'll have to bloat the site (which should be simple) with Supabase client library or even worse... ORMs.
That's when I remembered in an earlier project, plsgrade.me, I used Vercel KV to store some user-generated data. Moreover, it checked a lot of boxes. First being that it is fast to spin up, second is seamless integration with Next.js.
So that is exactly what I did. I spun up a Vercel KV storage (which then spins up an upstash instance – Redis) for me.
The only downside of this approach is that every time I need to write data, I'll have to store it in Redis in String and when fetched from the storage, I'll have to parse the JSON. Moreover, due to the nature of how I chose to create data entries, I would need to omit any apostrophes from the stringified JSON (i.e. "you're" -> "youre")
I wrote some test data, manually, to test if the application really shows up.
The first test
Image of the home page
What it looks like when accessing the page using the correct access code
Time to generate data for the rest of the people...
By now, graduation is about 1 week away, I was thinking of ways to improve the application. The first test data works... It shows up, I'm ecstatic.
Now, I'm writing each person's data into Vercel KV CLI.
But this task is proven to be a chore... For every person, I need to type out the data structure, change the name, content, url and then copy the key for the access code and paste in the value in the CLI format: SET <key> <value>
.
That's when I made my own script to help me generate data in a type-safe way and pretty-print, so that I can just copy and paste into the CLI: generateData.ts
.
And running the file would output these into the console, making it easier for me to bulk insert data into the CLI:
A – A ready-to-copy-and-paste text to paste into Vercel CLI
B – The URL for the QR Code
The essence of anticipation!
With about less than 7 days, I prepared everything – the goodie bags and the site – cleaning up messes, smoothing out rough edges.
One thing that was missing is the essence of anticipation – taking cues from other sites, some sites incite anticipation via countdowns. And that is what I did!
I created an if-check to check if the user's current date is before 6th of May, 6 p.m. (Graduation date)
Big Issue!
After deploying the test version, I realized that users are able to change their device's date and time to skip the countdown and display the hidden content.
So, how did I fix this? I knew that the problem lies in that the check for the time checks it against the user's date and time. I researched on ways to solve this and came down to the solution – instead of relying on the user's date and time, rely on the server's date and time.
I created an api at /api/time
Remember when I said SSR played a part? It does because when the component is rendered and sent to the client, no other code is being sent to the client. If you view the page source, you'll only see the code for the countdown but not the hidden content. SSR – 1, Hackers – 0.
Final touches
Okay, everything is done. From the access code, to the note, videos, images and the anticipation element. One final thing, which was REALLY not needed but somehow fun to do is the idea of access logging.
I would love to know when someone entered their access code and viewed their note.
I leveraged Redis, again, to store the data. Instead of using a simple GET and SET, I used LPUSH (List Push) which allows me to store items as part of an array. Retrieving it is as simple as using LRANGE.
Tada, it works!
Now, all I got to do is send to my friends the website and wait for the day to come.
Conclusion
The day came, and I think the site is well received:
What did I exactly learn?
Yeah, this seems like a simple job. There is no out-of-the-world technologies being implemented. But hey, every project has a lesson.
Countdown and it's nuances
Since it is my first time working with time, the issue of relying on user's date and time versus relying on the server's date and time is new to me. And I'm pretty sure I'll keep this in mind for future projects.
Using Redis
While learning how to use Redis, I also learned that Redis can be used for plethora of other things such as rate limiting. Isn't that interesting? This is something new to me, and I'll explore using Redis for my other projects. I know that you can use Redis as a complete data store but not recommended to. Maybe I'll explore data caching using Redis?
What was done right?
I feel that I am proud of how fast I got the project up-and-running. Considering some security measures implemented, which is overkill, would benefit other projects BUT there is no harm to me using what I've learned thus far into this small site.
What could've been done better?
Let's take a step back. If there was something that can be done better, it is to create a dedicated page for data creation rather than having to manually create data form the Vercel KV CLI.
Maybe this new page can interact with Imgur's and YouTube's API to handle uploading of assets rather than me having to manually upload the assets and copy the URL and ID.