Rails 8 · Ruby 3.4 · MIT
Rails with the boundaries already drawn.
A teishoku is a set meal: everything you need, on one tray, nothing to assemble. This is that for a Rails 8 app. Bounded contexts, Service and Query objects, auth, admin, API, three languages, and a suite that fails the build when you cross a line.
git clone https://github.com/gxolivei/ruby-on-rails-8-ddd-template my-app cd my-app && bin/setup_wizard
What's on the tray
Everything below is wired, tested, and enforced. Run the wizard and choose what to keep.
Bounded contexts
Every file lives in a context. Identity::User, not User. Crossing a boundary is written in the code, not an accident of autoloading.
Services and Queries
Writes return a Result. Reads return records. Controllers call them and never touch Active Record.
Generators that know the rules
ddd:context, ddd:model, ddd:query, ddd:service, ddd:controller --with query service. The plain Rails ones are shadowed and point you back.
Auth, done
Sign-in, sign-up, lockout, password policy, reset emails, GitHub OAuth.
Admin and API
A protected backoffice with branding, and a token-authenticated versioned JSON API.
Three languages
English, Português, Español across the whole UI. A literal string in a view fails the build.
Themes without JavaScript
Light, dark and system, driven by the user's preference through semantic tokens.
The Solid stack
Cache, queue and cable on PostgreSQL. No Redis.
The rules are tests
A .find in a controller fails the build. A .where in a view fails the build. A model outside a context fails the build.
The failure names the file and line, the generator to run, and the section of ARCHITECTURE.md to read.
app/controllers/billing/invoices_controller.rb:7 — controller calls User.find(params[:id]) directly; move the read into a Query or the write into a Service
Fix: bin/rails g ddd:query Billing <Name> (read) or bin/rails g ddd:service Billing <Name> (write), then call Billing::<Name>Query.call / <Name>Service.call from here
See: ARCHITECTURE.md §3 Strict Layer Contracts, §4 Service Object Pattern, §5 Query Object Pattern
Start in five commands
Every generator ends by telling you what to run next.
bin/rails g ddd:context Billing
folders for the Billing context and its routes namespace
bin/rails g ddd:model Billing Invoice amount:decimal status:integer
Billing::Invoice model, migration, factory and spec
bin/rails g ddd:query Billing ListInvoices
Billing::ListInvoicesQuery, a read for a page, with spec
bin/rails g ddd:service Billing CreateInvoice
Billing::CreateInvoiceService, a write that returns a Result, with spec
bin/rails g ddd:controller Billing Invoices index show create --with query service
Billing::InvoicesController, views, routes, locale keys and request spec,
plus the queries and services those actions call
100.0% line coverage, enforced.
The suite fails below it. SimpleCov's minimum_coverage gate is the mechanism, and the wizard runs the suite before it says you are done.