Skip to content

Latest commit

 

History

286 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Seams

Gem Version CI Docs site API docs License: MIT

Seams generates modular Rails engines inside your Rails app.

You ship one Rails app. Inside it, each feature (auth, accounts, billing, teams, and so on) lives in its own engine under engines/. Each engine has its own models, tests, and boundaries. Engines talk to each other through events, not by reaching into each other's code. Custom RuboCop cops enforce that.

Every generated file is plain Rails code in your repo. You can read it, change it, or delete it. Nothing is hidden behind the gem.

Note

Seams is the executable companion to the book Modular Rails: Architecture for the Long Game. The full guides live on the documentation site. seams-example is a reference host with every engine wired up.

Requirements

Supported Tested in CI
Ruby 3.3 or newer 3.3, 3.4, 4.0.7
Rails 7.1 or newer (below 9) 8.1.4
Database PostgreSQL PostgreSQL 18

Important

PostgreSQL is required. The generated engines use jsonb columns, and each engine's test suite runs against Postgres. SQLite and MySQL are not supported.

Installation

Add Seams to your Gemfile:

# Gemfile
gem "seams", "~> 0.2"

Warning

Use 0.2.0 or newer. Version 0.1.0 requires Ruby 4.0 and predates many fixes, including the admin engine working and Ruby 3.3 support.

Then install the framework:

bundle install
bin/rails generate seams:install
bundle install

seams:install adds the framework files, a CI workflow, a bin/seams command, and a few development gems (hence the second bundle install). Every step after this uses bin/seams.

Quick start

Generate the engines you need. The order matters, because later engines build on earlier ones. Each generator can add gems to your Gemfile, so run bundle install after each one, before the next:

bin/seams core && bundle install            # shared building blocks (always first)
bin/seams auth && bundle install            # sign-in, sessions, OAuth, API tokens
bin/seams accounts && bundle install        # the tenant (Account) and its members
bin/seams notifications && bundle install   # in-app, email, and SMS notifications
bin/seams billing && bundle install         # Stripe subscriptions
bin/seams teams && bundle install           # optional teams inside an account
bin/seams design --shell && bundle install  # UI components and an app layout

Then finish the setup:

bin/rails tailwindcss:build     # the design layout loads the compiled CSS
bin/rails db:encryption:init    # auth encrypts personal data; paste the printed
bin/rails credentials:edit      #   active_record_encryption block into credentials
bin/rails db:migrate
bin/seams list                  # show engines, their events, and subscribers

Important

Skip the encryption keys and sign-up fails with Missing Active Record encryption credential. Skip the Tailwind build and every page using the design layout fails with The asset 'tailwind.css' was not found.

Start the app with bin/rails server. Sign up at /auth/registration/new and sign in at /auth/session/new.

Tip

New to Seams? Follow Getting Started. It goes step by step from bundle install to a running app.

What you get

The engines

Command What it generates
bin/seams core Shared basics: per-request Current attributes, an audit log, tenant scoping, an email validator.
bin/seams auth Identity (the person signing in), sessions, OAuth providers, API tokens. Personal data is encrypted at rest.
bin/seams accounts Account (the tenant), memberships with roles, account scoping.
bin/seams notifications Notifications over in-app, email, and SMS. Choose channels with --channels in_app,email,sms (default: all).
bin/seams billing Stripe subscriptions using the official stripe gem (19.x), a webhook router with 13 handlers, and lifetime deals.
bin/seams teams Teams, team memberships, and invitations. Choose features with --with invitations,roles (default: all).
bin/seams admin An admin area built on Administrate and Pundit. Optional. See Admin engine below.
bin/seams design A design system: 33 ui_* components, Tailwind v4 theme tokens, a form builder, and a /design/guide gallery. --shell also adds an app layout and a starter dashboard.
bin/seams permissions An editable map of which roles can do what, in config/initializers/seams_permissions.rb. See Permissions.

Framework and tools

Command What it does
bin/rails generate seams:install Installs the framework, the CI workflow, and bin/seams.
bin/seams engine <name> Generates an empty engine for your own feature.
bin/seams remove <name> Removes an engine, cleans up references to it, and adds a migration that drops its tables.
bin/seams list Lists engines, the events they publish, and who subscribes to them.
bin/seams test <engine> Runs one engine's tests.
bin/seams quality <engine> Runs RuboCop on one engine.
bin/seams resolve --eject <engine>/<file> Marks a generated file as yours, so future runs of the generator leave it alone. Also --list-markers <engine> and --list-ejected.
bin/rails generate seams:auth:add_oauth_provider <name> Adds an OAuth provider to the auth engine.

