<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Robbie Tambunting</title>
    <description>The latest articles on DEV Community by Robbie Tambunting (@rtambunt).</description>
    <link>https://dev.to/rtambunt</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1168111%2F98806f9f-8563-480a-a46d-bf1b6c86d9d3.JPEG</url>
      <title>DEV Community: Robbie Tambunting</title>
      <link>https://dev.to/rtambunt</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/rtambunt"/>
    <language>en</language>
    <item>
      <title>Beginner’s Guide 📘 to Using Supabase with Clerk</title>
      <dc:creator>Robbie Tambunting</dc:creator>
      <pubDate>Thu, 13 Mar 2025 23:49:51 +0000</pubDate>
      <link>https://dev.to/rtambunt/beginners-guide-to-using-supabase-with-clerk-4h6f</link>
      <guid>https://dev.to/rtambunt/beginners-guide-to-using-supabase-with-clerk-4h6f</guid>
      <description>&lt;p&gt;User authentication is crucial for any web app, and while securing it properly is essential, it can also be time-consuming. That's why, for my app &lt;strong&gt;WhereNow&lt;/strong&gt;, I chose &lt;strong&gt;Clerk&lt;/strong&gt; to handle the heavy lifting, paired with a &lt;strong&gt;Supabase&lt;/strong&gt; backend for a quick setup experience. But I ran into one challenge:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;I didn’t know how to integrate Clerk and Supabase together&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;Thankfully, I found a solution with the help of the official &lt;a href="https://www.youtube.com/watch?v=ICNulnfQvd8" rel="noopener noreferrer"&gt;Clerk YouTube tutorial&lt;/a&gt; and the &lt;a href="https://clerk.com/docs/integrations/databases/supabase" rel="noopener noreferrer"&gt;Clerk docs&lt;/a&gt;. While these resources provide helpful instructions, they ask you to run a few &lt;strong&gt;SQL queries&lt;/strong&gt;. If you're not familiar with PostgreSQL, it can be tricky to understand exactly what’s happening behind the scenes.&lt;/p&gt;

&lt;p&gt;The last thing you want is to apply code without fully understanding it. That’s why I’ve created this guide to break down those SQL queries step-by-step, helping you integrate Clerk and Supabase with confidence. Please pair this article with the video tutorial and documentation mentioned above.&lt;/p&gt;

&lt;p&gt;And with that, let’s get right into it.&lt;/p&gt;




&lt;h2&gt;
  
  
  Connecting to Clerk from Supabase using a DB Function
&lt;/h2&gt;

&lt;p&gt;To use Clerk and Supabase together effectively, we need to connect the two services. Fortunately, Clerk provides a &lt;strong&gt;DB function&lt;/strong&gt; that does exactly that.&lt;/p&gt;

&lt;p&gt;This function acts as the bridge between Clerk’s authentication system and Supabase’s database, ensuring that user data is properly synced and accessible within your app.&lt;/p&gt;

&lt;p&gt;Take at the function below, and let’s run through it line by line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;CREATE&lt;/span&gt; &lt;span class="nx"&gt;OR&lt;/span&gt; &lt;span class="nx"&gt;REPLACE&lt;/span&gt; &lt;span class="nx"&gt;FUNCTION&lt;/span&gt; &lt;span class="nf"&gt;requesting_user_id&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="nx"&gt;RETURNS&lt;/span&gt; &lt;span class="nx"&gt;TEXT&lt;/span&gt; &lt;span class="nx"&gt;AS&lt;/span&gt; &lt;span class="nx"&gt;$$&lt;/span&gt;
    &lt;span class="nx"&gt;SELECT&lt;/span&gt; &lt;span class="nc"&gt;NULLIF&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nf"&gt;current_setting&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;request.jwt.claims&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)::&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sub&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;''&lt;/span&gt;
    &lt;span class="p"&gt;)::&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;$$&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;CREATE OR REPLACE FUNCTION requesting_user_id()&lt;/code&gt;

&lt;ul&gt;
&lt;li&gt;Creates a new function called “requesting_user_id()”&lt;/li&gt;
&lt;li&gt;Overwrites the function if it already exists&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;
&lt;code&gt;RETURNS TEXT AS $$&lt;/code&gt;

&lt;ul&gt;
&lt;li&gt;Specifies the function will return a “TEXT” value&lt;/li&gt;
&lt;li&gt;$$ - Used to start SQL block quotes. Sometimes more readable alternative to single quotes ‘’&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;SELECT statement&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;SELECT&lt;/span&gt; &lt;span class="nc"&gt;NULLIF&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nf"&gt;current_setting&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;request.jwt.claims&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)::&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sub&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;''&lt;/span&gt;
&lt;span class="p"&gt;)::&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;NULLIF&lt;/code&gt; - Compares ‘sub’ and and empty string’’. If ‘sub’ is empty, ensures NULL is returned rather than an empty string&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;::text&lt;/code&gt;  - Type casts the result to TEXT to match how we are storing user_id’s in our Supabase tables&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;current_setting()&lt;/code&gt;  - A PostgreSQL function that retrieves the value of a config setting&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Refer to &lt;a href="https://www.postgresql.org/docs/current/functions-admin.html" rel="noopener noreferrer"&gt;PostgreSQL's documentation&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;'request.jwt.claims'&lt;/code&gt;  - A Supabase setting that holding the JWT payload for the database request&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;true&lt;/code&gt; - Ensure NULL is returned if the setting doesn’t exist instead of an error&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;code&gt;::json&lt;/code&gt;  - Converts the JWT to JSON format&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;code&gt;-&amp;gt;&amp;gt; 'sub'&lt;/code&gt;  - Gets the subject field from the JWT&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;sub&lt;/code&gt; is the unique identifier for the user, Clerk includes this in the JWT payload&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;code&gt;LANGUAGE SQL&lt;/code&gt;  - Specifies the function is in SQL&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;code&gt;STABLE&lt;/code&gt;  -  Indicates that the function’s output remains the same for the same input, unless the underlying data changes&lt;/p&gt;&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;The &lt;code&gt;requesting_user_id()&lt;/code&gt; function is an essential part of ensuring that your app’s authentication system works seamlessly between &lt;strong&gt;Clerk&lt;/strong&gt; and &lt;strong&gt;Supabase&lt;/strong&gt;. By extracting the &lt;code&gt;sub&lt;/code&gt; field from Clerk’s JWT and using it in Supabase, we ensure that each user’s unique identifier is correctly linked to their account in the database. Understanding how this function works is key to making sure authentication runs smoothly and securely. With this function in place, we can get into configuring our table Row Level Security policies&lt;/p&gt;




&lt;h2&gt;
  
  
  Configuring RLS in Supabase for Clerk
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Row Level Security (RLS) Policies&lt;/strong&gt; are used to define the rules for accessing or modifying a SQL table’s data. Without these restrictions, anyone could read, edit, or delete our stored sensitive data - which is a major privacy risk.&lt;/p&gt;

&lt;p&gt;We want to ensure that users can only access their own data when signed in. Thanks to the &lt;code&gt;requesting_user_id()&lt;/code&gt;function we created to check the Clerk authentication, setting up RLS policies becomes much easier.&lt;/p&gt;

