- I spent five months building a full-stack web app for a SAAS startup I founded with a friend.
- Along the way, I learned React, Next.js, TailwindCSS, Firebase, Redux, API's, and much more.
- I failed to validate the startup idea before building it, and I learned a lot about the process of building a product.
- I'm bummed that it failed, but proud that I built a SAAS app from scratch myself and glad I learned what I did!
My largest project to date, and boy does this one have a story. My friend and I had an idea to create an app that helps you come up with novel ideas using AI and a set of thinking tools, so I got to work building it. I was the coder between the two of us, and I decided that I would build the app in React as I learn the framework. I was six months into my dev journey, and it's safe to say I bit off more than I could chew, but I kept at it and ended up building the entire codebase myself. I started off using only create-react-app, but I quickly discovered that I would need a backend to send API requests to. This lead me to convert my entire project to a Next.js app and learn that as I went as well. As the complexity grew, as did my need for a global state manager, so I did a crash course in Redux and added Redux state management to the project. I then implemented Firebase authentication and a Firestore NoSQL database for user accounts and data. It was surprisingly easy to learn Firebase, but hard to master the intricacies down the road. I converted to Tailwind CSS halfway through my project, so I had a large CSS file and Tailwind on the same project (don't worry, I'll showcase ALL of my mistakes at the end of this).
Every day I would spend at least 3-4 hours watching code videos or reading books and articles to learn the new tech, then code for the rest of the day. I'd say my average day was about 10 hours of work, 6 days a week minimum. Non-stop coding for five months straight. I'm skipping a lot of details here of specific implementations, I could write a book on everything that I did for this project, but you get the idea. At the end of the five-month period, I had a working app! It worked well, loaded quickly, was secure, and had an array of features. It was well and truly, a full stack Next.js SAAS app built from scratch with my own hands. I was super proud of it and excited to show it off to potential customers. (Yup, we made the mistake of building the entire app before validating the idea or getting customer feedback, oops.)
We invited 20 beta users to try the app and give proper feedback using a Tally form I created. The results weren't great. Tons of feedback about how the navigation didn't make sense, not enough context and help menus, and overall confusion as to what it was and what it does. Disheartening to say the least. I added help menus, modified the navigation and flow of the app, and added some new things over the next two weeks, but again, the feedback was exceedingly negative. That's when I realized that it wasn't the app, it was the underlying problem we were trying to solve. I had meetings with a few entrepreneurs and asked them questions about how they come up with ideas and manage them. I learned that most entrepreneurs have way too many ideas, not too few. And that the app I built was targeted at folks that wanted to start a business, but didn't have a business idea yet. That's a tough niche to market to, and even tougher to convince those folks to pay a monthly subscription fee for a tool that could * potentially * help them create an idea. After five months of development, it took less than a week to learn that the idea for an idea maker was weak, and not worth pursuing. Ouch.
This project helped me to learn a massive amount about full stack web development, but those learnings pale in comparison to the lesson of validating projects early on and talking to customers before building. Never again will I build business apps blindly, and I intend to never go at it fully alone again. Knowing what I know now, I could build a similar app in a fraction of the time, and that knowledge gained was worth the price of admission, but barely lol.
Mistakes and lessons learned
Only build a SAAS app if you have validated that the problem your app will solve is worth solving in the first place.
Talk to users early and often. Their feedback should help to guide the direction of the app.
One thing at a time. I should have learned React by building some example projects first, then gone on to learn Next.js, then built out the app. Learning them both at the same time definitely slowed me down.
Redux is probably overkill. Atomic state is the future.
Deciding to use TailwindCSS halfway through made styling a nightmare. I love Tailwind, but jamming it into a project that was working just fine with regular CSS classes added unnecessary complexity, especially for a beginner.
Keep it simple stupid. I didn't need to spend four full days implementing a rich text editor, but I did. I should have kept complexity to a minimum until I knew that a feature is worth pursuing.
Keep components small. Looking back, I'm embarrassed at the sheer size of some of the components. If I had to jump in and fix something in that file I would have no idea where to start.
Write comments in places where the code needs explaining. I ignored this most of the time for the sake of speed.
Rely less on npm packages. They have their uses, for sure. But I was unafraid of just tossing in another npm package willy-nilly. Not again. I will use bundle phobia in the future.
Clean code and refactor as you go. I left a lot of commented-out code all over the place “just in case I needed it later”. Bad idea. You can always access old code from old commits, that's where it belongs. Not grayed out next to functioning code.
Perfectionism is rarely helpful. I recall days when I would spend several hours just micro-adjusting CSS positions and colors to make it “perfect”. Perfect UI's don't exist. Get it 80% of the way there, and come back to it later if you have to. Even big sites like Apple.com have tiny imperfections.
Burnout is real. After five months of 10-hour days six days a week with zero vacations, I was exhausted. Add on top of that the negative feedback and feeling like I was an idiot for wasting all that time, my mental state got to an all-time low. I've since picked myself up and recovered, but lesson learned.
- Component-based web architecture
- JSX and the virtual DOM
- Events and component life cycles
- React Hooks: useState, useEffect, useCallback, useMemo, useContext, useRef
- Using useContext to provide global user state throughout the component tree
- Custom hooks such as useClickOutside
- Iterating over arrays in React using array.map()
- npm, npm packages, package.json, and package-lock.json
- Using ESLint to enforce clean code rules. I also used SonarLint which provides helpful security and performance linting error messages
- Modals in React
- Using React-Table to create beautiful, interactive tables with cells that allow for JSX children
- Using hotkeys in React
- Next.js SSR, CSR, ISR
- Next.js API routes
- Adding manifest.json to allow the app to be a Progressive Web App
- Private environment variables
- Layouts that persist between routes in Next.js
- Protected routes to prevent unauthenticated visitors from accessing private content
- Custom CSS loader to display between route changes in Next.js
- Using dynamic imports to run a component only on the client
- Custom 404 and 500 pages
Firebase / Data
- User Authentication with Firebase and sign in with Google
- NoSQL databases with Cloud Firestore
- Data modeling and structuring a NoSQL database
- Querying data from collections
- Limiting read and write events to prevent a large Firebase bill
- Creating interactive calculators with graphs using chart.js
- Create, Read, Update, and Delete (CRUD) functionality in Cloud Firestore
- Firestore security rules
- Implementing custom usernames by searching a Firestore collection of taken usernames to see if it is taken
- Tree shaking in general, Firebase v9 taught me how to do it, and the performance benefits of doing so
- Redux (Store, actions, reducers, dispatch, selectors, and middleware)
- Redux-persist to store state between sessions, and make that play nicely with server-side rendering
Styling / UI
- Tailwind CSS
- Custom Tailwind config file
- Using the @layer directive to create short class names using tailwind
- Dark mode with Tailwind
- Framer Motion basics
- CSS variables, and modifying them with JS
- Using and styling SVG icons
- The use of opacity and glassmorphism to make modern UI's
- Loading skeletons while an image loads
- OpenAI GPT-3 integration
- GPT-J integration using the Text Synth API
- API rate limiting using node.js
- Using webhooks in a Next.js API route to get payment events and update a users cloud Firestore account using Firebase Admin API
- Payment integration using Paddle.js
- Using Pexels and Similar words API to show images and related words to the word displayed in the combinatorial tool
- Using the Pexels API to allow a user to add an image header to a note, and adjust the position of the image, similar to Notion
- Hosting with Vercel
- Cookies and session
- Local Storage, in particular saving user settings to Local Storage
- Google Analytics
- Rich text editors (WYSIWYG)
- Sanitizing HTML to prevent Cross-site scripting attacks
- Debouncing user inputs
- Using a step wizard UI for interactive step-wise forms
- Help context menus for better UX
- Browser cross-origin errors
- Cascading menu using Ant Design's Cascader component
- Using array.filter() to allow for searching of notes
- Toast messages
- Integrating feedback forms in the help page using Tally
- Using Shepherd.js to create an interactive product demo
- Using LogRocket to track performance and replay user sessions to find bugs
- Setting up a log drain on Vercel to monitor logs from edge functions invoked from Next.js API routes
User accounts with Firebase
Sign in with google
CRUD notes using Cloud Firestore
GPT-3 or GPT-J AI-assisted ideas
Combinatorial thinking tool that displays three random words with Pexels images for each word
Problem discovery tool using a step wizard UI
Feature selection tool that allows a user to select features for their idea and rank these features in an interactive table UI
Tech Stack selection tool that lets you pick a tech stack for your idea and estimate the cost of your stack
Interactive pricing calculator with graph
Payments and subscriptions using Paddle.js and webhooks
User customizable UI and color scheme
Rich text editors with sanitized HTML
Customizable timer component for timed idea creation sessions.
Global state that persists between sessions
Integrated user feedback forms
Progressive Web App (PWA) support to add the app to mobile home screen