diff --git a/gems/fizzy-saas/.github/dependabot.yml b/gems/fizzy-saas/.github/dependabot.yml
deleted file mode 100644
index 83610cfa4..000000000
--- a/gems/fizzy-saas/.github/dependabot.yml
+++ /dev/null
@@ -1,12 +0,0 @@
-version: 2
-updates:
-- package-ecosystem: bundler
- directory: "/"
- schedule:
- interval: weekly
- open-pull-requests-limit: 10
-- package-ecosystem: github-actions
- directory: "/"
- schedule:
- interval: weekly
- open-pull-requests-limit: 10
diff --git a/gems/fizzy-saas/.github/workflows/ci.yml b/gems/fizzy-saas/.github/workflows/ci.yml
deleted file mode 100644
index ef5e97c73..000000000
--- a/gems/fizzy-saas/.github/workflows/ci.yml
+++ /dev/null
@@ -1,69 +0,0 @@
-name: CI
-
-on:
- pull_request:
- push:
- branches: [ main ]
-
-jobs:
- lint:
- runs-on: ubuntu-latest
- env:
- RUBY_VERSION: ruby-3.4.5
- RUBOCOP_CACHE_ROOT: tmp/rubocop
- steps:
- - name: Checkout code
- uses: actions/checkout@v5
-
- - name: Set up Ruby
- uses: ruby/setup-ruby@v1
- with:
- ruby-version: ${{ env.RUBY_VERSION }}
- bundler-cache: true
-
- - name: Prepare RuboCop cache
- uses: actions/cache@v4
- env:
- DEPENDENCIES_HASH: ${{ hashFiles('**/.rubocop.yml', '**/.rubocop_todo.yml', 'Gemfile.lock') }}
- with:
- path: ${{ env.RUBOCOP_CACHE_ROOT }}
- key: rubocop-${{ runner.os }}-${{ env.RUBY_VERSION }}-${{ env.DEPENDENCIES_HASH }}-${{ github.ref_name == github.event.repository.default_branch && github.run_id || 'default' }}
- restore-keys: |
- rubocop-${{ runner.os }}-${{ env.RUBY_VERSION }}-${{ env.DEPENDENCIES_HASH }}-
-
- - name: Lint code for consistent style
- run: bin/rubocop -f github
-
- test:
- runs-on: ubuntu-latest
-
- # services:
- # redis:
- # image: valkey/valkey:8
- # ports:
- # - 6379:6379
- # options: --health-cmd "redis-cli ping" --health-interval 10s --health-timeout 5s --health-retries 5
- steps:
- - name: Checkout code
- uses: actions/checkout@v5
-
- - name: Set up Ruby
- uses: ruby/setup-ruby@v1
- with:
- ruby-version: ruby-3.4.5
- bundler-cache: true
-
- - name: Run tests
- env:
- RAILS_ENV: test
- # RAILS_MASTER_KEY: ${{ secrets.RAILS_MASTER_KEY }}
- # REDIS_URL: redis://localhost:6379/0
- run: bin/rails db:test:prepare test
-
- - name: Keep screenshots from failed system tests
- uses: actions/upload-artifact@v4
- if: failure()
- with:
- name: screenshots
- path: ${{ github.workspace }}/tmp/screenshots
- if-no-files-found: ignore
diff --git a/gems/fizzy-saas/.gitignore b/gems/fizzy-saas/.gitignore
deleted file mode 100644
index a3ee5aad3..000000000
--- a/gems/fizzy-saas/.gitignore
+++ /dev/null
@@ -1,10 +0,0 @@
-/.bundle/
-/doc/
-/log/*.log
-/pkg/
-/tmp/
-/test/dummy/db/*.sqlite3
-/test/dummy/db/*.sqlite3-*
-/test/dummy/log/*.log
-/test/dummy/storage/
-/test/dummy/tmp/
diff --git a/gems/fizzy-saas/.kamal/hooks/post-deploy b/gems/fizzy-saas/.kamal/hooks/post-deploy
deleted file mode 100755
index 871506078..000000000
--- a/gems/fizzy-saas/.kamal/hooks/post-deploy
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/usr/bin/env bash
-
-MESSAGE="$KAMAL_PERFORMER deployed $KAMAL_SERVICE_VERSION to $KAMAL_DESTINATION in $KAMAL_RUNTIME seconds"
-CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD)
-
-bin/notify_dash_of_deployment "$MESSAGE" $KAMAL_VERSION $KAMAL_PERFORMER $CURRENT_BRANCH $KAMAL_DESTINATION $KAMAL_RUNTIME
-
-if [[ $CURRENT_BRANCH == "main" && $KAMAL_DESTINATION == "production" ]]; then
- gh release create $KAMAL_SERVICE_VERSION --target $KAMAL_VERSION --generate-notes 2> /dev/null || true
-
- RELEASE_URL=$(gh release view $KAMAL_SERVICE_VERSION --json url,body --jq .url)
- RELEASE_BODY=$(gh release view $KAMAL_SERVICE_VERSION --json url,body --jq .body)
-
- bin/broadcast_to_bc "$MESSAGE "$'\n'"$RELEASE_URL "$'\n'"$RELEASE_BODY"
-else
- bin/broadcast_to_bc "$MESSAGE"
-fi
diff --git a/gems/fizzy-saas/.kamal/hooks/pre-build b/gems/fizzy-saas/.kamal/hooks/pre-build
deleted file mode 100755
index 99de8a824..000000000
--- a/gems/fizzy-saas/.kamal/hooks/pre-build
+++ /dev/null
@@ -1,37 +0,0 @@
-#!/usr/bin/env ruby
-
-def exit_with_error(message)
- $stderr.puts message
- exit 1
-end
-
-def check_branch
- if ENV["KAMAL_DESTINATION"] == "production"
- current_branch = `git branch --show-current`.strip
-
- if current_branch != "main"
- exit_with_error "Only the `main` branch should be deployed to production, current branch is #{current_branch}. If this is expected, try again with `SKIP_GIT_CHECKS=1` prepended to the command"
- end
- end
-end
-
-def check_for_uncommitted_changes
- if `git status --porcelain`.strip.length != 0
- exit_with_error "You have uncommitted changes, aborting"
- end
-end
-
-def check_local_and_remote_heads_match
- remote_head = `git ls-remote origin --tags $(git branch --show-current) | cut -f1 | head -1`.strip
- local_head = `git rev-parse HEAD`.strip
-
- if local_head != remote_head
- exit_with_error "Remote HEAD #{remote_head}, differs from local HEAD #{local_head}, aborting"
- end
-end
-
-unless ENV["SKIP_GIT_CHECKS"]
- check_branch
- check_for_uncommitted_changes
- check_local_and_remote_heads_match
-end
diff --git a/gems/fizzy-saas/.kamal/hooks/pre-connect b/gems/fizzy-saas/.kamal/hooks/pre-connect
deleted file mode 100755
index 5f42f2cf2..000000000
--- a/gems/fizzy-saas/.kamal/hooks/pre-connect
+++ /dev/null
@@ -1,82 +0,0 @@
-#!/usr/bin/env bash
-
-# Validate hostnames are FQDNs ending in -int.37signals.com
-if command -v yq >/dev/null 2>&1; then
- declare -A SUGGESTIONS
- while IFS= read -r host; do
- if [[ ! $host =~ -int\.37signals\.com$ ]]; then
- if [[ $host =~ -4[0-9]{2}$ ]]; then
- SUGGESTIONS["$host"]="$host.df-ams-int.37signals.com"
- elif [[ $host =~ -1[0-9]{2}$ ]]; then
- SUGGESTIONS["$host"]="$host.df-iad-int.37signals.com"
- else
- SUGGESTIONS["$host"]="$host.sc-chi-int.37signals.com"
- fi
- fi
- done < <(bin/kamal config -d "${KAMAL_DESTINATION:-production}" 2>/dev/null | yq -r '.":hosts"[]')
-
- if [ ${#SUGGESTIONS[@]} -gt 0 ]; then
- echo "Unqualified hostnames found in config/deploy.${KAMAL_DESTINATION:-production}.yml:" >&2
- echo "" >&2
- echo "Update to use fully-qualified hostnames:" >&2
- for host in "${!SUGGESTIONS[@]}"; do
- echo " $host → ${SUGGESTIONS[$host]}" >&2
- done
- exit 1
- fi
-fi
-
-# Verify Tailscale connection and SSH authentication before deploying.
-tailscale_cmd() {
- if command -v tailscale >/dev/null 2>&1; then
- tailscale "$@"
- elif [ -f "/Applications/Tailscale.app/Contents/MacOS/Tailscale" ]; then
- env TAILSCALE_BE_CLI=1 /Applications/Tailscale.app/Contents/MacOS/Tailscale "$@"
- else
- return 1
- fi
-}
-
-on_tailscale() {
- tailscale_cmd status --json 2>/dev/null | jq -e '.Self.Online' >/dev/null 2>&1
-}
-
-# Check Tailscale connection
-if ! on_tailscale; then
- echo "" >&2
- echo "You must be connected to Tailscale to deploy." >&2
- echo "" >&2
- echo "→ Connect to Tailscale and try again" >&2
- echo "" >&2
- exit 1
-fi
-
-# Verify SSH access
-echo "Deploying via Tailscale. Verifying SSH access…" >&2
-
-TEST_HOST="fizzy-app-101"
-
-SSH_OUTPUT=$(ssh -o ConnectTimeout=5 "app@$TEST_HOST" true 2>&1)
-SSH_EXIT=$?
-
-echo "$SSH_OUTPUT" >&2
-
-if echo "$SSH_OUTPUT" | grep -q "Permission denied"; then
- GITHUB_USER=$(gh api user 2>/dev/null | jq -r '.login // "unknown"')
- GITHUB_KEYS_URL="https://github.com/${GITHUB_USER}.keys"
-
- echo "" >&2
- echo "ERROR: SSH authentication failed" >&2
- echo "" >&2
- echo "You must deploy with an SSH key that's on your GitHub account." >&2
- echo "" >&2
- echo "→ Verify your public key is at $GITHUB_KEYS_URL" >&2
- echo " Add it at https://github.com/settings/keys if not" >&2
- echo "" >&2
- echo "Note that SSH keys are pulled from GitHub every 5 minutes, so if you've" >&2
- echo "just added a new key to GitHub, try again in five." >&2
- echo "" >&2
- exit 1
-fi
-
-exit $SSH_EXIT
diff --git a/gems/fizzy-saas/.rubocop.yml b/gems/fizzy-saas/.rubocop.yml
deleted file mode 100644
index f9d86d4a5..000000000
--- a/gems/fizzy-saas/.rubocop.yml
+++ /dev/null
@@ -1,8 +0,0 @@
-# Omakase Ruby styling for Rails
-inherit_gem: { rubocop-rails-omakase: rubocop.yml }
-
-# Overwrite or add rules to create your own house style
-#
-# # Use `[a, [b, c]]` not `[ a, [ b, c ] ]`
-# Layout/SpaceInsideArrayLiteralBrackets:
-# Enabled: false
diff --git a/gems/fizzy-saas/Gemfile b/gems/fizzy-saas/Gemfile
deleted file mode 100644
index 396a3192e..000000000
--- a/gems/fizzy-saas/Gemfile
+++ /dev/null
@@ -1,6 +0,0 @@
-source "https://rubygems.org"
-git_source(:bc) { |repo| "https://github.com/basecamp/#{repo}" }
-
-# 37id and Queenbee integration
-gem "queenbee", bc: "queenbee-plugin", ref: "eb01c697de1ad028afc65cc7d9b5345a7a8e849f"
-gem "activeresource", require: "active_resource" # needed by queenbee
diff --git a/gems/fizzy-saas/Gemfile.lock b/gems/fizzy-saas/Gemfile.lock
deleted file mode 100644
index 5d83987cd..000000000
--- a/gems/fizzy-saas/Gemfile.lock
+++ /dev/null
@@ -1,69 +0,0 @@
-GIT
- remote: https://github.com/basecamp/queenbee-plugin
- revision: eb01c697de1ad028afc65cc7d9b5345a7a8e849f
- ref: eb01c697de1ad028afc65cc7d9b5345a7a8e849f
- specs:
- queenbee (3.2.0)
- activeresource
- builder
- rexml
-
-GEM
- remote: https://rubygems.org/
- specs:
- activemodel (8.0.2.1)
- activesupport (= 8.0.2.1)
- activemodel-serializers-xml (1.0.3)
- activemodel (>= 5.0.0.a)
- activesupport (>= 5.0.0.a)
- builder (~> 3.1)
- activeresource (6.1.4)
- activemodel (>= 6.0)
- activemodel-serializers-xml (~> 1.0)
- activesupport (>= 6.0)
- activesupport (8.0.2.1)
- base64
- benchmark (>= 0.3)
- bigdecimal
- concurrent-ruby (~> 1.0, >= 1.3.1)
- connection_pool (>= 2.2.5)
- drb
- i18n (>= 1.6, < 2)
- logger (>= 1.4.2)
- minitest (>= 5.1)
- securerandom (>= 0.3)
- tzinfo (~> 2.0, >= 2.0.5)
- uri (>= 0.13.1)
- base64 (0.3.0)
- benchmark (0.4.1)
- bigdecimal (3.2.3)
- builder (3.3.0)
- concurrent-ruby (1.3.5)
- connection_pool (2.5.4)
- drb (2.2.3)
- i18n (1.14.7)
- concurrent-ruby (~> 1.0)
- logger (1.7.0)
- minitest (5.25.5)
- rexml (3.4.4)
- securerandom (0.4.1)
- tzinfo (2.0.6)
- concurrent-ruby (~> 1.0)
- uri (1.0.3)
-
-PLATFORMS
- aarch64-linux-gnu
- aarch64-linux-musl
- arm-linux-gnu
- arm-linux-musl
- arm64-darwin
- x86_64-darwin
- x86_64-linux-gnu
- x86_64-linux-musl
-
-DEPENDENCIES
- activeresource
- queenbee!
-
-BUNDLED WITH
- 2.7.0
diff --git a/gems/fizzy-saas/README.md b/gems/fizzy-saas/README.md
deleted file mode 100644
index ecaa3ede6..000000000
--- a/gems/fizzy-saas/README.md
+++ /dev/null
@@ -1,28 +0,0 @@
-# Fizzy::Saas
-Short description and motivation.
-
-## Usage
-How to use my plugin.
-
-## Installation
-Add this line to your application's Gemfile:
-
-```ruby
-gem "fizzy-saas"
-```
-
-And then execute:
-```bash
-$ bundle
-```
-
-Or install it yourself as:
-```bash
-$ gem install fizzy-saas
-```
-
-## Contributing
-Contribution directions go here.
-
-## License
-The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
diff --git a/gems/fizzy-saas/Rakefile b/gems/fizzy-saas/Rakefile
deleted file mode 100644
index e7793b5c1..000000000
--- a/gems/fizzy-saas/Rakefile
+++ /dev/null
@@ -1,8 +0,0 @@
-require "bundler/setup"
-
-APP_RAKEFILE = File.expand_path("test/dummy/Rakefile", __dir__)
-load "rails/tasks/engine.rake"
-
-load "rails/tasks/statistics.rake"
-
-require "bundler/gem_tasks"
diff --git a/gems/fizzy-saas/app/assets/images/fizzy/saas/.keep b/gems/fizzy-saas/app/assets/images/fizzy/saas/.keep
deleted file mode 100644
index e69de29bb..000000000
diff --git a/gems/fizzy-saas/app/assets/stylesheets/fizzy/saas/application.css b/gems/fizzy-saas/app/assets/stylesheets/fizzy/saas/application.css
deleted file mode 100644
index 0ebd7fe82..000000000
--- a/gems/fizzy-saas/app/assets/stylesheets/fizzy/saas/application.css
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- * This is a manifest file that'll be compiled into application.css, which will include all the files
- * listed below.
- *
- * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
- * or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
- *
- * You're free to add application-wide styles to this file and they'll appear at the bottom of the
- * compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
- * files in this directory. Styles in this file should be added after the last require_* statement.
- * It is generally better to create a new file per style scope.
- *
- *= require_tree .
- *= require_self
- */
diff --git a/gems/fizzy-saas/app/controllers/concerns/.keep b/gems/fizzy-saas/app/controllers/concerns/.keep
deleted file mode 100644
index e69de29bb..000000000
diff --git a/gems/fizzy-saas/app/controllers/signup/completions_controller.rb b/gems/fizzy-saas/app/controllers/signup/completions_controller.rb
deleted file mode 100644
index d7f09c086..000000000
--- a/gems/fizzy-saas/app/controllers/signup/completions_controller.rb
+++ /dev/null
@@ -1,24 +0,0 @@
-class Signup::CompletionsController < ApplicationController
- layout "public"
-
- disallow_account_scope
-
- def new
- @signup = Signup.new(identity: Current.identity)
- end
-
- def create
- @signup = Signup.new(signup_params)
-
- if @signup.complete
- redirect_to landing_url(script_name: @signup.account.slug)
- else
- render :new, status: :unprocessable_entity
- end
- end
-
- private
- def signup_params
- params.expect(signup: %i[ full_name ]).with_defaults(identity: Current.identity)
- end
-end
diff --git a/gems/fizzy-saas/app/models/concerns/.keep b/gems/fizzy-saas/app/models/concerns/.keep
deleted file mode 100644
index e69de29bb..000000000
diff --git a/gems/fizzy-saas/app/models/signup.rb b/gems/fizzy-saas/app/models/signup.rb
deleted file mode 100644
index ca76f5b08..000000000
--- a/gems/fizzy-saas/app/models/signup.rb
+++ /dev/null
@@ -1,127 +0,0 @@
-class Signup
- include ActiveModel::Model
- include ActiveModel::Attributes
- include ActiveModel::Validations
-
- attr_accessor :full_name, :email_address, :identity
- attr_reader :queenbee_account, :account, :user
-
- with_options on: :completion do
- validates_presence_of :full_name, :identity
- end
-
- def initialize(...)
- @full_name = nil
- @email_address = nil
- @account = nil
- @user = nil
- @queenbee_account = nil
- @identity = nil
-
- super
-
- @email_address = @identity.email_address if @identity
- end
-
- def create_identity
- @identity = Identity.find_or_create_by!(email_address: email_address)
- @identity.send_magic_link
- end
-
- def complete
- if valid?(:completion)
- begin
- create_queenbee_account
- create_account
-
- true
- rescue => error
- destroy_account
- destroy_queenbee_account
-
- errors.add(:base, "Something went wrong, and we couldn't create your account. Please give it another try.")
- Rails.error.report(error, severity: :error)
- Rails.logger.error error
- Rails.logger.error error.backtrace.join("\n")
-
- false
- end
- else
- false
- end
- end
-
- private
- def create_queenbee_account
- @account_name = AccountNameGenerator.new(identity: identity, name: full_name).generate
- @queenbee_account = Queenbee::Remote::Account.create!(queenbee_account_attributes)
- @tenant = queenbee_account.id.to_s
- end
-
- def destroy_queenbee_account
- @queenbee_account&.cancel
- @queenbee_account = nil
- end
-
- def create_account
- @account = Account.create_with_admin_user(
- account: {
- external_account_id: @tenant,
- name: @account_name
- },
- owner: {
- name: full_name,
- identity: identity
- }
- )
- @user = @account.users.find_by!(role: :admin)
- @account.setup_customer_template
- end
-
- def destroy_account
- @account&.destroy!
-
- @user = nil
- @account = nil
- @tenant = nil
- end
-
- def queenbee_account_attributes
- {}.tap do |attributes|
- attributes[:product_name] = "fizzy"
- attributes[:name] = @account_name
- attributes[:owner_name] = full_name
- attributes[:owner_email] = email_address
-
- attributes[:trial] = true
- attributes[:subscription] = subscription_attributes
- attributes[:remote_request] = request_attributes
-
- # # TODO: Terms of Service
- # attributes[:terms_of_service] = true
-
- # We've confirmed the email
- attributes[:auto_allow] = true
-
- # Tell Queenbee to skip the request to create a local account. We've created it ourselves.
- attributes[:skip_remote] = true
- end
- end
-
- def subscription_attributes
- subscription = FreeV1Subscription
-
- {}.tap do |attributes|
- attributes[:name] = subscription.to_param
- attributes[:price] = subscription.price
- end
- end
-
- def request_attributes
- {}.tap do |attributes|
- attributes[:remote_address] = Current.ip_address
- attributes[:user_agent] = Current.user_agent
- attributes[:referrer] = Current.referrer
- end
- end
-end
diff --git a/gems/fizzy-saas/app/models/signup/account_name_generator.rb b/gems/fizzy-saas/app/models/signup/account_name_generator.rb
deleted file mode 100644
index a6844d3a3..000000000
--- a/gems/fizzy-saas/app/models/signup/account_name_generator.rb
+++ /dev/null
@@ -1,53 +0,0 @@
-class Signup::AccountNameGenerator
- SUFFIX = "Fizzy".freeze
-
- attr_reader :identity, :name
-
- def initialize(identity:, name:)
- @identity = identity
- @name = name
- end
-
- def generate
- next_index = current_index + 1
-
- if next_index == 1
- "#{prefix} #{SUFFIX}"
- else
- "#{prefix} #{next_index.ordinalize} #{SUFFIX}"
- end
- end
-
- private
- def current_index
- existing_indices.max || 0
- end
-
- def existing_indices
- Current.without_account do
- identity.accounts.filter_map do |account|
- if account.name.match?(first_account_name_regex)
- 1
- elsif match = account.name.match(nth_account_name_regex)
- match[1].to_i
- end
- end
- end
- end
-
- def first_account_name_regex
- @first_account_name_regex ||= /\A#{prefix}\s+#{SUFFIX}\Z/i
- end
-
- def nth_account_name_regex
- @nth_account_name_regex ||= /\A#{prefix}\s+(1st|2nd|3rd|\d+th)\s+#{SUFFIX}/i
- end
-
- def prefix
- @prefix ||= "#{first_name}'s"
- end
-
- def first_name
- name.strip.split(" ", 2).first
- end
-end
diff --git a/gems/fizzy-saas/app/models/subscription.rb b/gems/fizzy-saas/app/models/subscription.rb
deleted file mode 100644
index 5efb1a7fa..000000000
--- a/gems/fizzy-saas/app/models/subscription.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-class Subscription < Queenbee::Subscription
- SHORT_NAMES = %w[ FreeV1 ]
-
- def self.short_name
- name.demodulize
- end
-
- class FreeV1 < Subscription
- property :proper_name, "Free Subscription"
- property :price, 0
- property :frequency, "yearly"
- end
-end
diff --git a/gems/fizzy-saas/app/views/layouts/fizzy/saas/application.html.erb b/gems/fizzy-saas/app/views/layouts/fizzy/saas/application.html.erb
deleted file mode 100644
index 144b37838..000000000
--- a/gems/fizzy-saas/app/views/layouts/fizzy/saas/application.html.erb
+++ /dev/null
@@ -1,17 +0,0 @@
-
-
-
- Fizzy saas
- <%= csrf_meta_tags %>
- <%= csp_meta_tag %>
-
- <%= yield :head %>
-
- <%= stylesheet_link_tag "fizzy/saas/application", media: "all" %>
-
-
-
-<%= yield %>
-
-
-
diff --git a/gems/fizzy-saas/app/views/signup/completions/new.html.erb b/gems/fizzy-saas/app/views/signup/completions/new.html.erb
deleted file mode 100644
index aee8f4586..000000000
--- a/gems/fizzy-saas/app/views/signup/completions/new.html.erb
+++ /dev/null
@@ -1,30 +0,0 @@
-<% @page_title = "Complete your sign-up" %>
-
-">
-
<%= @page_title %>
-
- <%= form_with model: @signup, url: saas.signup_completion_path, scope: "signup", class: "flex flex-column gap", data: { controller: "form" } do |form| %>
- <%= form.text_field :full_name, class: "input txt-large", autocomplete: "name", placeholder: "Enter your full name…", autofocus: true, required: true %>
-
-
You’re one step away. Just enter your name to get your own Fizzy account.
-
- <% if @signup.errors.any? %>
-
-
- <% @signup.errors.full_messages.each do |message| %>
- - <%= message %>
- <% end %>
-
-
- <% end %>
-
-
- <% end %>
-
-
-<% content_for :footer do %>
- <%= render "sessions/footer" %>
-<% end %>
diff --git a/gems/fizzy-saas/app/views/signup/new.html.erb b/gems/fizzy-saas/app/views/signup/new.html.erb
deleted file mode 100644
index 93166dd2f..000000000
--- a/gems/fizzy-saas/app/views/signup/new.html.erb
+++ /dev/null
@@ -1,28 +0,0 @@
-<% @page_title = "Sign up for Fizzy" %>
-
-">
-
Sign up
-
- <%= form_with model: @signup, url: saas.signup_path, scope: "signup", class: "flex flex-column gap", data: { turbo: false, controller: "form" } do |form| %>
- <%= form.email_field :email_address, class: "input", autocomplete: "username", placeholder: "Email address", required: true %>
-
- <% if @signup.errors.any? %>
-
-
- <% @signup.errors.full_messages.each do |message| %>
- - <%= message %>
- <% end %>
-
-
- <% end %>
-
-
- <% end %>
-
-
-<% content_for :footer do %>
- <%= render "sessions/footer" %>
-<% end %>
diff --git a/gems/fizzy-saas/bin/rails b/gems/fizzy-saas/bin/rails
deleted file mode 100755
index 42a0e5bce..000000000
--- a/gems/fizzy-saas/bin/rails
+++ /dev/null
@@ -1,14 +0,0 @@
-#!/usr/bin/env ruby
-# This command will automatically be run when you run "rails" with Rails gems
-# installed from the root of your application.
-
-ENGINE_ROOT = File.expand_path("..", __dir__)
-ENGINE_PATH = File.expand_path("../lib/fizzy/saas/engine", __dir__)
-APP_PATH = File.expand_path("../test/dummy/config/application", __dir__)
-
-# Set up gems listed in the Gemfile.
-ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
-require "bundler/setup" if File.exist?(ENV["BUNDLE_GEMFILE"])
-
-require "rails/all"
-require "rails/engine/commands"
diff --git a/gems/fizzy-saas/bin/rubocop b/gems/fizzy-saas/bin/rubocop
deleted file mode 100755
index 40330c0ff..000000000
--- a/gems/fizzy-saas/bin/rubocop
+++ /dev/null
@@ -1,8 +0,0 @@
-#!/usr/bin/env ruby
-require "rubygems"
-require "bundler/setup"
-
-# explicit rubocop config increases performance slightly while avoiding config confusion.
-ARGV.unshift("--config", File.expand_path("../.rubocop.yml", __dir__))
-
-load Gem.bin_path("rubocop", "rubocop")
diff --git a/gems/fizzy-saas/config/database.yml b/gems/fizzy-saas/config/database.yml
deleted file mode 100644
index 3c68fd081..000000000
--- a/gems/fizzy-saas/config/database.yml
+++ /dev/null
@@ -1,100 +0,0 @@
-<%
- if ENV["MIGRATE"].present?
- mysql_app_user_key = "MYSQL_ALTER_USER"
- mysql_app_password_key = "MYSQL_ALTER_PASSWORD"
- else
- mysql_app_user_key = "MYSQL_APP_USER"
- mysql_app_password_key = "MYSQL_APP_PASSWORD"
- end
-
- mysql_app_user = ENV[mysql_app_user_key]
- mysql_app_password = ENV[mysql_app_password_key]
-%>
-
-default: &default
- adapter: trilogy
- host: <%= ENV.fetch "FIZZY_DB_HOST", "127.0.0.1" %>
- port: <%= ENV.fetch "FIZZY_DB_PORT", 3306 %>
- pool: 50
- timeout: 5000
- variables:
- transaction_isolation: READ-COMMITTED
-
-development:
- primary:
- <<: *default
- database: fizzy_development
- port: <%= ENV.fetch "FIZZY_DB_PORT", 33380 %>
- replica:
- <<: *default
- database: fizzy_development
- port: <%= ENV.fetch "FIZZY_DB_PORT", 33380 %>
- replica: true
- cable:
- <<: *default
- database: development_cable
- port: <%= ENV.fetch "FIZZY_DB_PORT", 33380 %>
- migrations_paths: db/cable_migrate
- cache:
- <<: *default
- database: development_cache
- port: <%= ENV.fetch "FIZZY_DB_PORT", 33380 %>
- migrations_paths: db/cache_migrate
- queue:
- <<: *default
- database: development_queue
- port: <%= ENV.fetch "FIZZY_DB_PORT", 33380 %>
- migrations_paths: db/queue_migrate
-
-# Warning: The database defined as "test" will be erased and
-# re-generated from your development database when you run "rake".
-# Do not set this db to the same as development or production.
-test:
- primary:
- <<: *default
- database: fizzy_test
- port: <%= ENV.fetch "FIZZY_DB_PORT", 33380 %>
- replica:
- <<: *default
- database: fizzy_test
- port: <%= ENV.fetch "FIZZY_DB_PORT", 33380 %>
- replica: true
-
-production: &production
- primary:
- <<: *default
- database: fizzy_production
- host: <%= ENV["MYSQL_DATABASE_HOST"] %>
- username: <%= mysql_app_user %>
- password: <%= mysql_app_password %>
- replica:
- <<: *default
- database: fizzy_production
- host: <%= ENV["MYSQL_DATABASE_REPLICA_HOST"] %>
- username: <%= ENV["MYSQL_READONLY_USER"] %>
- password: <%= ENV["MYSQL_READONLY_PASSWORD"] %>
- replica: true
- cable:
- <<: *default
- database: fizzy_solidcable_production
- host: <%= ENV["MYSQL_SOLID_CABLE_HOST"] %>
- username: <%= mysql_app_user %>
- password: <%= mysql_app_password %>
- migrations_paths: db/cable_migrate
- queue:
- <<: *default
- database: fizzy_solidqueue_production
- host: <%= ENV["MYSQL_SOLID_QUEUE_HOST"] %>
- username: <%= mysql_app_user %>
- password: <%= mysql_app_password %>
- migrations_paths: db/queue_migrate
- cache:
- <<: *default
- database: fizzy_solidcache_production
- host: <%= ENV["MYSQL_SOLID_CACHE_HOST"] %>
- username: <%= mysql_app_user %>
- password: <%= mysql_app_password %>
- migrations_paths: db/cache_migrate
-
-beta: *production
-staging: *production
diff --git a/gems/fizzy-saas/config/deploy.beta.yml b/gems/fizzy-saas/config/deploy.beta.yml
deleted file mode 100644
index 4c4c323f6..000000000
--- a/gems/fizzy-saas/config/deploy.beta.yml
+++ /dev/null
@@ -1,53 +0,0 @@
-servers:
- web:
- hosts:
- - fizzy-beta-app-01.sc-chi-int.37signals.com: sc_chi
- - fizzy-beta-app-101.df-iad-int.37signals.com: df_iad
- labels:
- otel_scrape_enabled: true
-
-# we don't run the jobs role in beta
-allow_empty_roles: true
-
-proxy:
- ssl: false
-
-ssh:
- user: app
-
-env:
- clear:
- RAILS_ENV: beta
- MYSQL_DATABASE_HOST: fizzy-mysql-primary
- MYSQL_DATABASE_REPLICA_HOST: fizzy-mysql-replica
- MYSQL_SOLID_CABLE_HOST: fizzy-mysql-primary
- MYSQL_SOLID_QUEUE_HOST: fizzy-mysql-primary
- MYSQL_SOLID_CACHE_HOST: fizzy-beta-solidcache-db-101
- secret:
- - RAILS_MASTER_KEY
- - MYSQL_ALTER_PASSWORD
- - MYSQL_ALTER_USER
- - MYSQL_APP_PASSWORD
- - MYSQL_APP_USER
- - MYSQL_READONLY_PASSWORD
- - MYSQL_READONLY_USER
- tags:
- sc_chi: {}
- df_iad:
- PRIMARY_DATACENTER: true
- df_ams: {}
-
-accessories:
- load-balancer:
- image: basecamp/kamal-proxy:lb
- host: fizzy-beta-lb-01.sc-chi-int.37signals.com
- labels:
- otel_role: load-balancer
- otel_service: fizzy-load-balancer
- otel_scrape_enabled: true
- options:
- publish:
- - 80:80
- - 443:443
- volumes:
- - load-balancer:/home/kamal-proxy/.config/kamal-proxy
diff --git a/gems/fizzy-saas/config/deploy.dhh.yml b/gems/fizzy-saas/config/deploy.dhh.yml
deleted file mode 100644
index 05bf874d4..000000000
--- a/gems/fizzy-saas/config/deploy.dhh.yml
+++ /dev/null
@@ -1,12 +0,0 @@
-servers:
- web:
- hosts:
- - test-1
- jobs:
- hosts:
- - test-1
-env:
- clear:
- ARTENANT: test
-
-proxy: false
diff --git a/gems/fizzy-saas/config/deploy.production.yml b/gems/fizzy-saas/config/deploy.production.yml
deleted file mode 100644
index 495227c1f..000000000
--- a/gems/fizzy-saas/config/deploy.production.yml
+++ /dev/null
@@ -1,72 +0,0 @@
-servers:
- web:
- hosts:
- - fizzy-app-01.sc-chi-int.37signals.com: sc_chi
- - fizzy-app-02.sc-chi-int.37signals.com: sc_chi
- - fizzy-app-101.df-iad-int.37signals.com: df_iad
- - fizzy-app-102.df-iad-int.37signals.com: df_iad
- - fizzy-app-401.df-ams-int.37signals.com: df_ams
- - fizzy-app-402.df-ams-int.37signals.com: df_ams
- labels:
- otel_scrape_enabled: true
- jobs:
- hosts:
- - fizzy-jobs-101.df-iad-int.37signals.com: df_iad
- - fizzy-jobs-102.df-iad-int.37signals.com: df_iad
- labels:
- otel_scrape_enabled: true
-
-proxy:
- ssl: false
-
-ssh:
- user: app
-
-env:
- clear:
- RAILS_ENV: production
- MYSQL_DATABASE_HOST: fizzy-mysql-primary
- MYSQL_DATABASE_REPLICA_HOST: fizzy-mysql-replica
- MYSQL_SOLID_CABLE_HOST: fizzy-mysql-primary
- MYSQL_SOLID_QUEUE_HOST: fizzy-mysql-primary
- secret:
- - RAILS_MASTER_KEY
- - MYSQL_ALTER_PASSWORD
- - MYSQL_ALTER_USER
- - MYSQL_APP_PASSWORD
- - MYSQL_APP_USER
- - MYSQL_READONLY_PASSWORD
- - MYSQL_READONLY_USER
- tags:
- sc_chi:
- MYSQL_SOLID_CACHE_HOST: fizzy-solidcache-db-01.sc-chi-int.37signals.com
- df_iad:
- MYSQL_SOLID_CACHE_HOST: fizzy-solidcache-db-101.df-iad-int.37signals.com
- PRIMARY_DATACENTER: true
- df_ams:
- MYSQL_SOLID_CACHE_HOST: fizzy-solidcache-db-401.df-ams-int.37signals.com
-
-
-accessories:
- load-balancer:
- image: basecamp/kamal-proxy:lb
- hosts:
- - fizzy-lb-101.df-iad-int.37signals.com
- - fizzy-lb-102.df-iad-int.37signals.com
- - fizzy-lb-01.sc-chi-int.37signals.com
- - fizzy-lb-02.sc-chi-int.37signals.com
- - fizzy-lb-401.df-ams-int.37signals.com
- - fizzy-lb-402.df-ams-int.37signals.com
- labels:
- otel_role: load-balancer
- otel_service: fizzy-load-balancer
- otel_scrape_enabled: true
- options:
- publish:
- - 80:80
- - 443:443
- # NFS mount for certificates
- # See https://3.basecamp.com/2914079/buckets/37331921/todos/9180260061
- mount: type=volume,src=certificates,dst=/certificates,volume-driver=local,volume-opt=type=nfs,volume-opt=device=:/fizzy-production-certificates,"volume-opt=o=addr=purestorage.sc-chi-int.37signals.com,nfsvers=3,rw,noatime,nconnect=8,soft,timeo=30,retrans=2"
- volumes:
- - load-balancer:/home/kamal-proxy/.config/kamal-proxy
diff --git a/gems/fizzy-saas/config/deploy.staging.yml b/gems/fizzy-saas/config/deploy.staging.yml
deleted file mode 100644
index 3163c7a7b..000000000
--- a/gems/fizzy-saas/config/deploy.staging.yml
+++ /dev/null
@@ -1,69 +0,0 @@
-servers:
- web:
- hosts:
- - fizzy-staging-app-101.df-iad-int.37signals.com: df_iad
- - fizzy-staging-app-102.df-iad-int.37signals.com: df_iad
- - fizzy-staging-app-01.sc-chi-int.37signals.com: sc_chi
- - fizzy-staging-app-02.sc-chi-int.37signals.com: sc_chi
- - fizzy-staging-app-401.df-ams-int.37signals.com: df_ams
- - fizzy-staging-app-402.df-ams-int.37signals.com: df_ams
- labels:
- otel_scrape_enabled: true
- jobs:
- hosts:
- - fizzy-staging-jobs-101.df-iad-int.37signals.com: df_iad
- - fizzy-staging-jobs-102.df-iad-int.37signals.com: df_iad
- labels:
- otel_scrape_enabled: true
-
-proxy:
- ssl: false
-
-ssh:
- user: app
-
-env:
- clear:
- RAILS_ENV: staging
- MYSQL_DATABASE_HOST: fizzy-staging-mysql-primary
- MYSQL_DATABASE_REPLICA_HOST: fizzy-staging-mysql-replica
- MYSQL_SOLID_CABLE_HOST: fizzy-staging-mysql-primary
- MYSQL_SOLID_QUEUE_HOST: fizzy-staging-mysql-primary
- secret:
- - RAILS_MASTER_KEY
- - MYSQL_ALTER_PASSWORD
- - MYSQL_ALTER_USER
- - MYSQL_APP_PASSWORD
- - MYSQL_APP_USER
- - MYSQL_READONLY_PASSWORD
- - MYSQL_READONLY_USER
- tags:
- sc_chi:
- MYSQL_SOLID_CACHE_HOST: fizzy-staging-solidcache-db-01.sc-chi-int.37signals.com
- df_iad:
- MYSQL_SOLID_CACHE_HOST: fizzy-staging-solidcache-db-101.df-iad-int.37signals.com
- PRIMARY_DATACENTER: true
- df_ams:
- MYSQL_SOLID_CACHE_HOST: fizzy-staging-solidcache-db-401.df-ams-int.37signals.com
-
-
-accessories:
- load-balancer:
- image: basecamp/kamal-proxy:lb
- hosts:
- - fizzy-staging-lb-01.sc-chi-int.37signals.com
- - fizzy-staging-lb-101.df-iad-int.37signals.com
- - fizzy-staging-lb-401.df-ams-int.37signals.com
- labels:
- otel_role: load-balancer
- otel_service: fizzy-load-balancer
- otel_scrape_enabled: true
- options:
- publish:
- - 80:80
- - 443:443
- # NFS mount for certificates
- # See https://3.basecamp.com/2914079/buckets/37331921/todos/9180260061
- mount: type=volume,src=certificates,dst=/certificates,volume-driver=local,volume-opt=type=nfs,volume-opt=device=:/fizzy-staging-certificates,"volume-opt=o=addr=purestorage.sc-chi-int.37signals.com,nfsvers=3,rw,noatime,nconnect=8,soft,timeo=30,retrans=2"
- volumes:
- - load-balancer:/home/kamal-proxy/.config/kamal-proxy
diff --git a/gems/fizzy-saas/config/deploy.yml b/gems/fizzy-saas/config/deploy.yml
deleted file mode 100644
index ea3ca3c49..000000000
--- a/gems/fizzy-saas/config/deploy.yml
+++ /dev/null
@@ -1,35 +0,0 @@
-service: fizzy
-image: basecamp/fizzy
-asset_path: /rails/public/assets
-hooks_path: <%= File.join(Gem::Specification.find_by_name("fizzy-saas").gem_dir, ".kamal", "hooks") %>
-
-servers:
- jobs:
- cmd: bin/jobs
-
-volumes:
- - fizzy:/rails/storage
-
-proxy:
- ssl: true
-
-registry:
- server: registry.37signals.com
- username: robot$harbor-bot
- password:
- - BASECAMP_REGISTRY_PASSWORD
-
-builder:
- arch: amd64
- secrets:
- - GITHUB_TOKEN
- remote: ssh://app@docker-builder-102
- local: <%= ENV.fetch("KAMAL_BUILDER_LOCAL", "true") %>
-
-env:
- secret:
- - RAILS_MASTER_KEY
-
-aliases:
- console: app exec -i --reuse "bin/rails console"
- ssh: app exec -i --reuse /bin/bash
diff --git a/gems/fizzy-saas/config/routes.rb b/gems/fizzy-saas/config/routes.rb
deleted file mode 100644
index 2b9639edb..000000000
--- a/gems/fizzy-saas/config/routes.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-Fizzy::Saas::Engine.routes.draw do
- get "/signup/new", to: redirect("/session/new")
-
- namespace :signup do
- resource :completion, only: %i[ new create ]
- end
-
- Queenbee.routes(self)
-end
diff --git a/gems/fizzy-saas/fizzy-saas.gemspec b/gems/fizzy-saas/fizzy-saas.gemspec
deleted file mode 100644
index f1b28de00..000000000
--- a/gems/fizzy-saas/fizzy-saas.gemspec
+++ /dev/null
@@ -1,27 +0,0 @@
-require_relative "lib/fizzy/saas/version"
-
-Gem::Specification.new do |spec|
- spec.name = "fizzy-saas"
- spec.version = Fizzy::Saas::VERSION
- spec.authors = [ "Mike Dalessio" ]
- spec.email = [ "mike@37signals.com" ]
- spec.homepage = "TODO"
- spec.summary = "TODO: Summary of Fizzy::Saas."
- spec.description = "TODO: Description of Fizzy::Saas."
-
- # Prevent pushing this gem to RubyGems.org. To allow pushes either set the "allowed_push_host"
- # to allow pushing to a single host or delete this section to allow pushing to any host.
- spec.metadata["allowed_push_host"] = "TODO: Set to 'http://mygemserver.com'"
-
- spec.metadata["homepage_uri"] = spec.homepage
- spec.metadata["source_code_uri"] = "TODO: Put your gem's public repo URL here."
- spec.metadata["changelog_uri"] = "TODO: Put your gem's CHANGELOG.md URL here."
-
- spec.files = Dir.chdir(File.expand_path(__dir__)) do
- Dir["{app,config,db,lib}/**/*", "MIT-LICENSE", "Rakefile", "README.md"]
- end
-
- spec.add_dependency "rails", ">= 8.1.0.beta1"
- spec.add_dependency "queenbee"
- spec.add_dependency "rails_structured_logging"
-end
diff --git a/gems/fizzy-saas/lib/fizzy/saas.rb b/gems/fizzy-saas/lib/fizzy/saas.rb
deleted file mode 100644
index dd0d35492..000000000
--- a/gems/fizzy-saas/lib/fizzy/saas.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-require "fizzy/saas/version"
-require "fizzy/saas/engine"
-
-module Fizzy
- module Saas
- end
-end
diff --git a/gems/fizzy-saas/lib/fizzy/saas/engine.rb b/gems/fizzy-saas/lib/fizzy/saas/engine.rb
deleted file mode 100644
index 14ce03759..000000000
--- a/gems/fizzy-saas/lib/fizzy/saas/engine.rb
+++ /dev/null
@@ -1,31 +0,0 @@
-require_relative "metrics"
-require_relative "transaction_pinning"
-
-module Fizzy
- module Saas
- class Engine < ::Rails::Engine
- # moved from config/initializers/queenbee.rb
- Queenbee.host_app = Fizzy
-
- initializer "fizzy_saas.transaction_pinning" do |app|
- if ActiveRecord::Base.replica_configured?
- app.config.middleware.insert_after(
- ActiveRecord::Middleware::DatabaseSelector,
- TransactionPinning::Middleware
- )
- end
- end
-
- config.to_prepare do
- Queenbee::Subscription.short_names = Subscription::SHORT_NAMES
- Queenbee::ApiToken.token = Rails.application.credentials.dig(:queenbee_api_token)
-
- Subscription::SHORT_NAMES.each do |short_name|
- const_name = "#{short_name}Subscription"
- ::Object.send(:remove_const, const_name) if ::Object.const_defined?(const_name)
- ::Object.const_set const_name, Subscription.const_get(short_name, false)
- end
- end
- end
- end
-end
diff --git a/gems/fizzy-saas/lib/fizzy/saas/metrics.rb b/gems/fizzy-saas/lib/fizzy/saas/metrics.rb
deleted file mode 100644
index 80a2bc194..000000000
--- a/gems/fizzy-saas/lib/fizzy/saas/metrics.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-Yabeda.configure do
- SHORT_HISTOGRAM_BUCKETS = [ 0.001, 0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5 ]
-
- group :fizzy do
- counter :replica_stale,
- comment: "Number of requests served from a stale replica"
-
- histogram :replica_wait,
- unit: :seconds,
- comment: "Time spent waiting for replica to catch up with transaction",
- buckets: SHORT_HISTOGRAM_BUCKETS
- end
-end
diff --git a/gems/fizzy-saas/lib/fizzy/saas/transaction_pinning.rb b/gems/fizzy-saas/lib/fizzy/saas/transaction_pinning.rb
deleted file mode 100644
index ed3cf2060..000000000
--- a/gems/fizzy-saas/lib/fizzy/saas/transaction_pinning.rb
+++ /dev/null
@@ -1,65 +0,0 @@
-module TransactionPinning
- class Middleware
- SESSION_KEY = :last_txn
- DEFAULT_MAX_WAIT = 0.25
-
- def initialize(app)
- @app = app
- @timeout = Rails.application.config.x.transaction_pinning&.timeout&.to_f || DEFAULT_MAX_WAIT
- end
-
- def call(env)
- request = ActionDispatch::Request.new(env)
- replica_metrics = {}
-
- if ApplicationRecord.current_role == :reading
- wait_for_replica_catchup(request, replica_metrics)
- end
-
- status, headers, body = @app.call(env)
- headers.merge!(replica_metrics.transform_values(&:to_s))
-
- if ApplicationRecord.current_role == :writing
- capture_transaction_id(request)
- end
-
- [ status, headers, body ]
- end
-
- private
- def wait_for_replica_catchup(request, replica_metrics)
- if last_txn = request.session[SESSION_KEY].presence
- has_transaction = tracking_replica_wait_time(replica_metrics) do
- replica_has_transaction(last_txn)
- end
-
- unless has_transaction
- Yabeda.fizzy.replica_stale.increment
- replica_metrics["X-Replica-Stale"] = true
- end
- end
- end
-
- def capture_transaction_id(request)
- request.session[SESSION_KEY] = ApplicationRecord.connection.show_variable("global.gtid_executed")
- end
-
- def replica_has_transaction(txn)
- sql = ApplicationRecord.sanitize_sql_array([ "SELECT WAIT_FOR_EXECUTED_GTID_SET(?, ?)", txn, @timeout ])
- ApplicationRecord.connection.select_value(sql) == 0
- rescue => e
- Sentry.capture_exception(e, extra: { gtid: txn })
- true # Treat as if we're up to date, since we don't know
- end
-
- def tracking_replica_wait_time(replica_metrics)
- started_at = Time.current
-
- Yabeda.fizzy.replica_wait.measure do
- yield
- end.tap do
- replica_metrics["X-Replica-Wait"] = Time.current - started_at
- end
- end
- end
-end
diff --git a/gems/fizzy-saas/lib/fizzy/saas/version.rb b/gems/fizzy-saas/lib/fizzy/saas/version.rb
deleted file mode 100644
index 7a95d2d05..000000000
--- a/gems/fizzy-saas/lib/fizzy/saas/version.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-module Fizzy
- module Saas
- VERSION = "0.1.0"
- end
-end
diff --git a/gems/fizzy-saas/lib/tasks/fizzy/saas_tasks.rake b/gems/fizzy-saas/lib/tasks/fizzy/saas_tasks.rake
deleted file mode 100644
index 8fe948d94..000000000
--- a/gems/fizzy-saas/lib/tasks/fizzy/saas_tasks.rake
+++ /dev/null
@@ -1,4 +0,0 @@
-# desc "Explaining what the task does"
-# task :fizzy_saas do
-# # Task goes here
-# end
diff --git a/gems/fizzy-saas/test/controllers/.keep b/gems/fizzy-saas/test/controllers/.keep
deleted file mode 100644
index e69de29bb..000000000
diff --git a/gems/fizzy-saas/test/controllers/signups/completions_controller_test.rb b/gems/fizzy-saas/test/controllers/signups/completions_controller_test.rb
deleted file mode 100644
index 49628a188..000000000
--- a/gems/fizzy-saas/test/controllers/signups/completions_controller_test.rb
+++ /dev/null
@@ -1,43 +0,0 @@
-require "test_helper"
-
-class Signup::CompletionsControllerTest < ActionDispatch::IntegrationTest
- setup do
- @signup = Signup.new(email_address: "newuser@example.com", full_name: "New User")
-
- @signup.create_identity || raise("Failed to create identity")
-
- sign_in_as @signup.identity
- end
-
- test "new" do
- untenanted do
- get saas.new_signup_completion_path
- end
-
- assert_response :success
- end
-
- test "create" do
- untenanted do
- post saas.signup_completion_path, params: {
- signup: {
- full_name: @signup.full_name
- }
- }
- end
-
- assert_response :redirect, "Valid params should redirect"
- end
-
- test "create with invalid params" do
- untenanted do
- post saas.signup_completion_path, params: {
- signup: {
- full_name: ""
- }
- }
- end
-
- assert_response :unprocessable_entity, "Invalid params should return unprocessable entity"
- end
-end
diff --git a/gems/fizzy-saas/test/fixtures/files/.keep b/gems/fizzy-saas/test/fixtures/files/.keep
deleted file mode 100644
index e69de29bb..000000000
diff --git a/gems/fizzy-saas/test/helpers/.keep b/gems/fizzy-saas/test/helpers/.keep
deleted file mode 100644
index e69de29bb..000000000
diff --git a/gems/fizzy-saas/test/integration/.keep b/gems/fizzy-saas/test/integration/.keep
deleted file mode 100644
index e69de29bb..000000000
diff --git a/gems/fizzy-saas/test/mailers/.keep b/gems/fizzy-saas/test/mailers/.keep
deleted file mode 100644
index e69de29bb..000000000
diff --git a/gems/fizzy-saas/test/models/.keep b/gems/fizzy-saas/test/models/.keep
deleted file mode 100644
index e69de29bb..000000000
diff --git a/gems/fizzy-saas/test/models/signup/account_name_generator_test.rb b/gems/fizzy-saas/test/models/signup/account_name_generator_test.rb
deleted file mode 100644
index d22922b29..000000000
--- a/gems/fizzy-saas/test/models/signup/account_name_generator_test.rb
+++ /dev/null
@@ -1,61 +0,0 @@
-require "test_helper"
-
-class Signup::AccountNameGeneratorTest < ActiveSupport::TestCase
- setup do
- @identity = Identity.create!(email_address: "newart.userbaum@example.com")
- @name = "Newart userbaum"
- @generator = Signup::AccountNameGenerator.new(identity: @identity, name: @name)
- end
-
- test "generate" do
- account_name = @generator.generate
- assert_equal "Newart's Fizzy", account_name, "The 1st account doesn't have 1st in the name"
-
- first_account = Account.create!(external_account_id: "1st", name: account_name)
- Current.without_account do
- @identity.users.create!(account: first_account, name: @name)
- @identity.reload
- end
-
- account_name = @generator.generate
- assert_equal "Newart's 2nd Fizzy", account_name
-
- second_account = Account.create!(external_account_id: "2nd", name: account_name)
- Current.without_account do
- @identity.users.create!(account: second_account, name: @name)
- @identity.reload
- end
-
- account_name = @generator.generate
- assert_equal "Newart's 3rd Fizzy", account_name
-
- third_account = Account.create!(external_account_id: "3rd", name: account_name)
- Current.without_account do
- @identity.users.create!(account: third_account, name: @name)
- @identity.reload
- end
-
- account_name = @generator.generate
- assert_equal "Newart's 4th Fizzy", account_name
-
- fourth_account = Account.create!(external_account_id: "4th", name: account_name)
- Current.without_account do
- @identity.users.create!(account: fourth_account, name: @name)
- @identity.reload
- end
-
- account_name = @generator.generate
- assert_equal "Newart's 5th Fizzy", account_name
- end
-
- test "generate continues from the previous highest index" do
- account = Account.create!(external_account_id: "12th", name: "Newart's 12th Fizzy")
- Current.without_account do
- @identity.users.create!(account: account, name: @name)
- @identity.reload
- end
-
- account_name = @generator.generate
- assert_equal "Newart's 13th Fizzy", account_name
- end
-end
diff --git a/gems/fizzy-saas/test/models/signup_test.rb b/gems/fizzy-saas/test/models/signup_test.rb
deleted file mode 100644
index 69c0e699f..000000000
--- a/gems/fizzy-saas/test/models/signup_test.rb
+++ /dev/null
@@ -1,53 +0,0 @@
-require "test_helper"
-
-class SignupTest < ActiveSupport::TestCase
- test "#create_identity" do
- signup = Signup.new(email_address: "brian@example.com")
-
- assert_difference -> { Identity.count }, 1 do
- assert_difference -> { MagicLink.count }, 1 do
- assert signup.create_identity
- end
- end
-
- assert_empty signup.errors
- assert signup.identity
- assert signup.identity.persisted?
-
- signup_existing = Signup.new(email_address: "brian@example.com")
-
- assert_no_difference -> { Identity.count } do
- assert_difference -> { MagicLink.count }, 1 do
- assert signup_existing.create_identity, "Should send magic link for existing identity"
- end
- end
-
- signup_invalid = Signup.new(email_address: "")
- assert_raises do
- signup_invalid.create_identity
- end
- end
-
- test "#complete" do
- Account.any_instance.expects(:setup_customer_template).once
- Current.without_account do
- signup = Signup.new(
- full_name: "Kevin",
- identity: identities(:kevin)
- )
-
- assert signup.complete
-
- assert signup.account
- assert signup.user
- assert_equal "Kevin", signup.user.name
-
- signup_invalid = Signup.new(
- full_name: "",
- identity: identities(:kevin)
- )
- assert_not signup_invalid.complete
- assert_not_empty signup_invalid.errors[:full_name]
- end
- end
-end
diff --git a/gems/fizzy-saas/test/test_helper.rb b/gems/fizzy-saas/test/test_helper.rb
deleted file mode 100644
index eeaf24954..000000000
--- a/gems/fizzy-saas/test/test_helper.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-require "queenbee/testing/mocks"
-
-Queenbee::Remote::Account.class_eval do
- # because we use the account ID as the tenant name, we need it to be unique in each test to avoid
- # parallelized tests clobbering each other.
- def next_id
- super + Random.rand(1000000)
- end
-end