You also get:

  • Four custom RuboCop cops. Two fail the build when one engine reaches into another's code or models. The other two check background job queue names and migration comments.
  • A GitHub Actions workflow that runs each engine's tests in parallel.
  • A quality toolchain set up by seams:install:
    • strong_migrations and lefthook git hooks are on by default. Turn them off with --no-strong-migrations or --no-lefthook.
    • herb (ERB lint) is off by default. Turn it on with --herb.
  • A Dockerfile and a Kamal deploy.yml, written only if your app doesn't already have them. Rails 8 apps ship their own Dockerfile, which Seams leaves in place.

Admin engine

bin/seams admin adds an admin area at /admin. It needs the auth engine. It adds the administrate and pundit gems to your Gemfile.

Important

Only staff can open the admin area by default. Set staff: true on an Auth::Identity to let that person in:

Auth::Identity.find_by(email: "you@example.com").update!(staff: true)

Signed-out visitors are sent to the sign-in page. Signed-in identities that aren't staff get a 403.

Tenant mode: let each customer's admins manage their own account

By default the admin area runs in platform mode: staff see every account. In tenant mode, an account's admins see only their own account's data.

Tenant mode needs three settings. Without the last two, tenant admins get a 403.

# config/initializers/seams_admin.rb
Seams::Admin.configure do |c|
  c.tenancy_scope = :tenant

  # Let any signed-in identity past the gate. The tenant policies then
  # decide what each role may do.
  c.authenticator = ->(ctrl) { ctrl.current_identity.present? }

  # Tell the admin area which membership the request belongs to.
  # This example takes the identity's first active membership. Use
  # however your app picks the current account (subdomain, session, a switcher).
  c.current_membership_resolver = lambda do |ctrl|
    identity = ctrl.current_identity
    identity && Accounts::Membership.find_by(identity_id: identity.id, active: true)
  end
end

With these set:

  • An admin or owner of an account sees only that account's rows.
  • Requests for another account's records return 404.
  • A member gets a 403.

Step-by-step guide: Setting up the admin area. The generated engines/admin/README.md has the full reference.

Upgrading an existing Seams app

Seams writes code into your app. So updating the gem does not change engines you already generated. Read the CHANGELOG before you update, and apply the changes that affect you.

Note

If you generated engines before the September 2026 changes, check these:

  • solid_cable 4.1 or newer: each engine's test app needs engines/*/spec/dummy/config/cable.yml, containing test: with adapter: test. Without it, the engine's tests fail to load.
  • Billing: the generated code now targets stripe ~> 19.0. The generated services now raise Billing::GatewayError instead of Stripe::* errors. Set your Stripe webhook endpoint to the same API version as the gem.
  • Admin: regenerate the admin engine, or copy the fixes listed in the CHANGELOG. Earlier versions could not boot or serve any admin page.

If you adopted Seams before Wave 9, start with the Wave 8 upgrade guide.

Documentation

The documentation site has every guide below, with search. The API reference is on rubydoc.info.

Start here
Building and extending
Reference
Design system
Architecture history

How Seams compares

Instead of Seams gives you
Bullet Train or Jumpstart Pro The code lives in your repo, not behind a gem. Seams also enforces engine boundaries with RuboCop cops.
rails plugin new --mountable Engines come wired with events, registries, observability, boundary checks, and CI.
Microservices One process and one deploy. No HTTP between services. Engines talk through synchronous events with explicit subscribers.

Project status

Note

Seams is in active development and has not reached 1.0. Breaking changes are listed in the CHANGELOG. Open work is tracked in issue #5.

Each change is checked in CI:

  • RuboCop, Brakeman, and bundle-audit
  • the gem's own tests, on Ruby 3.3, 3.4, and 4.0.7
  • an end-to-end run that creates a new Rails app with rails new, generates every engine, runs each engine's tests, and boots the app against Postgres

Contributing

License

MIT. See LICENSE.

Releases

Packages

Contributors

Languages