Our Experience Migrating to Jumpstart Pro

Ryan Castillo

26 Mar 2024

Why Wafris Needed to Jump to Jumpstart Pro

We’re a small team at Wafris so we tend to ask “how can we cheat” a lot. We had proven that our MVP worked and people were willing to pay for it but we were missing core features for a SaaS

Jumpstart Pro (JSP) ended up being a pretty big cheat. It brought features like

  • Integrated Stripe payments/subscriptions
  • Notifications
  • A more complete Admin Panel
  • User Account Management
  • Tailwind UI Components

This easily saved us a quarter or two worth of work. And we trusted the codebase because it had thousands of contributions over multiple years.


When we started building Wafris our goal was to move fast. So we stuck with what we knew:

  • Rails 7 - been building Rails apps since pre-3.0
  • Tailwind with a purchased theme - we’ve always been big fans of buying CSS themes. They’ve gotten our styling 80% of the way there and allowed us to spend more time building user feature
  • Heroku - have had a variety and apps and add-ons deployed on Heroku for over a decade

Needing Tests

We wouldn’t have considered the migration if we didn’t have tests. Experience has told us to at least have

  • unit tests around business logic
  • integration tests around core functionality

JSP also came with pretty decent test coverage. We knew that between our tests and JSP, it would catch any show-stoppers post-migration.

The Great Codebase Merge Adventure

A big question from the beginning was whether we should merge the git histories or not. We were paranoid about being stuck resolving merge conflicts on files shared between the codebases. Particularly those generated by Devise.

The very first thing we did was copy the entire JSP codebase and paste it on top of our directory. We trusted that git highlight the areas we needed to spend the most time. It boiled down to:

  • schema.rb
  • routes.rb
  • config files
  • Devise generated code

This approach allowed us to introduce sections of the JSP codebase into our history rather than trying to do it all at once with a merge or rebase.

Lazygit was a great tool for managing and visualizing this process.


The Upstream Firehose

We still wanted to get updates from JSP as the maintenance is quite active. It seems like they push updates daily!

So we knew that we’d eventually have to merge the Git histories. Git has a nice little trick to blend the histories from multiple repositories:

git merge <remote>/<branch> --allow-unrelated-histories

Migrations and Models Everywhere

Losing production data and trying to recover it was the last thing we wanted to do with our time.

The stickiest part involved User data. We had already implemented teams as an MVP (from the Bullettrain blog) feature but JSP used different terminology: teams were now named accounts and the hasmanythrough table was completely different.

Instead of using JSP’s existing migrations, we ended up deleting them and using their schema as a basis for one giant migration that was 321 lines long.

Suggestion: spend time considering the best approach for you here. You’ll have to either:

  • Create a giant migration (what we did) and delete the old corresponding migrations or
  • Merge your migrations with JSP’s and repeat the process of
    1. Running rails db:setup
    2. Addressing any migration issues
    3. Repeat 1 & 2 until you can get to a stable schema.rb from scratch.

JSP does a nice job of splitting out logic into modules which made it straightforward to merge with our models.

Routes and Controllers: The Unsung Heroes

The controllers were like the models. More of introducing new actions/methods rather than having to merge anything.

Routes on the other hand were a little more complicated as the migration tripled our routes.rb due to JSP shipping with Administrate, a skeleton for an API, and several other routes.

This forced us to decide whether we wanted to go with JSP’s route hierarchy.

We ended up going with everything JSP defaulted to but encountered all the annoyances of merging a large file and changing our routes.

Update: this has since been addressed in the recent releases of JSP as the team has utilized the draw macro to split out this large Routes file into multiple small ones.

Spaghetti Classes

Updating the views to JSP's standards was a major shift. Mainly because

  1. We had our tailwind theme that was pretty baked into our views.
  2. We were using importmaps rather than esbuild to deliver our assets.

The second point wasn’t as complicated as the first but we ran into some sharp corners (e.g. precompiled assets) that caused us to troubleshoot assets longer than we liked.

For the theming, we had to revisit every page to gut out our old theming and default to JSPs. This redundant refactor is one of the pain points of using Tailwind. Rather than editing CSS files, we had to meticulously remove classes.

Overall, it was worth it as we now have more universal theming and dark/light mode as a bonus.



It’s been several months since we migrated to JSP and we’re still reaping the benefits. One new one has been bringing on a contractor and them being able to hit the ground running as they’ve worked with multiple JSP projects before.

JSP is a cheat. 

Do this next

We're on a mission to better secure every web app on internet. Here's some ways you can jump in:

1. Check out our Open Source Web Application Firewall

Wafris is the free open source WAF that you can use to understand and visualize the requests hitting your apps and then take steps to protect them. It's still in early development, but you can signup for the waitlist to get early access at wafris.org

2. Investigate IP addresses with our IP Lookup service

Bad bots and probes hit sites within minutes of being put on the Internet. Sort the good from the bad by identifying request IPs as coming from bots, Tor networks, VPNs, proxies and malware hosts at wafris.org/ip-lookup

3. Anything else?

If you have any questions or need help finding the right way to handle web app security issues, please let us know at: help@wafris.org