rails-saas-builder 0.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 64d5d9b5bed88acac2449b7eed3c55dae27a67d9ee4466182125fd0ece98e676
4
+ data.tar.gz: 115928cdba7390516837f6d9e169d4baa65d8f68c45021bb4ee9a4dd3e768632
5
+ SHA512:
6
+ metadata.gz: 962b88b8300c90680851fd0c6f8754f5d840875ace281659b16fd2195832041a3acdcd2e91167e3bbf9f8fcda535d3112eb894acc1e7c7ab38c8322092e70514
7
+ data.tar.gz: f222b0912df9c0028afdcb282b18f9dda0674f83ebbba7f4f89a56350600106ad127884096141b82f81b8baeb28bfe364bd16d39c0c5a7e312b413c9cf51adc8
data/LICENSE ADDED
@@ -0,0 +1,15 @@
1
+ Rails SaaS Builder (RSB)
2
+ Copyright (C) 2026 Aleksandr Marchenko
3
+
4
+ This program is free software: you can redistribute it and/or modify
5
+ it under the terms of the GNU Lesser General Public License as published by
6
+ the Free Software Foundation, either version 3 of the License, or
7
+ (at your option) any later version.
8
+
9
+ This program is distributed in the hope that it will be useful,
10
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ GNU Lesser General Public License for more details.
13
+
14
+ You should have received a copy of the GNU Lesser General Public License
15
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
data/README.md ADDED
@@ -0,0 +1,89 @@
1
+ # Rails SaaS Builder
2
+
3
+ Full-stack SaaS framework for Rails. Modular, extensible, production-ready.
4
+
5
+ Rails SaaS Builder (RSB) is a collection of Rails engines that provide SaaS essentials out of the box. Built for Rails developers who need authentication with pluggable credentials, plan-based entitlements with usage tracking, an admin panel with role-based access control, and a dynamic settings system — all working together or independently. Use the umbrella gem for everything, or pick individual sub-gems for only what you need.
6
+
7
+ ## Quick Start
8
+
9
+ Add to your Gemfile:
10
+
11
+ ```ruby
12
+ gem "rails-saas-builder"
13
+ ```
14
+
15
+ Then run:
16
+
17
+ ```bash
18
+ bundle install
19
+ rails generate rails_saas_builder:install
20
+ rails db:migrate
21
+ rails rsb:create_admin EMAIL=admin@example.com PASSWORD=changeme
22
+ ```
23
+
24
+ Visit `/admin/login` to access the admin panel.
25
+ Visit `/auth/session/new` to sign in as a user.
26
+
27
+ ## Modular Architecture
28
+
29
+ RSB is composed of focused sub-gems. Use them all via `gem "rails-saas-builder"`, or pick only what you need.
30
+
31
+ ### Core Gems
32
+
33
+ | Gem | Purpose |
34
+ |-----|---------|
35
+ | [rsb-settings](rsb-settings/) | Dynamic runtime settings with schema registry |
36
+ | [rsb-auth](rsb-auth/) | Identity & authentication with pluggable credentials |
37
+ | [rsb-entitlements](rsb-entitlements/) | Plans, entitlements, and usage tracking |
38
+ | [rsb-admin](rsb-admin/) | Admin panel with dynamic RBAC |
39
+
40
+ ### Extension Gems
41
+
42
+ | Gem | Purpose |
43
+ |-----|---------|
44
+ | [rsb-entitlements-stripe](rsb-entitlements-stripe/) | Stripe payment provider for rsb-entitlements |
45
+
46
+ ## Requirements
47
+
48
+ - Ruby >= 3.2
49
+ - Rails >= 8.0
50
+
51
+ ## Development
52
+
53
+ Clone the repository and install dependencies:
54
+
55
+ ```bash
56
+ git clone https://github.com/Rails-SaaS-Builder/rails-saas-builder.git
57
+ cd rsb
58
+ bundle install
59
+ ```
60
+
61
+ Run the full test suite:
62
+
63
+ ```bash
64
+ bundle exec rake test
65
+ ```
66
+
67
+ Run a single gem's tests:
68
+
69
+ ```bash
70
+ bundle exec rake test_gem GEM=rsb-auth
71
+ ```
72
+
73
+ Run the linter:
74
+
75
+ ```bash
76
+ bundle exec rubocop
77
+ ```
78
+
79
+ ## Contributing
80
+
81
+ See [CONTRIBUTING.md](CONTRIBUTING.md) for development setup, coding standards, and how to submit pull requests.
82
+
83
+ ## Security
84
+
85
+ To report a security vulnerability, please see [SECURITY.md](SECURITY.md). Do not open public issues for security concerns.
86
+
87
+ ## License
88
+
89
+ Rails SaaS Builder is licensed under the [GNU Lesser General Public License v3.0](LICENSE).
data/Rakefile ADDED
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/setup'
4
+ require 'rake/testtask'
5
+
6
+ load File.expand_path('lib/tasks/release.rake', __dir__)
7
+
8
+ SUB_GEMS = %w[rsb-settings rsb-auth rsb-entitlements rsb-entitlements-stripe rsb-admin].freeze
9
+
10
+ desc 'Run tests for all sub-gems'
11
+ task :test_subgems do
12
+ SUB_GEMS.each do |gem_dir|
13
+ puts "\n#{'=' * 60}"
14
+ puts "Testing #{gem_dir}"
15
+ puts '=' * 60
16
+ Dir.chdir(gem_dir) do
17
+ sh 'bundle install --quiet'
18
+ sh 'bundle exec rake test'
19
+ end
20
+ end
21
+ end
22
+
23
+ Rake::TestTask.new(:test_integration) do |t|
24
+ t.libs << 'test'
25
+ t.pattern = 'test/integration/**/*_test.rb'
26
+ t.verbose = false
27
+ end
28
+
29
+ desc 'Run tests for a single sub-gem: rake test_gem GEM=rsb-admin'
30
+ task :test_gem do
31
+ gem_name = ENV['GEM'] || abort('Usage: rake test_gem GEM=rsb-admin')
32
+ abort("Unknown gem: #{gem_name}") unless SUB_GEMS.include?(gem_name)
33
+ Dir.chdir(gem_name) do
34
+ sh 'bundle install --quiet'
35
+ test_file = ENV['TEST']
36
+ if test_file
37
+ sh "bundle exec ruby -Itest #{test_file}"
38
+ else
39
+ sh 'bundle exec rake test'
40
+ end
41
+ end
42
+ end
43
+
44
+ desc 'Run all tests (sub-gems + integration)'
45
+ task test: %i[test_subgems test_integration]
46
+
47
+ task default: :test
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsSaasBuilder
4
+ class InstallGenerator < Rails::Generators::Base
5
+ desc 'Install Rails SaaS Builder: runs all sub-gem install generators.'
6
+
7
+ def install_settings
8
+ say 'Installing rsb-settings...', :green
9
+ generate 'rsb:settings:install'
10
+ end
11
+
12
+ def install_auth
13
+ say 'Installing rsb-auth...', :green
14
+ generate 'rsb:auth:install'
15
+ end
16
+
17
+ def install_entitlements
18
+ say 'Installing rsb-entitlements...', :green
19
+ generate 'rsb:entitlements:install'
20
+ end
21
+
22
+ def install_admin
23
+ say 'Installing rsb-admin...', :green
24
+ generate 'rsb:admin:install'
25
+ end
26
+
27
+ def print_post_install
28
+ say ''
29
+ say 'Rails SaaS Builder installed successfully!', :green
30
+ say ''
31
+ say 'Next steps:'
32
+ say ' 1. rails db:migrate'
33
+ say ' 2. rails rsb:create_admin EMAIL=admin@example.com PASSWORD=changeme'
34
+ say ' 3. Visit /admin/login for the admin panel'
35
+ say ' 4. Visit /auth/register for user registration'
36
+ say ''
37
+ say 'For documentation: https://github.com/Rails-SaaS-Builder/rails-saas-builder'
38
+ say ''
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails_saas_builder'
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rsb/version'
4
+ require 'rsb/settings'
5
+ require 'rsb/auth'
6
+ require 'rsb/entitlements'
7
+ require 'rsb/admin'
8
+
9
+ module RSB
10
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RSB
4
+ VERSION = '0.9.1'
5
+ end
@@ -0,0 +1,148 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'English'
4
+ PUBLISH_ORDER = [
5
+ { name: 'rsb-settings', dir: 'rsb-settings', gemspec: 'rsb-settings.gemspec' },
6
+ { name: 'rsb-auth', dir: 'rsb-auth', gemspec: 'rsb-auth.gemspec' },
7
+ { name: 'rsb-entitlements', dir: 'rsb-entitlements', gemspec: 'rsb-entitlements.gemspec' },
8
+ { name: 'rsb-admin', dir: 'rsb-admin', gemspec: 'rsb-admin.gemspec' },
9
+ { name: 'rails-saas-builder', dir: '.', gemspec: 'rails-saas-builder.gemspec' }
10
+ ].freeze
11
+
12
+ VERSION_FILE = 'lib/rsb/version.rb'
13
+
14
+ PKG_DIR = File.expand_path('pkg', __dir__.then { File.expand_path('../..', _1) })
15
+
16
+ module ReleaseHelper
17
+ module_function
18
+
19
+ def root
20
+ File.expand_path('../..', __dir__)
21
+ end
22
+
23
+ def current_version
24
+ content = File.read(File.join(root, VERSION_FILE))
25
+ content.match(/VERSION\s*=\s*['"]([^'"]+)['"]/)[1]
26
+ end
27
+
28
+ def next_version(current, bump)
29
+ major, minor, patch = current.split('.').map(&:to_i)
30
+ case bump.to_s
31
+ when 'major' then "#{major + 1}.0.0"
32
+ when 'minor' then "#{major}.#{minor + 1}.0"
33
+ when 'patch' then "#{major}.#{minor}.#{patch + 1}"
34
+ else abort "Unknown bump type: #{bump}. Use patch, minor, or major."
35
+ end
36
+ end
37
+
38
+ def update_version_file(new_version)
39
+ full_path = File.join(root, VERSION_FILE)
40
+ content = File.read(full_path)
41
+ updated = content.gsub(/VERSION\s*=\s*['"][^'"]+['"]/, "VERSION = '#{new_version}'")
42
+ File.write(full_path, updated)
43
+ puts " Updated #{VERSION_FILE} → #{new_version}"
44
+ end
45
+
46
+ def ensure_clean_git!
47
+ status = `git -C #{root} status --porcelain`.strip
48
+ abort 'Aborting: working tree is dirty. Commit or stash changes first.' unless status.empty?
49
+ end
50
+
51
+ def ensure_on_master!
52
+ branch = `git -C #{root} branch --show-current`.strip
53
+ abort "Aborting: not on master branch (currently on '#{branch}')." unless branch == 'master'
54
+ end
55
+
56
+ def ensure_tests_pass!
57
+ puts 'Running full test suite...'
58
+ return if system('bundle exec rake test', chdir: root)
59
+
60
+ abort 'Aborting: tests failed.'
61
+ end
62
+
63
+ def build_gem(gem_info)
64
+ FileUtils.mkdir_p(PKG_DIR)
65
+
66
+ gem_dir = File.join(root, gem_info[:dir])
67
+ gemspec = gem_info[:gemspec]
68
+
69
+ puts " Building #{gem_info[:name]}..."
70
+ output = `cd #{gem_dir} && gem build #{gemspec} 2>&1`
71
+ abort "Failed to build #{gem_info[:name]}:\n#{output}" unless $CHILD_STATUS.success?
72
+
73
+ gem_file = output.match(/File:\s*(.+\.gem)/)[1].strip
74
+ source = File.join(gem_dir, gem_file)
75
+ dest = File.join(PKG_DIR, gem_file)
76
+ FileUtils.mv(source, dest)
77
+ puts " Built #{dest}"
78
+ dest
79
+ end
80
+
81
+ def push_gem(gem_path)
82
+ name = File.basename(gem_path)
83
+ puts " Pushing #{name}..."
84
+ abort "Failed to push #{name}." unless system("gem push #{gem_path}")
85
+ puts " Pushed #{name}"
86
+ end
87
+
88
+ def build_all
89
+ puts "\nBuilding gems..."
90
+ PUBLISH_ORDER.map { |gem_info| build_gem(gem_info) }
91
+ end
92
+
93
+ def push_all(gem_paths)
94
+ puts "\nPushing gems to RubyGems.org..."
95
+ gem_paths.each { |path| push_gem(path) }
96
+ end
97
+ end
98
+
99
+ desc 'Build and push all gems to RubyGems.org (no version bump)'
100
+ task :publish do
101
+ version = ReleaseHelper.current_version
102
+ puts "Publishing v#{version}..."
103
+
104
+ gem_paths = ReleaseHelper.build_all
105
+ ReleaseHelper.push_all(gem_paths)
106
+
107
+ puts "\nPublished v#{version} successfully!"
108
+ end
109
+
110
+ desc 'Bump version, build, push gems, tag and push git (default: patch)'
111
+ task :release, [:bump] do |_t, args|
112
+ bump = args[:bump] || 'patch'
113
+ current = ReleaseHelper.current_version
114
+ new_version = ReleaseHelper.next_version(current, bump)
115
+
116
+ puts "Release: #{current} → #{new_version} (#{bump} bump)\n\n"
117
+
118
+ # Safety checks
119
+ ReleaseHelper.ensure_clean_git!
120
+ ReleaseHelper.ensure_on_master!
121
+ ReleaseHelper.ensure_tests_pass!
122
+
123
+ # Bump the single version file
124
+ puts "\nBumping version..."
125
+ ReleaseHelper.update_version_file(new_version)
126
+
127
+ # Git commit and tag
128
+ root = ReleaseHelper.root
129
+ puts "\nCommitting version bump..."
130
+ system("git -C #{root} add #{VERSION_FILE}")
131
+ system("git -C #{root} commit -m 'Release v#{new_version}'")
132
+ system("git -C #{root} tag -a v#{new_version} -m 'Release v#{new_version}'")
133
+
134
+ # Build and push gems
135
+ gem_paths = ReleaseHelper.build_all
136
+ ReleaseHelper.push_all(gem_paths)
137
+
138
+ # Push git
139
+ puts "\nPushing to origin..."
140
+ system("git -C #{root} push origin master")
141
+ system("git -C #{root} push origin v#{new_version}")
142
+
143
+ puts "\n#{'=' * 60}"
144
+ puts "Released v#{new_version} successfully!"
145
+ puts " - #{PUBLISH_ORDER.size} gems pushed to RubyGems.org"
146
+ puts " - Tagged v#{new_version} and pushed to origin"
147
+ puts '=' * 60
148
+ end
metadata ADDED
@@ -0,0 +1,108 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rails-saas-builder
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.9.1
5
+ platform: ruby
6
+ authors:
7
+ - Aleksandr Marchenko
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: rsb-admin
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - '='
17
+ - !ruby/object:Gem::Version
18
+ version: 0.9.1
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - '='
24
+ - !ruby/object:Gem::Version
25
+ version: 0.9.1
26
+ - !ruby/object:Gem::Dependency
27
+ name: rsb-auth
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - '='
31
+ - !ruby/object:Gem::Version
32
+ version: 0.9.1
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - '='
38
+ - !ruby/object:Gem::Version
39
+ version: 0.9.1
40
+ - !ruby/object:Gem::Dependency
41
+ name: rsb-entitlements
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - '='
45
+ - !ruby/object:Gem::Version
46
+ version: 0.9.1
47
+ type: :runtime
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - '='
52
+ - !ruby/object:Gem::Version
53
+ version: 0.9.1
54
+ - !ruby/object:Gem::Dependency
55
+ name: rsb-settings
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - '='
59
+ - !ruby/object:Gem::Version
60
+ version: 0.9.1
61
+ type: :runtime
62
+ prerelease: false
63
+ version_requirements: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - '='
66
+ - !ruby/object:Gem::Version
67
+ version: 0.9.1
68
+ description: 'Wrapper gem that includes all RSB sub-gems: settings, auth, entitlements,
69
+ admin. Like how the rails gem wraps activerecord, actionpack, etc.'
70
+ email:
71
+ - alex@marchenko.me
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - LICENSE
77
+ - README.md
78
+ - Rakefile
79
+ - lib/generators/rails_saas_builder/install/install_generator.rb
80
+ - lib/rails/saas/builder.rb
81
+ - lib/rails_saas_builder.rb
82
+ - lib/rsb/version.rb
83
+ - lib/tasks/release.rake
84
+ homepage: https://github.com/Rails-SaaS-Builder/rails-saas-builder
85
+ licenses:
86
+ - LGPL-3.0
87
+ metadata:
88
+ source_code_uri: https://github.com/Rails-SaaS-Builder/rails-saas-builder
89
+ bug_tracker_uri: https://github.com/Rails-SaaS-Builder/rails-saas-builder/issues
90
+ changelog_uri: https://github.com/Rails-SaaS-Builder/rails-saas-builder/blob/master/CHANGELOG.md
91
+ rdoc_options: []
92
+ require_paths:
93
+ - lib
94
+ required_ruby_version: !ruby/object:Gem::Requirement
95
+ requirements:
96
+ - - ">="
97
+ - !ruby/object:Gem::Version
98
+ version: '3.2'
99
+ required_rubygems_version: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ requirements: []
105
+ rubygems_version: 3.6.8
106
+ specification_version: 4
107
+ summary: Full-stack SaaS framework for Rails
108
+ test_files: []