Case Study: CatDish

Part 1

So what's the point of this app?


Back in October, I adopted a cat. He is seven years old, blind, and arrived at the SPCA with feline idiopathic cystitis, aka urinary crystals, which can be fatal in cats. His name is Wali.

One of his vets recommended a urinary diet. In cats this means: no kibble ever. Wet food only for hydration. Limited grains or fillers. As my vet called it: keto for cats.

very handsome cat

Wali the cat

Enter: The Spreadsheet

A cat-owner forum I frequent has a wonderful Google Sheet floating around that includes ingredient data for hundreds of US brands. This is an incredible resource for cats with allergies or dietary restrictions, like our friend Wali here.

The Problem

The first problem is that the spreadsheet is read only. The document’s original creator has locked the document, which means there’s no way for users to share updates to the data. Sure, we could just create a duplicate of the spreadsheet, but this doesn't protect the data from tampering or inaccuracy. Additionally:

  • Cat food brands adjust their ingredients often
  • This means the spreadsheet data might be stale!

The second problem is that this wealth of data is essentially inaccessible on mobile. Which means that if a cat owner is in a store looking for a suitable brand of cat food, they aren’t able to access the data easily. Here's why:

  • Nutrition labelling on cat food can be tricky to read. Sometimes the font is incredibly tiny in order to fit on the label of a 3-oz can
  • In other cases, the nutrition facts are actually hidden on the reverse/adhesive side of the label, requiring the label be peeled back in order to see the ingredients. Which, you know, isn’t cool to do in a store.

More than a few users on the forum indicated that having mobile access to the spreadsheet would be useful

The Solution

Well I’m a front-end developer. You know what I’m pretty good at? Building front-ends. Nary exists a spreadsheet whose data I can’t transform into something that looks good on a phone.

Additionally, I could certainly build an interface that would allow users to add or modify ingredient data.

Part 2

The Back End

What kind of data are we talking about here?

The data in question is a collection of US-based wet food brands for cats. Each record includes:

  • Brand name
  • Brand product line
  • Food texture
  • A yes/no flag for approx 100 common allergens
Google sheet data

Google sheet data

Choosing a back end

I chose MongoDB Atlas as the back end for this app

  • Low barrier to entry due to familiarity with the product
  • It's free (at least for my purposes)
  • I can store sensitive user data

Writing a REST API

At the moment, this app only requires two API endpoints:

  • Ingredient endpoint: return a list of brands which match the user’s specified query
  • User endpoint: storing user data
At the moment, the app's data is read only.

Back End Road Map

  • Build out user data table
  • Implement 3rd parth authentication (looking at you, PassportJS)
  • Integrate CMS to allow users to modify data
  • Update data schema (extract Ingredients to their own collection (table)

Part 3

Framework & Deployment Platforms

App Architecture

With the back-end all set, my next task was choosing a front-end. My app architecture of choice is the JAMStack. Why JAM?

I spent the beginning of my career building websites with LAMP stacks like Wordpress and Drupal. Wordpress and Drupal are easy to configure, and work exceptionally well for certain use-cases (looking at you, every public library in America).

But as a developer, the wordpress/drupal ecosystems can quickly become a nightmare to work with. Plugins contribute to code bloat very quickly. Customization can be a challenge. The codebases end up huge and potentially unnavigable.

A Note on React

You might be asking: does a tiny app like this really * need * React? And the answer to that is: certainly not. Everything this app does could be accomplished with good 'ol HTML and VanillaJS. However: using React added immense value to the development experience. It's easy. It's fun(ctional). Since I'm the only dev on this project, I get to choose the development tools :)

Battle of the SSGs (static site generators)

It really came down to Gatsby or NextJS.

However, having built a REST API already, I thought it would be inefficient to use Gatsby without GraphQL. NextJS + Vercel it was!

Part 4

The Fun Part!

Now that all the boring stuff is out of the way, let’s get to the fun part — the front end!

The Spirit of the App

The most important aspect of this app is that it be more user-friendly than a Google Sheet.

This means:

  • It has to look great on mobile
  • It should be very easy for users to filter results by the inclusion/exclusion of ingredients
  • I have assumed that users care more about the presence/absence of certain ingredients than any particular brand or texture. However, this might change.
Index page

Home page

UI Decisions

I chose to put each filter group on its own page. Here's why:

  • Each filter group is searchable
  • On pages with many filters, the filters are subcategorized
  • This keeps each page decluttered
  • This prevents the user from becoming overwhelmed with choice

Additionally, a current selected filters components allows users to see which filters they have chosen from each page.

Filter page

One of the filter groups

CSS Decisions

  • As a solo dev working on this project, I chose to use TailwindCSS
  • Tailwind’s design system is incredibly easy to use and reduces decision overhead
  • I think it’s a lot prettier than, say, Bootstrap
  • Using Tailwind with the classnames npm package makes dynamic styling a breeze
  • Caveat: using TailwindCSS on project with multiple developers would be challenging

NB: I am currently considering moving from SCSS to Styled Compoents. My understanding of Tailwind's ethos is this: don't leave your file to style. This felt jarring and oh-so-wrong at first, but now I find my ~ coding flow ~ disrupted by having to move into a SASS file to add styling. I think I'm finally sold on CSS-in-JS.

Colors & Motifs

I generally prefer a limited color palette.

Pink, dark gray, and light gray, along with a lot of whitespace, conveyed a sense of fun (because cats are fun) tempered with clean minimalism.

For a visual motif, I went for blobs and organic shapes. They add a modern but fun flair to web design.

Results page

Results Page

Front End Road Map

  • The results page needs some further organization and stronger visual differentiation for each result card
  • Users should be able group results by brand, since seeing a long list of results of the same brand is not visually appealing and feels cluttered
  • There are some bugs with the pagination!
  • I would like to make the app’s visual identity a little more distinct
  • The app needs to feel a little more vibrant — this can be accomplished with subtle animation on UI interaction and during page transitions and visibility changes
  • Results should include product images and purchase links
  • Device QA
  • Logged-in users will need an interface for modifying data
  • TESTS. Yeah. I need to write tests.
  • Typechecking. Many components are missing adequate typechecking. Future me will thank me.