Cushion Project blocks ↗
Cushion Redesigning the homepage ↗
Cushion Multiple timelines ↗
Cushion Archiving and estimate differences ↗
Cushion Multiple financial goals ↗
Cushion Zooming in on the timeline ↗
Cushion Currency ↗
Cushion Preferences, accounts, and typeface change ↗
Cushion Sending out the first email ↗
Cushion Currency inputs, notifications, and invoice nets ↗
Cushion Dots and lines ↗
Cushion Calculating in the database and revealing tendencies ↗
Cushion Improved form UX ↗
Cushion Cushion is online ↗
Cushion Schedule timeline patterns ↗
Cushion A slimmer schedule timeline ↗
Cushion The schedule timeline ↗
Cushion Plugging in real data for the first time ↗
Cushion Transitions and project lists ↗
Cushion Death to modals ↗
Cushion The individual project page ↗
Cushion Estimated incomes and talks with other freelancers ↗
Cushion Statuses to lists and the paid beta ↗
Cushion The timeline ↗
Cushion Invoice terminology ↗
Cushion Modal forms ↗
Cushion Wiring the backend to the frontend ↗
Cushion Balancing design and dev ↗
Cushion Timecop, Monocle, and Vagrant ↗
Cushion Going with Ruby and Sinatra ↗
Cushion Ditching local-first and trying out Node.js ↗
Cushion Switching to AngularJS ↗
Cushion Building the Table with Vue.js ↗
Cushion Clients, Projects, and Invoices ↗
Cushion Introduction (to the Cushion journal) ↗
Cushion Cushion ↗
2014
Cushion Retention through useful features ↗
Cushion The onboarding checklist ↗
Cushion Spreading the word ↗
Cushion From beta to launch - the subdomain ↗
Cushion From beta to launch - sign up ↗
Cushion From beta to launch - messaging ↗
Cushion Launch ↗
Cushion Authenticating with 3rd party services ↗
Cushion Intro to integrations ↗
Cushion Inspiration vs imitation ↗
Cushion The emotional rollercoaster ↗
Cushion Designing project blocks ↗
Cushion Everything in increments ↗
Cushion Deleting your account ↗
Cushion Designing the subscription page ↗
Cushion Rewriting the timeline ↗
2015
Cushion Funding Cushion ↗
Cushion Hiring a team of freelancers ↗
Cushion Taking a real break from work ↗
Cushion Slack as a notification center ↗
Cushion Document your features ↗
Cushion 300 ↗
Cushion Vacations ↗
Cushion Offering discounts ↗
Cushion Waves of traffic ↗
Cushion Less blogging, more journaling ↗
2016
Cushion My typical week as a founder ↗
Cushion Building components in a sandbox ↗
Cushion Reactive time with Vue.js ↗
Cushion Visualizing daylight saving time ↗
Cushion Recording screencast GIFs ↗
Cushion Writing a job listing ↗
Cushion Using feature flags to run betas ↗
Cushion Our first company lunch ↗
Cushion How to embed Vue.js & Vuex inside an AngularJS app... wait what? ↗
2017
Cushion The “Update Available” alert ↗
Cushion Improving readability with bigger fonts and higher contrast ↗
Cushion My design workflow ↗
Cushion Simplifying our build process and SSL with Cloudfront ↗
Cushion Restructuring an evolving app ↗
2018
Cushion The new invoice page is live ↗
With only days before the SCA deadline, I launch the new invoice page with to be SCA-ready while also paving the way for more improvements.
Cushion Integration testing the invoice page with Cypress ↗
Wrapping up my work on the invoice page, I set up integration testing using Cypress to make sure that everything continues to work end-to-end.
Cushion Tidying up as you go ↗
Continuing to make progress on the invoice page, I talk about some of the ways I’m improving the codebase along the way.
Cushion A subsidized plan for 2021 ↗
A chat with a user leads me to consider a subsidized plan for the New Year to help folks through the pandemic.
Cushion Redesigning the invoice page for SCA with Stripe Elements ↗
I pause work on the account page to make sure Cushion’s invoice payment integration is ready for the SCA deadline.
Cushion Rethinking the pricing page ↗
In needing to redesign the pricing page for the new account section, I decide to rethink the structure of Cushion’s existing plans.
Cushion A dev’s troubleshooting journey ↗
An innocent bug report unfolds into a roller coaster ride of a troubleshooting journey.
Cushion Scaffolding the account page ↗
As I begin building Cushion’s new account page, I start by scaffolding a static version of it and building the components it requires.
Cushion Redesigning the account section for SCA with Stripe Billing customer portal ↗
With SCA regulation going into effect at the end of the year, I prioritize migrating to the Stripe customer portal, which means redesigning the account section.
Cushion Designing a new layout system ↗
After years and years of incrementally tweaking the design of Cushion, I take a holistic look at the layout system.
Cushion Redesigning the blog ↗
After redesigning Cushion’s homepage, I take the next step in migrating to Contentful by rethinking the blog.
Cushion Animating the new homepage hero ↗
To keep my mind busy while dealing with a tough time, I distract myself with Cushion’s new homepage animation.
Cushion Responsive images for different layouts ↗
While building Cushion’s new homepage, I go the extra mile to swap out better-fitting images for different breakpoints.
Cushion A flexible way of using Nuxt.js with Contentful CMS ↗
After migrating Cushion’s changelog to Contentful, I move onto the homepage, where I narrow in on an approach to compose pages entirely in the CMS.
Cushion Migrating the changelog to the Contentful CMS ↗
In my initial step towards migrating Cushion’s marketing site to Contentful, I start with the changelog.
Cushion Promoting invoicing to the main nav ↗
I reworked the main nav to include invoicing, which was met with a wave of thanks from users.
Cushion The next big rocks ↗
After launching Cushion’s new onboarding, I detail the next few items on my to-do list, which for once are not new features.
Cushion Onboarding is live ↗
A weekend turned into a month, but Cushion’s new onboarding is finally live. Instead of focusing on the launch itself, I talk through my favorite part.
Cushion Composable onboarding ↗
To provide a more pleasant codebase for Future Jonnie to inherit, I restructure the onboarding to be composable and easily testable.
Cushion Writing my own utility methods ↗
I decide to write a few utility methods myself, rather than relying on 3rd party library, and I’m glad I do.
Cushion Using a utility library vs building my own ↗
Torn between adding a dependency for a utility method or writing it myself, I talk through the pros and cons of both approaches.
Cushion A reminder to write ↗
Determined to launch thew onboarding flow, I forgot to write for a week and it shows.
Cushion The date picker component ↗
Continuing my work on Cushion’s onboarding flow, I build a new and improved date picker component.
Cushion Building components for the long run ↗
With my recent work on Cushion’s new onboarding flow, I take a meandering walk through the new components I built for it that are all typed and tested.
Cushion Investigating inflection points ↗
Stepping back to look at Cushion’s growth over its entire lifetime reveals a crystal clear moment when everything went south.
Cushion Recalibrating my estimates ↗
I start working on the new onboarding flow, but quickly realize it won’t be a weekend project.
Cushion A friendly onboarding flow ↗
As a first stab at onboarding, I design a flow that includes myself asking questions, which hopefully provides a friendly intro to the app.
Cushion Bringing back onboarding ↗
In an attempt to ease people into the app rather than pushing them out of the airplane, I decide to bring back a proper onboarding flow.
Cushion Rough sketches ↗
After feeling reluctant to reveal any design progress, I decide to bite the bullet and share a few rough sketches—no matter how uncomfortable it feels.
Cushion Flattening the nav ↗
Continuing the idea of the single click, I talk through a potential path to flattening the nav from multiple layers down to one.
Cushion Well, this is embarrassing ↗
Browsing through Cushion, I realize something strange. As I troubleshoot the anomaly, I discover an embarrassing truth.
Cushion Sending newsletters again ↗
I sent my first Cushion newsletter in over a year and a half, which sounds crazy, but nonetheless, it feels great to send them again.
Cushion Validating assumptions ↗
Before diving into analytics, I decide to spend time writing database queries that could validate some of my assumptions using existing data.
Cushion Intentional analytics ↗
After building Cushion so far based purely on assumptions and intuition, I finally start to think about using analytics to help guide me.
Cushion This app has good bones ↗
A thought-provoking conversation leads me to realize that Cushion is still solid and worth iterating on, instead of restarting from scratch.
Cushion Keeping API requests simple ↗
After establishing a new guiding principle to keep API requests simple, I describe how I could refactor a complex view that relies on a heavy API request.
Cushion A single click ↗
I discuss a pain point in the current Cushion involving the number of clicks it takes to get to where you need to go. What if it only took one?
Cushion Shaping Vuex through testing ↗
Cushion Excluding a folder from VSCode’s search (and disabling Jest’s generated coverage reports) ↗
Cushion Retaining state with the router in a single page application ↗
Cushion Custom focus rings using :focus-within ↗
Cushion Testing v-on="$listeners" in Vue.js ↗
Cushion Vue + ESLint + Prettier conflicts ↗
Cushion Speeding up Jest tests with --runInBand ↗
Cushion Moving the Cushion Journal to my blog ↗
Cushion Updating Sentry ↗
Cushion Updating Skylight and dealing with ActiveSupport ↗
Cushion Reducing Heroku CI time by 35% for an extra penny ↗
Cushion The build failed, but I swear it wasn’t me ↗
Cushion A hiccup with subdomain routing ↗
Cushion Upgrading to Ruby 2.7.1 ↗
Cushion QA’ing pull requests using Heroku Review Apps ↗
Cushion Subdomain routing in Sinatra ↗
Cushion Redirecting the Heroku “Open app” button to a custom domain ↗
Cushion Reloading Ruby with Sinatra::Reloader ↗
Cushion Exploring a modern Cushion ↗
Cushion Migrating the Cushion website to S3 to avoid dealing with SSL ↗
2020
Cushion Quick launches after a big launch ↗
After launching the Schedule timeline beta, I’m able to easily launch a handful of smaller releases to keep progress going.
Cushion The new Schedule timeline is in beta! ↗
To get folks to start testing the new Schedule timeline early, I released the initial beta this weekend.
Cushion Zooming into the schedule timeline ↗
With the schedule timeline nearing a beta launch, I take a couple more weeks to sneak zooming into the feature set.
Cushion Flipping the schedule timeline ↗
In an unexpected moment, I decide to try vertically flipping the new schedule timeline, so projects stack from the top.
Cushion Handling timeline labels ↗
Determined to always display labels on the new schedule timeline, I detail all the edge cases I’ve gotten myself into.
Cushion Visualizing projects in the new schedule timeline ↗
Now that I have a canvas for the new schedule timeline, I need to fill it with projects.
Cushion A freeform scrolling timeline ↗
After thinking through a modern schedule timeline, I start by enlarging the timeline to full-page and adding freeform scrolling.
Cushion Exploring a modern schedule timeline ↗
Taking a break from the Clients section, I get a burst of inspiration thinking about scheduling.
Cushion Revisiting the UX for client notes ↗
Continuing work on the new Clients section, I revisit client notes, but with a few UX improvements.
Cushion Overflow shadows using the Intersection Observer API ↗
Improving a upon the overflow shadows in Cushion, I replace scroll events with the Intersection Observer API.
Cushion Addressing beta feedback for the new Clients section ↗
After rolling out the new Client section to a few dozen beta users, I start applying their feedback.
Cushion Upgrading to Vue 3 ↗
While making forward progress with the new Clients section, I take a break to upgrade the new codebase to Vue 3.
Cushion A Safari performance issue and other stresses ↗
An already stressful time is made even more stressful by a Safari performance issue with nested grids.
Cushion Time period filter and totals for the Clients section ↗
With the Clients section beta up and running, I launch my first incremental update.
Cushion A video call with a friend about marking projects as paid ↗
A video call with a friend provides some interesting insight into a potential direction for restructuring the app.
Cushion The new Clients section is now in private beta ↗
After a heads-down week, I managed to reach the first milestone in releasing the new Clients section—private beta.
Cushion Stabilizing PostgreSQL memory issues with pgbouncer ↗
In an update of the database memory saga, I discover pgbouncer, which puts a stop to the constantly climbing memory woes.
Cushion A top-level “Clients” section ↗
With the sidebar navigation ready to deploy this weekend, I get an early start on the top-level “Clients” section.
Cushion Improving the sidebar nav ↗
After regretting, but living with, the skinny sidebar nav of obscure icons, I finally set a course to improve its UX.
Cushion Sending blog posts as emails - Part 2 ↗
Following up on the initial proof of concept, I build the complete system to send journal posts as emails.
Cushion Sending blog posts as emails ↗
In an effort to grow readership, while also prototyping an idea, I start building a system to email my posts.
Cushion Sticky line item totals ↗
Putting the final touches on the invoice form, I apply a sticky behavior to the line item totals.
Cushion Little details: Overflow shadows ↗
I spend extra time getting a little detail right by tying shadows to whether the underlying content has overflow.
Cushion Redesigning the flow for importing tracked time into invoices ↗
With the last remaining to-do on my list for the new invoice form, I tackle the flow for importing tracked time.
Cushion A week of cleanup ↗
With the inline forms behind me, I spend a week cleaning up the codebase with a focus on Cushion’s form states.
Cushion Building the inline form system ↗
After detailing how I planned to build inline forms in Cushion, I went ahead and built the first one for creating clients inline.
Cushion Inline forms and the weight of the next big task ↗
In between big tasks, I distract myself with smaller tasks until I’m ready to finally face it—inline forms.
Cushion Designing a breadcrumbs component ↗
Chopping away at the new invoice form, I designed and built a new component for breadcrumbs.
Cushion Thinking about a “test mode” ↗
Aggravated by people signing up with no real intention to use Cushion leads me to consider a “test mode” where they can try the app without signing up.
Cushion Redesigning the invoice line item footer ↗
While redesigning the invoice form, I share the decision-making behind the design of the new line item footer.
Cushion Migrating CI to GitHub Actions ↗
Frustrated with Heroku, I start migrating away from it, beginning with continuous integration.
Cushion Troubleshooting the database upgrade ↗
Upgrading Cushion’s database leads to a week of troubleshooting performance issues.
Cushion Upgrading the production database ↗
After receiving an email from Heroku to upgrade Cushion’s database, I upgrade Cushion’s database.
Cushion 7 years old ↗
With Cushion reaching the 7-year mark, I reflect on its life and plot a course for its future.
Cushion Thinking through a new invoice form ↗
At the fork in the road, I choose the invoice form as the next step in renovating Cushion, including a long-awaited list of improvements.
Cushion The calm after the sprint ↗
With a couple big launches behind me, I think about what to tackle next or whether I need to pick a direction just yet.
Cushion The new account page is live ↗
After launching Cushion’s new invoice page last week, I launch the new account page this week with a ton of other goodies.
2021
Cushion “Software” with a capital “S” ↗
I hit a roadblock designing a UI that didn’t excite me, so I decide to take a step back and rethink a more personalized design.
Cushion Adding hotkey labels to the UI ↗
After taking a short break to collect myself, I eased back into work with a low-priority feature that I’ve been itching to add for a while.
Cushion Moving & resizing workloads in the timeline ↗
While building the drag & drop interaction for workloads, I accidentally created the coolest interaction I’ve ever made.
Cushion Editing workloads in the timeline ↗
After taking a couple weeks off to move into our new home, I’m back in the saddle with creating and editing workloads.
Cushion Vacations in the timeline ↗
To continue reaching feature parity with the existing schedule view, I added vacations to the new timeline.
Cushion Nested modal drawers with parallax ↗
Over the weekend, I ate the broccoli and built a nested drawer system, but ended up with a delightful parallax effect.
Cushion The evolution of a tooltip design ↗
The full circle journey of designing a tooltip that’s both simple and useful.
Cushion Estimated workloads in the schedule timeline ↗
After visualizing tracked time, I jumped from the past and into the future to visualize estimated workloads.
Cushion Total tracked time in the schedule timeline ↗
Now that Cushion can visualize tracked time, the next step is to combine tracked time and highlight when you overworked yourself.
Cushion Lazy loading tracked time in the schedule timeline ↗
After being close to launching tracked time in the schedule timeline beta, I decide to spend an extra week adding lazy loading.
Cushion Visualizing tracked time in the schedule timeline ↗
Straying from the plan to bring the timeline to 1:1 feature parity with the existing timeline, I visualize tracked time.
Cushion Duplicating an invoice ↗
I take a short break from the timeline beta to launch the ability to duplicate an invoice. No big deal.
Cushion Grouping and archiving projects in the schedule timeline ↗
On the new path of pursuing a list-based layout, I group the projects by list and add an archive filter.
Cushion One step back, two steps forward ↗
Foreseeing a problematic future with the stacking layout, I rethink the direction and end up down a better path.
Cushion Project actions in the Schedule timeline beta ↗
After adding the ability to add and edit projects in the Schedule timeline, I implement more detailed interactions with project actions.
Cushion Creating a project via form in the schedule timeline ↗
Back to working on the app, I take the leap into creating projects, but via form first instead of click & drag.
Cushion New year, new homepage ↗
I spend my holiday break bringing more fun to the Cushion homepage with a new design, full of illustrations and animations.
2022
Cushion Building a table for the nth time ↗
Now that I have data to wire up, I set out to build a table component, but first I revisit past attempts.
Cushion A return to tabbed navigation ↗
With a focus on navigation, I return to the early days when Cushion had a simple tabbed nav.
Cushion End-to-end testing with Playwright ↗
With the stack picked out, I set up end-to-end testing from the start, so I can get in the habit of testing user flows without any excuses.
Cushion Vercel, Supabase, Vue, and Vite ↗
As I rethink Cushion in the modern age, I detail my choices for platform, stack, and database.
Cushion Imagining Cushion circa 2016 in 2024 ↗
With Cushion’s 10-year anniversary approaching, a theory leads to an attempt at a modern upgrade, but with 2016’s feature set.
Cushion A weekend marathon of an infrastructure upgrade ↗
I spent a weekend upgrading Cushion’s Heroku stack and Ruby version, which sent me down a path of fixing hundreds of failing tests and removing a feature.
2023
Cushion Cleaning up the cobwebs ↗
After years of side-eyeing an unreleased feature that has been nagging me while slowing down the app, I finally take the time to remove it from the app.
Cushion Building a table for the nth time - Part 2 ↗
Following up on the initial post about building a table in Cushion, I actually detail my approach this time.
Cushion How to use Playwright with GitHub Actions for e2e testing of Vercel preview deployments ↗
I spent way too long trying to find out how to set up e2e testing with Vercel preview deploys, so I wrote a quick post to save others.
2024