&lt;p&gt;To restrict data access for authenticated users, we use a simple SQL check in our RLS policy to ensure that the current Clerk &lt;code&gt;user_id&lt;/code&gt; matches the &lt;code&gt;user_id&lt;/code&gt; in the Supabase table. This check prevents unauthorized users from accessing or modifying data.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="nf"&gt;requesting_user_id&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;user_id&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Clerk’s documentation lays out how to create your own RLS polcies pretty clearly. Please refer to Step 3 of the &lt;a href="https://clerk.com/docs/integrations/databases/supabase" rel="noopener noreferrer"&gt;docs tutorial&lt;/a&gt; to create some for your own project.&lt;/p&gt;

&lt;p&gt;Here is an query used in my app &lt;strong&gt;WhereNow&lt;/strong&gt; that creates an RLS policy for the &lt;code&gt;list_items&lt;/code&gt;  table&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;CREATE&lt;/span&gt; &lt;span class="nx"&gt;POLICY&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Select list_items policy&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; 
&lt;span class="nx"&gt;ON&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;public&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;list_items&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; 
&lt;span class="nx"&gt;AS&lt;/span&gt; &lt;span class="nx"&gt;PERMISSIVE&lt;/span&gt; 
&lt;span class="nx"&gt;FOR&lt;/span&gt; &lt;span class="nx"&gt;SELECT&lt;/span&gt; 
&lt;span class="nc"&gt;USING &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nc"&gt;EXISTS &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;SELECT&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; 
    &lt;span class="nx"&gt;FROM&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;public&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;lists&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; 
    &lt;span class="nx"&gt;WHERE&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;lists&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;list_items&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;list_id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="nx"&gt;AND&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;lists&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;user_id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;requesting_user_id&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This query does the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Creates a policy for the &lt;code&gt;list_items&lt;/code&gt; table&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;It applies to the &lt;code&gt;list_items&lt;/code&gt; table in the &lt;code&gt;public&lt;/code&gt; schema and defines how users can interact with it&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Defines the policy as "PERMISSIVE"&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;This means the policy allows access if the condition is met&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Applies the policy to &lt;code&gt;SELECT&lt;/code&gt; operations&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;This policy specifically affects &lt;code&gt;SELECT&lt;/code&gt; queries on the &lt;code&gt;list_items&lt;/code&gt; table

&lt;ul&gt;
&lt;li&gt;(Must create other policies for &lt;code&gt;UPDATE&lt;/code&gt; , &lt;code&gt;DELETE&lt;/code&gt; , and &lt;code&gt;INSERT&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Defines contraints for selecting rows&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;USING&lt;/code&gt; specifies conditions in which users are allowed to perform a &lt;code&gt;SELECT&lt;/code&gt; query on the &lt;code&gt;list_items&lt;/code&gt; table&lt;/li&gt;
&lt;li&gt;Two conditions:

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;list_id&lt;/code&gt; foreign key in the &lt;code&gt;list_items&lt;/code&gt; row must match a list in the &lt;code&gt;id&lt;/code&gt; of a list in the &lt;code&gt;lists&lt;/code&gt; table&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;user_id&lt;/code&gt; associated with that &lt;code&gt;list&lt;/code&gt; must match the &lt;strong&gt;&lt;code&gt;requesting_user_id()&lt;/code&gt;&lt;/strong&gt;, which is the ID of the currently authenticated user.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Ensures users can only access their own list items&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;By using the &lt;code&gt;requesting_user_id()&lt;/code&gt; function, the policy guarantees that users can only view &lt;code&gt;list_items&lt;/code&gt; associated with their own lists, ensuring privacy and data security&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;This query only applies to the &lt;code&gt;SELECT&lt;/code&gt; operation, but you can apply similar policies for other operations to further safeguard your table’s data.&lt;/p&gt;




&lt;h2&gt;
  
  
  Wrapping Up: Streamlining Authentication and Security with Clerk and Supabase
&lt;/h2&gt;

&lt;p&gt;In this post, we touched on how using &lt;strong&gt;Clerk&lt;/strong&gt; for user authentication with a &lt;strong&gt;Supabase&lt;/strong&gt; backend be both efficient and secure for your application. The main challenge was connecting these two services and understanding how to do so.&lt;/p&gt;

&lt;p&gt;We walked through the process of creating a custom &lt;strong&gt;DB function&lt;/strong&gt; that integrates Clerk’s JWT with Supabase to check that users are properly authenticated. Then, we implemented &lt;strong&gt;Row Level Security (RLS) policies&lt;/strong&gt; to restrict access to sensitive information, ensuring that each user can only access their own data.&lt;/p&gt;

&lt;p&gt;By understanding and implementing these steps, you can quickly set up a secure authentication system for your web application and focus more energy on building key features. Happy coding, and best of luck with your projects!&lt;/p&gt;

&lt;p&gt;If you have any questions or comments, feel free to reach out - I’m always open to learning something new or lending a helping hand!&lt;/p&gt;

</description>
      <category>clerk</category>
      <category>supabase</category>
      <category>beginners</category>
      <category>authentication</category>
    </item>
    <item>
      <title>Designing the Core Features of an App 🧑‍💻 : Building the MVP Step-by-Step</title>
      <dc:creator>Robbie Tambunting</dc:creator>
      <pubDate>Wed, 12 Mar 2025 06:21:26 +0000</pubDate>
      <link>https://dev.to/rtambunt/designing-the-core-features-of-an-app-building-the-mvp-step-by-step-48m1</link>
      <guid>https://dev.to/rtambunt/designing-the-core-features-of-an-app-building-the-mvp-step-by-step-48m1</guid>
      <description>&lt;p&gt;Building an app is exciting, but designing it to be functional and user-friendly can feel overwhelming - especially when you’re building from scratch. If you’ve ever struggled with structuring your project and don’t know where to start, continue reading on! This is my process, and I’ll break it down step-by-step as I go.&lt;/p&gt;

&lt;p&gt;(This is DevLog #3 for my hangout tracking app, &lt;em&gt;WhereNow&lt;/em&gt;. If you’d like to see how I planned the MVP and made intentional UI decisions for the app, checkout my previous blog posts)&lt;/p&gt;




&lt;h2&gt;
  
  
  tldr
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Integrated &lt;strong&gt;Clerk Auth&lt;/strong&gt; to rapidly build the MVP

&lt;ul&gt;
&lt;li&gt;May be expensive if the app scales considerably&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Focus on minimal UI for now (can always make UI prettier in the future)

&lt;ul&gt;
&lt;li&gt;Prioritize functionality&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Homepage Functionality

&lt;ul&gt;
&lt;li&gt;View and create lists&lt;/li&gt;
&lt;li&gt;View and create groups&lt;/li&gt;
&lt;li&gt;Page navigation not necessary right now (small MVP project scope)&lt;/li&gt;
&lt;li&gt;Search for lists and groups&lt;/li&gt;
&lt;li&gt;View profile&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Lists: Table View &amp;gt; Gallery view

&lt;ul&gt;
&lt;li&gt;No need to worry about bucket storage&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;List Page Functionality

&lt;ul&gt;
&lt;li&gt;Search list items&lt;/li&gt;
&lt;li&gt;Add/Delete list items&lt;/li&gt;
&lt;li&gt;Sort items by

&lt;ul&gt;
&lt;li&gt;Name (Alphabetical)&lt;/li&gt;
&lt;li&gt;City (Alphabetical)&lt;/li&gt;
&lt;li&gt;Date Created&lt;/li&gt;
&lt;li&gt;Date Completed (Future possibility)&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;AI list summaries&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;/ul&gt;




&lt;h2&gt;
  
  
  A Brief Note on Authentication
&lt;/h2&gt;

&lt;p&gt;While Supabase provides authentication, I’ve decided on using &lt;a href="https://clerk.com/" rel="noopener noreferrer"&gt;Clerk&lt;/a&gt; as my authentication provider for a few reasons:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Faster and simpler implementation.&lt;/li&gt;
&lt;li&gt;Seamless integration with Supabase.&lt;/li&gt;
&lt;li&gt;Likely to stay within the 10,000 Monthly Active Users (MAUs) free tier.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Clerk handles much of the heavy lifting, allowing me to focus on the app’s core functionality. It’s a great choice for the project right now; however, &lt;strong&gt;Clerk’s costs can become very expensive&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;I plan to offer a limited free tier, with a premium option to extend those limits. The challenge is that if WhereNow exceeds 10,000 MAUs, &lt;strong&gt;there’s no guarantee how many of those will convert to paying users&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It’s something to consider for the future, but for now, the priority is on building the product.&lt;/p&gt;

&lt;p&gt;With authentication in place, it’s time to tackle the next big step: designing the homepage. This is where users will interact with the core features of WhereNow, making it one of the most crucial parts of the app.&lt;/p&gt;




&lt;h2&gt;
  
  
  Designing the Homepage
&lt;/h2&gt;

&lt;p&gt;The homepage of WhereNow will serve as the place for users to interact with key features. Initially, the functionality will include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Viewing and creating lists&lt;/strong&gt;: Users will be able to create and view lists of places or events with their friends.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Viewing and creating groups&lt;/strong&gt;: Users can create and join groups to organize their lists and activities.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Search functionality&lt;/strong&gt;: Users will have the ability to search for existing lists and groups, making it easier to discover and join relevant ones.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Profile view&lt;/strong&gt;: Profile settings in the top-right will allow users to view and edit their personal details.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;(Figma Desktop Design)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsvl8ycpi8r1nci5wclzn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsvl8ycpi8r1nci5wclzn.png" alt="Figma Desktop Design of WhereNow Homepage" width="800" height="617"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;(Localhost Implementation)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3a60a85ydq0a5mmpf6rt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3a60a85ydq0a5mmpf6rt.png" alt="Localhost Implementation of WhereNow Homepage" width="800" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Given the limited scope of the MVP, page navigation is not a priority for now. We’ll keep the experience focused on the core features.&lt;/p&gt;




&lt;h2&gt;
  
  
  Lists and List Page Functionality
&lt;/h2&gt;

&lt;p&gt;For displaying lists, the initial view will be in a &lt;strong&gt;Table View&lt;/strong&gt;, but we’ll consider a &lt;strong&gt;Gallery View&lt;/strong&gt; in the future for a more visually-appealing experience. The Gallery View would be ideal for lists that include images, but since integrating image bucket storage adds complexity, the Table View will be the focus for the MVP.&lt;/p&gt;

&lt;p&gt;(Figma Desktop Design of List Page)&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdxs22rv837pwj3ba9k8k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdxs22rv837pwj3ba9k8k.png" alt="Image description" width="800" height="558"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;List Page&lt;/strong&gt; will offer several key functionalities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Search list items&lt;/strong&gt;: Users can easily search for items within a list.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Add and delete list items&lt;/strong&gt;: Users can manage the content of their lists by adding or removing items as needed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sorting options&lt;/strong&gt;: Users will be able to sort list items by:

&lt;ul&gt;
&lt;li&gt;Name (Alphabetically)&lt;/li&gt;
&lt;li&gt;City (Alphabetically)&lt;/li&gt;
&lt;li&gt;Date Created&lt;/li&gt;
&lt;li&gt;Date Completed (This feature may be added in the future)&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;AI-powered list summaries&lt;/strong&gt;: To enhance the user experience, AI will provide summaries of the list, offering quick insights into its contents.&lt;/li&gt;

&lt;/ul&gt;




&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;Designing &lt;em&gt;WhereNow’s&lt;/em&gt; MVP has been all about balancing functionality with simplicity. By integrating &lt;strong&gt;Clerk&lt;/strong&gt; for authentication, keeping the &lt;strong&gt;homepage streamlined&lt;/strong&gt;, and focusing on &lt;strong&gt;table-based list management&lt;/strong&gt;, we’ve set up a solid foundation for the app.&lt;/p&gt;

&lt;p&gt;Next up, we’ll be focusing on &lt;strong&gt;allowing users to use CRUD operations&lt;/strong&gt; to edit their lists.  Look out for the next dev log, where I’ll be utilizing Supabase and Clerk to achieve this.&lt;/p&gt;

&lt;p&gt;Have feedback or suggestions? Let me know—I’d love to hear your thoughts!&lt;/p&gt;

&lt;p&gt;(WhereNow Log 3)&lt;/p&gt;

</description>
      <category>design</category>
      <category>socialmedia</category>
      <category>learning</category>
      <category>frontend</category>
    </item>
    <item>
      <title>Building the Foundation: Designing an App’s UI 🎨 with Simplicity and Purpose</title>
      <dc:creator>Robbie Tambunting</dc:creator>
      <pubDate>Mon, 10 Mar 2025 20:00:39 +0000</pubDate>
      <link>https://dev.to/rtambunt/building-the-foundation-designing-an-apps-ui-with-simplicity-and-purpose-hho</link>
      <guid>https://dev.to/rtambunt/building-the-foundation-designing-an-apps-ui-with-simplicity-and-purpose-hho</guid>
      <description>&lt;p&gt;If you've ever felt that UI design for your project is daunting, don’t worry - it's more approachable than it seems. A great starting point is to focus on &lt;strong&gt;establishing a clear brand identity&lt;/strong&gt; by selecting an appropriate color palette and typography. For instance, choosing colors that evoke the desired emotions and fonts that align with your app's tone can significantly enhance user experience. &lt;/p&gt;

&lt;p&gt;In our journey with WhereNow, a friendship-centric social app, we began by focusing on these foundational elements. Let's walk through our design decisions to illustrate how thoughtful choices in color and typography can effectively convey an app's tone and purpose.&lt;/p&gt;




&lt;h2&gt;
  
  
  tldr
&lt;/h2&gt;

&lt;p&gt;If you’re in a rush, here’s a quick rundown of the app's design decisions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Color Palette:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Primary (Dark Blue #006EC7)&lt;/strong&gt; - changed from light blue (#64EDFF) to ensure accessible color contrast&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Light (Background #F7F7F7)&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Dark (Text #181818)&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Typography&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Quicksand font (Fontshare)&lt;/strong&gt; - rounded letters that convey warmth and approachability&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Type Scale (Golden Ratio)&lt;/strong&gt; - adequate sizing contrast between headings and body text&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Figma Design&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Start designing login + sign up page

&lt;ul&gt;
&lt;li&gt;Crucial feature of the app&lt;/li&gt;
&lt;li&gt;Ready to code once designed&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;/ul&gt;




&lt;h2&gt;
  
  
  Color Palette
&lt;/h2&gt;

&lt;p&gt;I began the design process by selecting the brand's color palette. Blue stood out as the primary choice, symbolizing calmness and trust—qualities essential to an app centered on friendship. Additionally, since our mascot is a harp seal, blue naturally complements the oceanic theme.&lt;/p&gt;

&lt;p&gt;Originally I wanted to go with a baby blue, but after doing some accessibility contrast checks to ensure readability and inclusivity, I decided to go with a darker blue hue.&lt;/p&gt;

&lt;p&gt;(Original Primary Color Choice)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3jc89qu6cu14zl7w3v3n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3jc89qu6cu14zl7w3v3n.png" alt="Contrast Checker for Baby Blue and Light Gray colors. Shows a 1.30 contrast score" width="800" height="482"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;(Final Primary Color Choice)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8ypxv65ty6dil0wph6ch.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8ypxv65ty6dil0wph6ch.png" alt="Contrast Checker for Baby Blue and Light Gray colors. Shows a 4.83 contrast score" width="800" height="485"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Typography
&lt;/h2&gt;

&lt;p&gt;For typography, the &lt;a href="https://fontshare.com/fonts/quicksand" rel="noopener noreferrer"&gt;&lt;strong&gt;Quicksand font from Fontshare&lt;/strong&gt;&lt;/a&gt; was chosen to give off a more casual, friendly look with its bubble letters and lack of sharp angles. This font gives the site a warm and approachable feel to it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frzv1g1eyimogrd7pcuy8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frzv1g1eyimogrd7pcuy8.png" alt="Quicksand font on Fontshare" width="800" height="375"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To establish a cohesive typographic hierarchy, I chose a golden ratio scale starting with a 16px base font size. Aesthetically, this scale looks great by providing harmonious contrast between headings and body text. However, one downside to the golden ratio is it causes heading sizes to increase rapidly, potentially leading to disproportionately large headings. To address this, I may switch to a different type scale in the future to maintain visual balance within the app’s design.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fedlhdrk4mgdr0nmw4vec.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fedlhdrk4mgdr0nmw4vec.png" alt="Golden ratio type scale on Typescale.com." width="800" height="446"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Designing User Authentication Pages
&lt;/h2&gt;

&lt;p&gt;With the foundation in place, it was time to boot up Figma and start designing the user login and sign-up pages. These pages are crucial for user retention and overall app function.&lt;/p&gt;

&lt;p&gt;Starting with them allows us to quickly transition into development. Incorporating best practices, such as offering alternative account sign-up options and avoiding the simultaneous use of 'sign in' and 'sign up' on the same screen, also enhances the user experience.&lt;/p&gt;

&lt;p&gt;It’s best to keep the design simple at this stage to focus on building the core functionality before introducing any creative complexity.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5h3e9m44xrmx0cltbv8j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5h3e9m44xrmx0cltbv8j.png" alt="Figma desktop design of sign-in and sign-up pages." width="800" height="314"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Conclusion&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Establishing a thoughtful design foundation is essential in creating an app that resonates with users. By carefully selecting colors and typography that reflect the app's brand and implementing user-centric design practices, we aim to deliver an intuitive and engaging experience. As we progress into the development phase, these design choices will guide the creation of a platform that embodies the spirit of WhereNow.&lt;/p&gt;

&lt;p&gt;What is your approach to product design? Comment down below!&lt;/p&gt;

&lt;p&gt;(WhereNow Log 2)&lt;/p&gt;

</description>
      <category>design</category>
      <category>ui</category>
      <category>frontend</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Designing Your Go-To Friend Hangout Organizer 👥 - Starting ‘WhereNow’ 📍</title>
      <dc:creator>Robbie Tambunting</dc:creator>
      <pubDate>Sat, 08 Mar 2025 18:36:04 +0000</pubDate>
      <link>https://dev.to/rtambunt/designing-your-go-to-friend-hangout-organizer-starting-wherenow-4bao</link>
      <guid>https://dev.to/rtambunt/designing-your-go-to-friend-hangout-organizer-starting-wherenow-4bao</guid>
      <description>&lt;h2&gt;
  
  
  An App to Track Hangouts with Friends
&lt;/h2&gt;

&lt;p&gt;Keeping track of new restaurants and activities to do shouldn’t feel like navigating a cluttered mess on your notes app. Yet, that’s exactly the situation my friends and I were in -  lost in a disorganized list within the Apple Notes app unable to really decide which place to try next. In order to transform this experience, I’m developing “WhereNow” - an app designed to bring order, excitement, and visual appeal to the experience of planning a hangout.&lt;/p&gt;

&lt;p&gt;I’ll walk through the journey of developing this project, starting with developing a MVP and selecting the right tech stack. We’ll then touch on modeling our tables to define a clear structure on how the app works. &lt;/p&gt;

&lt;p&gt;Alright, let’s get started.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Minimum Viable Product
&lt;/h2&gt;

&lt;p&gt;While there’s a lot of potential for incorporating advanced AI features, the initial goal is to quickly develop a product that my friends and I can use right away. This approach allows for quick feedback and iterative improvements. The core features of the Minimum Viable Product (MVP) will include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;User Authentication&lt;/strong&gt;: Secure login and signup functionalities to manage user profiles&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Personal Lists&lt;/strong&gt;: Ability to create and manage individual lists of places and activities&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Group Collaboration&lt;/strong&gt;: Option to create shared lists with friends within specific groups&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Review System&lt;/strong&gt;: Functionality to add reviews for list items and view reviews from group members&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI-Powered Summaries&lt;/strong&gt;: AI-generated summaries of list items to assist in decision-making and offer a more playful experience&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The aim is to quickly launch a usable product, gather user feedback, and make improvements - adding features once these core functionality are nailed down.&lt;/p&gt;




&lt;h2&gt;
  
  
  Tech Stack Selection
&lt;/h2&gt;

&lt;p&gt;WhereNow will initially launch as a browser application. While developing a mobile app makes the most sense, my expertise lies in building web products. This approach allows me to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Rapidly create an MVP with my existing skills &lt;/li&gt;
&lt;li&gt;Assess user interest in the product&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To ensure a secure and efficient development process, I have chosen the following technologies:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Supabase:&lt;/strong&gt; Provides backend services and a SQL database, including authentication and simplified database table creation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Next.js&lt;/strong&gt;: Enhances frontend performance with features like lazy-loaded images and server-side rendering.

&lt;ul&gt;
&lt;li&gt;Will allow the development of a dynamic product landing page with Framer Motion animations&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Clerk (Optional)&lt;/strong&gt;: Offers an affordable authentication services with quick integration options (Google, Twitter, etc.)&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Claude AI&lt;/strong&gt;: An advanced AI language model known for its safety and performance&lt;/li&gt;

&lt;/ul&gt;




&lt;h2&gt;
  
  
  Modeling Tables
&lt;/h2&gt;

&lt;p&gt;Designing the database schema is important for ensuring efficient data manipulation and providing insight into the apps functionality. Below is an overview of the proposed tables for WhereNow:&lt;/p&gt;

&lt;h3&gt;
  
  
  Table Name: users
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Description:&lt;/strong&gt; Stores info about registered users&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fields:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;id&lt;/code&gt; (Primary Key, Required): Unique identifier for each user&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;name&lt;/code&gt; (Required): name or nickname of the user&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;email&lt;/code&gt; (Unique, Required): Email address of the user&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Table Name: groups
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Description:&lt;/strong&gt; Stores information about user groups.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fields:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;id&lt;/code&gt; (Primary Key, Required): Unique identifier for each group&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;name&lt;/code&gt; (Required): Name of the group.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Table Name: group_members
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Description:&lt;/strong&gt; Associates users with groups, establishing a many-to-many relationship&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fields:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;user_id&lt;/code&gt;  ((Foreign Key to &lt;code&gt;users.id&lt;/code&gt;, Required)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;group_id&lt;/code&gt;  (Foreign Key to &lt;code&gt;groups.id&lt;/code&gt;, Required)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Table Name: lists
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Description:&lt;/strong&gt; Stores lists that users create for themselves or for their groups&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fields:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;id&lt;/code&gt; (Primary Key, Required): Unique identifier for each list&lt;/li&gt;
&lt;li&gt;name (Required)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;user_id&lt;/code&gt; (Foreign Key to &lt;code&gt;users.id&lt;/code&gt;, Required)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;group_id&lt;/code&gt;  (Foreign Key to &lt;code&gt;groups.id&lt;/code&gt;, Required)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Table Name: list_items
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Description:&lt;/strong&gt; Stores items within created lists&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fields:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;id&lt;/code&gt; (Primary Key, Required): Unique identifier for each item&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;list_id&lt;/code&gt; (Foreign Key to &lt;code&gt;lists.id&lt;/code&gt;, Required)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;name&lt;/code&gt; (Required): Name or title of the item.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;city&lt;/code&gt; (Optional): City where the item (e.g., restaurant) is located.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;completed&lt;/code&gt; (Boolean, Default: &lt;code&gt;false&lt;/code&gt;, Required): Status indicating if the item has been visited or completed&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Table Name: reviews
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Description:&lt;/strong&gt; Stores user reviews for list items.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fields:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;id&lt;/code&gt; (Primary Key, Required): Unique identifier for each review&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;list_item_id&lt;/code&gt; (Foreign Key to &lt;code&gt;list_items.id&lt;/code&gt;, Required)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;user_id&lt;/code&gt; (Foreign Key to &lt;code&gt;users.id&lt;/code&gt;, Required): Identifier linking to the reviewer&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;rating&lt;/code&gt; (Integer, Required): Rating given to the item (e.g., 1-5 stars).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  - &lt;code&gt;comment&lt;/code&gt; (Text): Optional textual feedback
&lt;/h2&gt;

&lt;h2&gt;
  
  
  Table Relationships
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tables&lt;/th&gt;
&lt;th&gt;Relationship&lt;/th&gt;
&lt;th&gt;Reason&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;users ↔ groups&lt;/td&gt;
&lt;td&gt;many:many&lt;/td&gt;
&lt;td&gt;Users can be part of many groups. Groups can contain many users&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;users → lists&lt;/td&gt;
&lt;td&gt;one:many&lt;/td&gt;
&lt;td&gt;Each list can only have one “creator”&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;groups → lists&lt;/td&gt;
&lt;td&gt;one:many&lt;/td&gt;
&lt;td&gt;Groups can have many lists, but each list must be associated with one group only&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;lists → list_items&lt;/td&gt;
&lt;td&gt;one:many&lt;/td&gt;
&lt;td&gt;List Items are associated with one list&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;list_items → reviews&lt;/td&gt;
&lt;td&gt;one:many&lt;/td&gt;
&lt;td&gt;Reviews are associated with one list item, but list items can have multiple reviews&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;user → reviews&lt;/td&gt;
&lt;td&gt;one:many&lt;/td&gt;
&lt;td&gt;Reviews are associated to only one user&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;With the project's foundation established and the backend implemented on Supabase, we can turn our attention to designing the product's user interface. The design will significantly influence the frontend development, so let's dive into Figma to brainstorm! &lt;/p&gt;

&lt;p&gt;Thoughts or suggestions? Please comment down below! Your feedback is invaluable to making WhereNow a tool that meets your needs.&lt;/p&gt;

&lt;p&gt;(WhereNow Log 1)&lt;/p&gt;

</description>
      <category>fullstack</category>
      <category>appdev</category>
      <category>mvp</category>
      <category>socialmedia</category>
    </item>
    <item>
      <title>Master Type-Safe Object Keys with TypeScript keyof typeof</title>
      <dc:creator>Robbie Tambunting</dc:creator>
      <pubDate>Wed, 08 Jan 2025 06:20:51 +0000</pubDate>
      <link>https://dev.to/rtambunt/master-type-safe-object-keys-with-typescript-keyof-typeof-47i3</link>
      <guid>https://dev.to/rtambunt/master-type-safe-object-keys-with-typescript-keyof-typeof-47i3</guid>
      <description>&lt;h2&gt;
  
  
  Intro
&lt;/h2&gt;

&lt;p&gt;Ensuring type safety with TypeScript is essential when accessing object properties within your application. &lt;strong&gt;One powerful yet overlooked feature that can simplify this process is the &lt;code&gt;keyof typeof&lt;/code&gt; construct&lt;/strong&gt;. This simple trick leverages the &lt;code&gt;keyof&lt;/code&gt; and &lt;code&gt;typeof&lt;/code&gt; operator to infer the key types of an object at runtime. As a result, it helps you write &lt;strong&gt;safer&lt;/strong&gt;, &lt;strong&gt;more maintainable code&lt;/strong&gt; and reduces the risk of passing invalid property names.  &lt;/p&gt;




&lt;h2&gt;
  
  
  What is &lt;code&gt;keyof&lt;/code&gt;?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;keyof&lt;/code&gt; is a TypeScript operator used to return the union type of keys from an object type&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;In the following example, the &lt;code&gt;keyof&lt;/code&gt; operator lets us define constraints on which property names can be passed into our function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Document&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;string,&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="na"&gt;author&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;DocumentKeys&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;keyof&lt;/span&gt; &lt;span class="nx"&gt;Document&lt;/span&gt; &lt;span class="c1"&gt;// returns "id" | "title" | "author"&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;myDocument&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;Untitled Document&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="na"&gt;author&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Robbie&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getMyDocumentProperty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;DocumentKeys&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;myDocument&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt; &lt;span class="c1"&gt;// key must be either "id", "title", or "author"&lt;/span&gt;
                                                    &lt;span class="c1"&gt;// thanks to keyof, no other property name is allowed&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;TypeScript will throw an error if &lt;code&gt;key&lt;/code&gt; is anything other than "id", "title", or "author".&lt;/p&gt;




&lt;h2&gt;
  
  
  What is &lt;code&gt;typeof&lt;/code&gt;?
&lt;/h2&gt;

&lt;p&gt;In TypeScript, &lt;strong&gt;the &lt;code&gt;typeof&lt;/code&gt; operator returns the type value of the variable, object, or function that follows it.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We can use typeof to automatically infer the type of an object without manually defining it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Untitled Document&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;author&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Robbie&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Document&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// { id: number, title: string, author: string }&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Combining &lt;code&gt;keyof typeof&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Combining the two operators allows us to dynamically extract an object's keys in a type-safe manner. But when would we need this in practice? &lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;Consider the following scenario:&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;&lt;strong&gt;You have predefined an object with key-value pairs, such as a configuration object&lt;/strong&gt;&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&lt;strong&gt;You are building a React component, and one of its &lt;code&gt;props&lt;/code&gt; must correspond to a key in this predefined object&lt;/strong&gt;&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is where combining &lt;code&gt;keyof&lt;/code&gt; and &lt;code&gt;typeof&lt;/code&gt; really shines.&lt;/p&gt;

&lt;p&gt;Instead of manually defining the object keys as a union type — which can lead to errors if keys change — &lt;strong&gt;you can use &lt;code&gt;keyof typeof&lt;/code&gt; to derive the keys directly from the object.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Here’s an example where I leveraged this technique in one of my reusable UI components:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// --- Button.tsx ---&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;ButtonProps&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;twStyles&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;keyof&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;colors&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;colors&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;primary&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;transition-2s hover-translate-y rounded-lg border-2 border-[#004A7C] bg-[#004A7C] px-4 py-2 text-white hover:border-[#31678c] hover:font-semibold hover:bg-[#31678c]&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;secondary&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;transition-2s hover-translate-y rounded-lg border-2 border-[#004A7C] bg-gray-50 px-4 py-2 text-[#004A7C]  hover:font-semibold hover:bg-[#eaf3ff]&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;twStyles&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;color&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;primary&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;ButtonProps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;colorStyles&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;colors&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;color&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;
      &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;twStyles&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;colorStyles&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; rounded-lg border-2 px-4 py-2`&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, &lt;strong&gt;&lt;code&gt;keyof typeof&lt;/code&gt; ensures the &lt;code&gt;color&lt;/code&gt; prop is restricted to valid keys of the &lt;code&gt;colors&lt;/code&gt; object.&lt;/strong&gt; If &lt;code&gt;colors&lt;/code&gt; is updated, its type automatically reflects the changes, reducing the risk of bugs.&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;There you have it! Understanding the &lt;code&gt;keyof typeof&lt;/code&gt; combo in TypeScript allows you to create type-safe, maintainable code that adapts to changes in your objects. &lt;strong&gt;This approach eliminates redundant type definitions and reduces the chance of errors, making it a valuable tool for any TypeScript developer.&lt;/strong&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;What did you think?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;I’d love to hear your thoughts! Have you ever used this technique? If so, how?  Share your feedback in the comments below!&lt;/em&gt;&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>react</category>
      <category>webdev</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Create a Time-Saving Template 🧩 with React, Vite, and Tailwind CSS</title>
      <dc:creator>Robbie Tambunting</dc:creator>
      <pubDate>Sat, 14 Dec 2024 22:35:38 +0000</pubDate>
      <link>https://dev.to/rtambunt/create-a-time-saving-template-with-react-vite-and-tailwind-css-3p3h</link>
      <guid>https://dev.to/rtambunt/create-a-time-saving-template-with-react-vite-and-tailwind-css-3p3h</guid>
      <description>&lt;h2&gt;
  
  
  Why You Should Create a Template
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Creating new React projects can be both time-consuming and redundant&lt;/strong&gt;. In this guide, I’ll show you how to set up a reusable React template with Vite and Tailwind CSS. This approach allows you to skip the initial set-up process and jump straight into development for future projects.&lt;/p&gt;

&lt;p&gt;If you’re looking for a quick start, &lt;strong&gt;I’ve created a ready-to-use template on GitLab &lt;a href="https://gitlab.com/rtambunt/react-vite-template" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/strong&gt;. Just clone it to your machine, and you’ll be up and running.&lt;/p&gt;

&lt;p&gt;Now, let’s get started by setting up a remote repository.&lt;/p&gt;




&lt;p&gt;&lt;a id="setup-repo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting Up a Remote Repository
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Sign In to the Version Control Platform of Your Choice&lt;/strong&gt; - I’ll be using GitLab, but any other choice works&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Create a New Project&lt;/strong&gt; - In GitLab, this can be done by clicking the “+” icon on the upper left corner by your profile picture

&lt;ul&gt;
&lt;li&gt;Select “Create blank project”&lt;/li&gt;
&lt;li&gt;Choose a project name, slug, + privacy level&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Hit the “Create Project” Button&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Under the Blue “Code” Button, copy the “Clone with HTTPS” link&lt;/strong&gt; - We’ll need this soon, so just hold onto it&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;And you’re all set! Now your template will be automatically linked to this remote repo when you clone it.&lt;/p&gt;




&lt;p&gt;&lt;a id="initialize"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Initializing the Template
&lt;/h2&gt;

&lt;p&gt;Let’s explore the first steps to creating your template&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Navigate to the Folder Where You Want to Store the Template:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Open your terminal&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Change into your desired directory&lt;/p&gt;

&lt;p&gt;e.g. &lt;code&gt;cd my-projects&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Clone Your Template:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Replace  with the one you copied in the previous section&lt;/li&gt;
&lt;li&gt;Change into your new template’s directory
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;git&lt;/span&gt; &lt;span class="nx"&gt;clone&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Remote&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;Clone&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;Link&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nx"&gt;cd&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;template&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Initialize a Vite Project:&lt;/strong&gt; &lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Use “.” after &lt;code&gt;vite@latest&lt;/code&gt; to prevent Vite from creating an extra folder inside the cloned git repo&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;npm&lt;/span&gt; &lt;span class="nx"&gt;create&lt;/span&gt; &lt;span class="nx"&gt;vite&lt;/span&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;latest&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Select “React” and “TypeScript” when Vite prompts you for project options&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;💡 Note: At this point, I like to remove a lot of the default Vite files + assets&lt;/strong&gt;&lt;/p&gt;




&lt;p&gt;&lt;a id="packages"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Installing Packages
&lt;/h2&gt;

&lt;p&gt;Feel free to customize this section. Here’s my preferred package combination:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;tailwindcss&lt;/strong&gt; - a utility-first CSS framework&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;postcss&lt;/strong&gt; - process and optimizes CSS files&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;autoprefixer&lt;/strong&gt; - adds prefixes to ensure CSS compatibility across all browsers&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;prettier&lt;/strong&gt; - auto formats your code to improve readability&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;prettier-plugin-tailwindcss&lt;/strong&gt; - ensures consisten Tailwind class formatting (personal favorite)
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;npm&lt;/span&gt; &lt;span class="nx"&gt;install&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;D&lt;/span&gt; &lt;span class="nx"&gt;tailwindcss&lt;/span&gt; &lt;span class="nx"&gt;postcss&lt;/span&gt; &lt;span class="nx"&gt;autoprefixer&lt;/span&gt; &lt;span class="nx"&gt;prettier&lt;/span&gt; &lt;span class="nx"&gt;prettier&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;plugin&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;tailwindcss&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;&lt;a id="config"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Configuring Tailwind and Prettier
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;tailwind.config.js&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;content:&lt;/strong&gt; specifies which file types should use Tailwind classes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;theme.extend:&lt;/strong&gt; allows you to create custom classes
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// -- tailwind.config.js --&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./index.html&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./src/**/*.{js,ts,jsx,tsx}&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;extend&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{},&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;index.css&lt;/strong&gt; - imports Tailwind’s base styles, components, and utility classes
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// -- index.css --&lt;/span&gt;
&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;tailwind&lt;/span&gt; &lt;span class="nx"&gt;base&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;tailwind&lt;/span&gt; &lt;span class="nx"&gt;components&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;tailwind&lt;/span&gt; &lt;span class="nx"&gt;utilities&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;.prettierrc&lt;/strong&gt; - allows Prettier to format Tailwind classes
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// -- .prettierrc&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;plugins&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;prettier-plugin-tailwindcss&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;&lt;a id="commit"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Committing and Pushing to the Remote Repo
&lt;/h2&gt;

&lt;p&gt;You’re almost finished! To make this truly reusable, we need to save our changes to our remote repo&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;git&lt;/span&gt; &lt;span class="nx"&gt;add&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="nx"&gt;git&lt;/span&gt; &lt;span class="nx"&gt;commit&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Finish react template&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="nx"&gt;git&lt;/span&gt; &lt;span class="nx"&gt;push&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;&lt;a id="notes"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Notes
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Update Packages Regularly&lt;/strong&gt; - Always check in on your project to ensure packages aren’t deprecated and that updates don’t break your project&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Remove the .git File When Cloning&lt;/strong&gt; - This ensures that your changes to your new project don’t affect the template’s remote repo&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;a id="conclusion"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Congratulations, by creating a React project template, you’ve significantly streamlined the setup process, saving yourself valuable time. Now, you can focus on actually building out your application and bringing your idea to life. &lt;/p&gt;

&lt;p&gt;What did you think? I’m always open to feedback and suggestions, so feel free to share your thoughts or ask questions!&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>tutorial</category>
      <category>webdev</category>
      <category>react</category>
    </item>
    <item>
      <title>Why I’m Building a Realtime Collaboration App (DocuMe Devlog 1)</title>
      <dc:creator>Robbie Tambunting</dc:creator>
      <pubDate>Tue, 03 Dec 2024 21:57:33 +0000</pubDate>
      <link>https://dev.to/rtambunt/why-im-building-a-realtime-collaboration-app-docume-devlog-1-3bek</link>
      <guid>https://dev.to/rtambunt/why-im-building-a-realtime-collaboration-app-docume-devlog-1-3bek</guid>
      <description>&lt;h2&gt;
  
  
  Intro
&lt;/h2&gt;

&lt;p&gt;So I’m on a mission to refine my software engineering skills by building practical projects that present a new challenge each time.&lt;/p&gt;

&lt;p&gt;I recently built out my first full-stack application called &lt;a href="https://gitlab.com/rtambunt/on-the-rocks" rel="noopener noreferrer"&gt;On the Rocks&lt;/a&gt; which taught me the basics of integrating a frontend, backend, database, and cloud hosting service. While I’m very proud of it, I know that this is just the beginning. There is so much more to learn.&lt;/p&gt;

&lt;p&gt;This brings me to my next project: a real-time collaboration app like Google Docs.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Idea: Why a Realtime Collaboration App?
&lt;/h2&gt;

&lt;p&gt;As companies turn to remote or hybrid work models, collaboration tools like Google Suite and Microsoft 365 have become a necessity. These tools enable efficient teamwork by providing easy accessibility to files and instantly visible updates.&lt;br&gt;
&lt;br&gt;&lt;br&gt;
&lt;strong&gt;The Goal: To build a real-time document collaboration app and master concepts that can be applied to other projects&lt;/strong&gt;&lt;br&gt;
&lt;br&gt;&lt;br&gt;
I won’t reinvent the wheel here, but this project will be a great opportunity to challenge myself and grow as a developer.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Features
&lt;/h2&gt;

&lt;p&gt;Full-stack apps like to-do lists and recipe trackers really only require the implementation of CRUD operations to have full user functionality.&lt;/p&gt;

&lt;p&gt;Building a real-time app requires us to stretch our skills beyond the basics and tackle the following features:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Live Updates&lt;/strong&gt; - Synchronizing updates across multiple clients requires use of WebSockets&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rich Text Editing&lt;/strong&gt; - For documents to be easily styled by the user and formatted for storing in the database, a feature-rich editor like Quill is required&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Handling Concurrent Edits&lt;/strong&gt; - I’ll have to do more research on this, but the app needs a way to handle document edits happening at the same time and manipulating the same data&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Version History (Stretch Goal)&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In addition, I am excited to learn:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;AWS Web Service Hosting&lt;/strong&gt; - Easily scalable with different tiers suited for the app's required needs&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Google Oauth&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  The First Steps: A High-Level Overview
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Frontend Framework:&lt;/strong&gt;

&lt;ol&gt;
&lt;li&gt;React for the user interface&lt;/li&gt;
&lt;li&gt;Tailwind CSS for fast, responsive design&lt;/li&gt;
&lt;li&gt;TypeScript for type checking and debugging&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Backend:&lt;/strong&gt;

&lt;ol&gt;
&lt;li&gt;Node.js&lt;/li&gt;
&lt;li&gt;Express&lt;/li&gt;
&lt;li&gt;MongoDB&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;li&gt;&lt;strong&gt;Quill Rich Text Editor&lt;/strong&gt;&lt;/li&gt;

&lt;li&gt;&lt;strong&gt;Websockets for Real-time Communication&lt;/strong&gt;&lt;/li&gt;

&lt;li&gt;&lt;strong&gt;Google Oauth&lt;/strong&gt;&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Deployment:&lt;/strong&gt;

&lt;ol&gt;
&lt;li&gt;Vercel (Frontend)&lt;/li&gt;
&lt;li&gt;AWS (Backend)&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;/ol&gt;

&lt;p&gt;I’ll possibly explore Redis for database caching and scaling preparation.&lt;/p&gt;




&lt;h2&gt;
  
  
  Looking Ahead
&lt;/h2&gt;

&lt;p&gt;That’s the app so far! Over the coming weeks, I’ll tackle features like Quill integration, Google Oauth implementation, and real-time collaboration to realize this vision. I’ll document the challenges I face and share solutions that could help others working on similar projects.&lt;/p&gt;

&lt;p&gt;Stay tuned for the next dev log, where I’ll discuss how I designed the app's frontend and backend architecture!&lt;/p&gt;




&lt;h2&gt;
  
  
  What do you think?
&lt;/h2&gt;

&lt;p&gt;I’d love to hear your thoughts or share your experiences building real-time apps. Share your feedback in the comments or connect with me on LinkedIn!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>node</category>
      <category>react</category>
      <category>design</category>
    </item>
    <item>
      <title>C++ Programming Lecture 1</title>
      <dc:creator>Robbie Tambunting</dc:creator>
      <pubDate>Tue, 20 Aug 2024 04:40:29 +0000</pubDate>
      <link>https://dev.to/rtambunt/c-programming-lecture-1-3gki</link>
      <guid>https://dev.to/rtambunt/c-programming-lecture-1-3gki</guid>
      <description>&lt;h2&gt;
  
  
  Why C++?
&lt;/h2&gt;

&lt;p&gt;I'm on my journey to pursuing my Master's in CS! Along with taking the GRE and obtaining letters of rec, I also must take a handful of prerequisites that my Computational Mathematics major didn't include. &lt;/p&gt;

&lt;p&gt;Today marked the start of my C++ Programming course. So why are we learning C++ instead of let’s say Python or Java? While this question wasn’t answered in my first lecture, I would like to highlight a few points:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;C++ is more similar to C and requires manual memory management. &lt;/li&gt;
&lt;li&gt;C++ supports Object Oriented Programming (OOP)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Since both Python and Java support OOP, I’d imagine that the main selling point is C++’s low-level programming capabilities. Higher-level languages abstract memory management, so C++ forces us to efficiently manage it ourselves. &lt;/p&gt;

&lt;p&gt;Side-note: It’s really convenient that most C code can also be run as a C++ program.&lt;/p&gt;

&lt;p&gt;Now back to my class activities.&lt;/p&gt;

&lt;h2&gt;
  
  
  Components of a C++ Program
&lt;/h2&gt;

&lt;p&gt;We took a look at a particular code segment and were introduced to the basic components of a C++ program. Afterward, we were asked to make a few edits for an in-class assignment. &lt;/p&gt;

&lt;p&gt;The following code snippet is as follows&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;iostream&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;totalInches&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;totalFeet&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;totalMiles&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;remainingFeet&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;remainingInches&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;"Please enter the total number of inches: "&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="n"&gt;cin&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;totalInches&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


    &lt;span class="n"&gt;totalFeet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;totalInches&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;totalMiles&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;totalFeet&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;5280&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;remainingFeet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;totalFeet&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;5280&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;remainingInches&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;totalInches&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;totalInches&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;" inch(es) is equal to "&lt;/span&gt;
         &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;totalMiles&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;"mile(s),"&lt;/span&gt;
         &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;remainingFeet&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;" feet and "&lt;/span&gt;
         &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;remainingInches&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;" inch(es)."&lt;/span&gt;
         &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;endl&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;"Bye Now!"&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let’s break down each unfamiliar keyword and operator.&lt;/p&gt;

&lt;h3&gt;
  
  
  General
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;#include&lt;/strong&gt; - a directive that tells the compiler to include contents of a specified file. The preprocessor replaces the line with #includes with the actual code located in the header file&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;header file&lt;/strong&gt; - any file that contains C-language functions. May be included in other existing C files&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;namespace&lt;/strong&gt; - an area that defines the scope of all things (functions + variables) inside it. It’s much like adding curly braces {} around a whole region of code and calling it a name.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;int main()&lt;/strong&gt; - defines our main program that all other functions are called from

&lt;ul&gt;
&lt;li&gt;Standard practice is to specify an int return value and to return 0 on finish&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  IoStream + std
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;std&lt;/strong&gt; - namespace for the C++ standard library that holds many useful classes and functions

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;cout&lt;/strong&gt; - used to print characters to the console. stands for “character output”. part of std&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;cin&lt;/strong&gt; - used to get input from the user. stands for “character input”. part of std&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;endl&lt;/strong&gt; - used to print a newline “\n” to the console and flushes the output buffer (AKA all data is written to the output device in that instant)&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;“using namespace std;”&lt;/strong&gt; - allows us to define things like cout without having to write the full std::cout statement&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;iostream&lt;/strong&gt; - a file that includes functions that allow for input and output operations using streams (streams - flow of data in or out of a program)

&lt;ul&gt;
&lt;li&gt;printing to the console&lt;/li&gt;
&lt;li&gt;printing an error message&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;&amp;lt;&amp;lt;&lt;/strong&gt; &lt;strong&gt;operator&lt;/strong&gt; - used for outputting data onto the stream. Usually used to push data into the &lt;strong&gt;cout&lt;/strong&gt; output stream&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;&amp;gt;&amp;gt; operator&lt;/strong&gt; - used for getting input data from the stream. Usually used to pull user inputted data from the stream into a variable via &lt;strong&gt;cin&lt;/strong&gt;
&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;And that’s all for the first day! I’m looking forward to furthering my understanding of computer programs as this course progresses&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Valid Parentheses (Leetcode 20)</title>
      <dc:creator>Robbie Tambunting</dc:creator>
      <pubDate>Sat, 20 Jul 2024 19:48:21 +0000</pubDate>
      <link>https://dev.to/rtambunt/valid-parentheses-leetcode-20-3p40</link>
      <guid>https://dev.to/rtambunt/valid-parentheses-leetcode-20-3p40</guid>
      <description>&lt;p&gt;I’m on a quest to improve my interview skills and general knowledge of Software Engineering as a whole. What better way to do so than to do coding challenges on Leetcode! &lt;/p&gt;

&lt;p&gt;I’ll be honest Leetcode isn’t my strong point, but that’s all the more reason to get better. Each of these will be solved using my own implementation in JavaScript, and they will include a detailed walkthrough of my process.&lt;/p&gt;

&lt;p&gt;So join me on this journey as I work my way through Neetcode’s 150 and more!&lt;/p&gt;

&lt;p&gt;The first problem I will be tackling is valid parentheses:&lt;/p&gt;

&lt;h2&gt;
  
  
  Valid Parentheses
&lt;/h2&gt;

&lt;p&gt;You are given a string &lt;code&gt;s&lt;/code&gt; consisting of the following characters: &lt;code&gt;'('&lt;/code&gt;, &lt;code&gt;')'&lt;/code&gt;, &lt;code&gt;'{'&lt;/code&gt;, &lt;code&gt;'}'&lt;/code&gt;, &lt;code&gt;'['&lt;/code&gt; and &lt;code&gt;']'&lt;/code&gt;.**&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The input string &lt;code&gt;s&lt;/code&gt; is valid if and only if:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Every open bracket is closed by the same type of close bracket. Open brackets are closed in the correct order.Every close bracket has a corresponding open bracket of the same type.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Return &lt;code&gt;true&lt;/code&gt; if &lt;code&gt;s&lt;/code&gt; is a valid string, and &lt;code&gt;false&lt;/code&gt; otherwise.&lt;/strong&gt;&lt;/p&gt;



&lt;p&gt;Problem Link: &lt;a href="https://neetcode.io/problems/validate-parentheses" rel="noopener noreferrer"&gt;https://neetcode.io/problems/validate-parentheses&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  My Solution
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Space Complexity: O(n)&lt;/strong&gt; &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Stack of max length n&lt;/li&gt;
&lt;li&gt;Hashmap&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Time Complexity: O(n)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Must iterate through n chars of string s&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Pseudo-code Steps
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Define a hashmap containing closing brackets and their opening counterparts&lt;/li&gt;
&lt;li&gt;Define a stack that will hold all of our opening parentheses in the order they appear&lt;/li&gt;
&lt;li&gt;Iterate through string s

&lt;ol&gt;
&lt;li&gt;if the current char is an opening bracket: add it to our stack&lt;/li&gt;
&lt;li&gt;else it is a closing bracket: see if it’s corresponding opening bracket is the last element in the stack

&lt;ol&gt;
&lt;li&gt;if so, else pop from stack&lt;/li&gt;
&lt;li&gt;else the corresponding opening bracket isn’t the last element in the stack, return false (invalid parentheses)&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;/ol&gt;

&lt;/li&gt;

&lt;li&gt;Return stack === 0 (boolean value) &lt;/li&gt;

&lt;/ol&gt;

&lt;h3&gt;
  
  
  Code
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Solution&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cm"&gt;/**
     * @param {string} s
     * @return {boolean}
     */&lt;/span&gt;
    &lt;span class="nf"&gt;isValid&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// define stack&lt;/span&gt;
        &lt;span class="c1"&gt;// define hashmap for brackets&lt;/span&gt;
        &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;stack&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;map&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;([[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;)&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;]&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;}&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;{&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]])&lt;/span&gt;

        &lt;span class="c1"&gt;// iterate through s&lt;/span&gt;
            &lt;span class="c1"&gt;// if char is not in map&lt;/span&gt;
                &lt;span class="c1"&gt;// add char to stack&lt;/span&gt;
            &lt;span class="c1"&gt;// else if corresponding val is the last val in stack&lt;/span&gt;
                &lt;span class="c1"&gt;// pop top of stack&lt;/span&gt;
            &lt;span class="c1"&gt;// else (closing brace but no corresponding open brace in stack)&lt;/span&gt;
                &lt;span class="c1"&gt;// return false&lt;/span&gt;

        &lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;char&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;char&lt;/span&gt;&lt;span class="p"&gt;)){&lt;/span&gt;
                &lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;char&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;char&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;){&lt;/span&gt;
                &lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="c1"&gt;// return true if stack is empty, false if not empty&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
    </item>
  </channel>
</rss>
