seams 0.2.0 → 0.2.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 +4 -4
- data/CHANGELOG.md +39 -0
- data/README.md +36 -23
- data/lib/generators/seams/admin/templates/README.md.tt +50 -17
- data/lib/generators/seams/admin/templates/app/controllers/admin/application_controller.rb.tt +25 -5
- data/lib/generators/seams/design/design_generator.rb +6 -2
- data/lib/generators/seams/install/templates/deploy.yml.tt +6 -0
- data/lib/seams/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3ef90aa737b9e8b791771fc08707df790b8a9b870b448cedc4a52824282881c9
|
|
4
|
+
data.tar.gz: caf6906f698570313cb0b22b90fa93cd917ea11de1e1ff05660a330149997e4d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b0193a281248bec66c49e53f3e34a9b278854f056cb63ad4174520b7973a826d3468e8317881b53eba28733f0090f33904372996d2adcb3e526c226d5cadc8a5
|
|
7
|
+
data.tar.gz: bc365fb8bffac2bb41cbc295fd8ebece8b10d998cef1135957eaba27a846bbcbfd138236c05297f6e308eeb359ad0b4ba323ad05b6fb7609315534b7c088cee7
|
data/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,45 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.2.1] — 2026-09-28
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- Docs: [Setting up the admin area](doc/how-to/SETTING_UP_ADMIN.md), a
|
|
15
|
+
step-by-step guide covering installation, the staff flag, tenant mode,
|
|
16
|
+
`before_admin_action`, ejecting, and adding your own dashboards. Every
|
|
17
|
+
step was checked in a generated app.
|
|
18
|
+
- Docs: the Deploying guide covers Rails 8's four production databases
|
|
19
|
+
(`CACHE_/QUEUE_/CABLE_DATABASE_URL`) and the Active Record encryption
|
|
20
|
+
keys the auth engine needs. The generated Kamal `deploy.yml` lists the
|
|
21
|
+
three extra database URLs.
|
|
22
|
+
|
|
23
|
+
### Fixed
|
|
24
|
+
|
|
25
|
+
- Admin engine: an app without every canonical engine (for example only
|
|
26
|
+
`core` and `auth`) got a 500 on every admin page, because the
|
|
27
|
+
navigation loaded dashboards whose models don't exist. Those
|
|
28
|
+
dashboards are now hidden and their URLs return 404.
|
|
29
|
+
- Design generator: the next-steps message now marks
|
|
30
|
+
`bin/rails tailwindcss:build` as required and names the error you get
|
|
31
|
+
without it.
|
|
32
|
+
- Admin README: the "add your own dashboard" recipe now includes
|
|
33
|
+
`self.model`, the policies, the leading-slash route, and deleting
|
|
34
|
+
Administrate's generated host controller. It no longer claims
|
|
35
|
+
`theme_css_path` restyles the admin, since that setting is not
|
|
36
|
+
applied yet.
|
|
37
|
+
- Docs: the onboarding path now works when followed literally. Both
|
|
38
|
+
tutorials and the README quick start were re-run in fresh apps from
|
|
39
|
+
the published gem. The 10-minute tutorial claimed SQLite works (the
|
|
40
|
+
migrations use `jsonb` and fail), sent readers to a nonexistent
|
|
41
|
+
`/auth/sign_up`, and had them add mount lines the generators already
|
|
42
|
+
write. All onboarding docs now cover PostgreSQL, `bundle install`
|
|
43
|
+
after each generator, `bin/rails db:encryption:init` (without it,
|
|
44
|
+
sign-up raises `Missing Active Record encryption credential`), and
|
|
45
|
+
`bin/rails tailwindcss:build` after `design --shell`. The Engine
|
|
46
|
+
Catalogue's wiring example now matches what the generators write.
|
|
47
|
+
Docs links point at davidslv.uk/seams.
|
|
48
|
+
|
|
10
49
|
## [0.2.0] — 2026-09-27
|
|
11
50
|
|
|
12
51
|
> [!WARNING]
|
data/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://rubygems.org/gems/seams)
|
|
4
4
|
[](https://github.com/Davidslv/seams/actions/workflows/ci.yml)
|
|
5
|
-
[](https://davidslv.uk/seams/)
|
|
6
6
|
[](https://rubydoc.info/gems/seams)
|
|
7
7
|
[](LICENSE)
|
|
8
8
|
|
|
@@ -13,7 +13,7 @@ You ship one Rails app. Inside it, each feature (auth, accounts, billing, teams,
|
|
|
13
13
|
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.
|
|
14
14
|
|
|
15
15
|
> [!NOTE]
|
|
16
|
-
> Seams is the executable companion to the book **[Modular Rails: Architecture for the Long Game](https://davidslv.uk/modular-rails/)**. The full guides live on the **[documentation site](https://davidslv.
|
|
16
|
+
> Seams is the executable companion to the book **[Modular Rails: Architecture for the Long Game](https://davidslv.uk/modular-rails/)**. The full guides live on the **[documentation site](https://davidslv.uk/seams/)**. [seams-example](https://github.com/Davidslv/seams-example) is a reference host with every engine wired up.
|
|
17
17
|
|
|
18
18
|
## Requirements
|
|
19
19
|
|
|
@@ -28,43 +28,55 @@ Every generated file is plain Rails code in your repo. You can read it, change i
|
|
|
28
28
|
|
|
29
29
|
## Installation
|
|
30
30
|
|
|
31
|
+
Add Seams to your Gemfile:
|
|
32
|
+
|
|
33
|
+
```ruby
|
|
34
|
+
# Gemfile
|
|
35
|
+
gem "seams", "~> 0.2"
|
|
36
|
+
```
|
|
37
|
+
|
|
31
38
|
> [!WARNING]
|
|
32
|
-
> **
|
|
33
|
-
>
|
|
34
|
-
> ```ruby
|
|
35
|
-
> # Gemfile
|
|
36
|
-
> gem "seams", github: "Davidslv/seams"
|
|
37
|
-
> ```
|
|
38
|
-
>
|
|
39
|
-
> Once a newer version is on RubyGems, use `gem "seams"` instead.
|
|
39
|
+
> **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.
|
|
40
40
|
|
|
41
41
|
Then install the framework:
|
|
42
42
|
|
|
43
43
|
```bash
|
|
44
44
|
bundle install
|
|
45
45
|
bin/rails generate seams:install
|
|
46
|
+
bundle install
|
|
46
47
|
```
|
|
47
48
|
|
|
48
|
-
`seams:install` adds the framework files, a CI workflow,
|
|
49
|
+
`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`.
|
|
49
50
|
|
|
50
51
|
## Quick start
|
|
51
52
|
|
|
52
|
-
Generate the engines you need. The order matters, because later engines build on earlier ones:
|
|
53
|
+
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:
|
|
53
54
|
|
|
54
55
|
```bash
|
|
55
|
-
bin/seams core # shared building blocks (always first)
|
|
56
|
-
bin/seams auth # sign-in, sessions, OAuth, API tokens
|
|
57
|
-
bin/seams accounts # the tenant (Account) and its members
|
|
58
|
-
bin/seams notifications # in-app, email, and SMS notifications
|
|
59
|
-
bin/seams billing # Stripe subscriptions
|
|
60
|
-
bin/seams teams # optional teams inside an account
|
|
61
|
-
bin/seams design --shell # UI components and an app layout
|
|
56
|
+
bin/seams core && bundle install # shared building blocks (always first)
|
|
57
|
+
bin/seams auth && bundle install # sign-in, sessions, OAuth, API tokens
|
|
58
|
+
bin/seams accounts && bundle install # the tenant (Account) and its members
|
|
59
|
+
bin/seams notifications && bundle install # in-app, email, and SMS notifications
|
|
60
|
+
bin/seams billing && bundle install # Stripe subscriptions
|
|
61
|
+
bin/seams teams && bundle install # optional teams inside an account
|
|
62
|
+
bin/seams design --shell && bundle install # UI components and an app layout
|
|
63
|
+
```
|
|
62
64
|
|
|
63
|
-
|
|
65
|
+
Then finish the setup:
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
bin/rails tailwindcss:build # the design layout loads the compiled CSS
|
|
69
|
+
bin/rails db:encryption:init # auth encrypts personal data; paste the printed
|
|
70
|
+
bin/rails credentials:edit # active_record_encryption block into credentials
|
|
64
71
|
bin/rails db:migrate
|
|
65
|
-
bin/seams list
|
|
72
|
+
bin/seams list # show engines, their events, and subscribers
|
|
66
73
|
```
|
|
67
74
|
|
|
75
|
+
> [!IMPORTANT]
|
|
76
|
+
> 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`.
|
|
77
|
+
|
|
78
|
+
Start the app with `bin/rails server`. Sign up at `/auth/registration/new` and sign in at `/auth/session/new`.
|
|
79
|
+
|
|
68
80
|
> [!TIP]
|
|
69
81
|
> New to Seams? Follow **[Getting Started](doc/tutorials/GETTING_STARTED.md)**. It goes step by step from `bundle install` to a running app.
|
|
70
82
|
|
|
@@ -150,7 +162,7 @@ With these set:
|
|
|
150
162
|
- Requests for another account's records return 404.
|
|
151
163
|
- A `member` gets a 403.
|
|
152
164
|
|
|
153
|
-
The generated `engines/admin/README.md` has the full reference.
|
|
165
|
+
Step-by-step guide: [Setting up the admin area](doc/how-to/SETTING_UP_ADMIN.md). The generated `engines/admin/README.md` has the full reference.
|
|
154
166
|
|
|
155
167
|
</details>
|
|
156
168
|
|
|
@@ -168,7 +180,7 @@ Seams writes code into your app. So updating the gem does not change engines you
|
|
|
168
180
|
|
|
169
181
|
## Documentation
|
|
170
182
|
|
|
171
|
-
The **[documentation site](https://davidslv.
|
|
183
|
+
The **[documentation site](https://davidslv.uk/seams/)** has every guide below, with search. The API reference is on **[rubydoc.info](https://rubydoc.info/gems/seams)**.
|
|
172
184
|
|
|
173
185
|
<details>
|
|
174
186
|
<summary><strong>Start here</strong></summary>
|
|
@@ -186,6 +198,7 @@ The **[documentation site](https://davidslv.github.io/seams/)** has every guide
|
|
|
186
198
|
- [Removing an engine](doc/how-to/REMOVING_AN_ENGINE.md)
|
|
187
199
|
- [Writing an adapter](doc/how-to/WRITING_AN_ADAPTER.md): swap in Mailgun, Twilio, Paddle, and others
|
|
188
200
|
- [Writing follow-up generators](doc/how-to/WRITING_FOLLOW_UP_GENERATORS.md)
|
|
201
|
+
- [Setting up the admin area](doc/how-to/SETTING_UP_ADMIN.md)
|
|
189
202
|
- [Insertion points](doc/reference/INSERTION_POINTS.md) and the [catalogue of markers](doc/reference/INSERTION_POINTS_CATALOGUE.md)
|
|
190
203
|
- [Deploying](doc/how-to/DEPLOYING.md)
|
|
191
204
|
|
|
@@ -136,9 +136,8 @@ Seams::Admin.configure do |c|
|
|
|
136
136
|
# at request time. See "Two-mode operation" above.
|
|
137
137
|
c.tenancy_scope = :platform
|
|
138
138
|
|
|
139
|
-
# 3. theme_css_path —
|
|
140
|
-
#
|
|
141
|
-
# defaults.
|
|
139
|
+
# 3. theme_css_path — Reserved for a host-supplied CSS file on top of
|
|
140
|
+
# Administrate's stock styling. Accepted but not applied yet.
|
|
142
141
|
c.theme_css_path = nil
|
|
143
142
|
|
|
144
143
|
# 4. before_admin_action — Optional callable that runs before every
|
|
@@ -192,18 +191,51 @@ bin/seams resolve --eject admin/app/dashboards/admin/identity_dashboard.rb
|
|
|
192
191
|
# Now edit engines/admin/app/dashboards/admin/identity_dashboard.rb freely.
|
|
193
192
|
```
|
|
194
193
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
194
|
+
To add a dashboard for one of your own models, e.g. `Project`:
|
|
195
|
+
|
|
196
|
+
1. **Dashboard:** `engines/admin/app/dashboards/admin/project_dashboard.rb`.
|
|
197
|
+
Generate a starting point with `bin/rails generate administrate:dashboard Project`,
|
|
198
|
+
then move it here, rename it to `Admin::ProjectDashboard`, and declare
|
|
199
|
+
its model. Administrate would otherwise guess `Admin::Project`:
|
|
200
|
+
|
|
201
|
+
```ruby
|
|
202
|
+
module Admin
|
|
203
|
+
class ProjectDashboard < Administrate::BaseDashboard
|
|
204
|
+
def self.model
|
|
205
|
+
::Project
|
|
206
|
+
end
|
|
207
|
+
# ATTRIBUTE_TYPES, COLLECTION_ATTRIBUTES, ... as generated
|
|
208
|
+
end
|
|
209
|
+
end
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
2. **Controller:** `engines/admin/app/controllers/admin/projects_controller.rb`,
|
|
213
|
+
subclassing the gated base controller. Delete the controller
|
|
214
|
+
Administrate generated in your app's `app/controllers/admin/`, because
|
|
215
|
+
it bypasses the gate:
|
|
216
|
+
|
|
217
|
+
```ruby
|
|
218
|
+
module Admin
|
|
219
|
+
class ProjectsController < ::Seams::Admin::ApplicationController
|
|
220
|
+
def resource_class = ::Project
|
|
221
|
+
def dashboard = (@dashboard ||= ProjectDashboard.new)
|
|
222
|
+
end
|
|
223
|
+
end
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
3. **Policies:** `Admin::Platform::ProjectPolicy` and `Admin::Tenant::ProjectPolicy`
|
|
227
|
+
under `engines/admin/app/policies/admin/{platform,tenant}/`. Subclass the
|
|
228
|
+
namespace's `ApplicationPolicy`. The controller name picks the policy, and
|
|
229
|
+
an action with no policy is denied.
|
|
230
|
+
|
|
231
|
+
4. **Route:** add this to `engines/admin/config/routes.rb`, inside the
|
|
232
|
+
`scope as: :admin do` block:
|
|
233
|
+
|
|
234
|
+
```ruby
|
|
235
|
+
resources :projects, controller: "/admin/projects"
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
The leading slash is required. The sidebar picks the dashboard up automatically.
|
|
207
239
|
|
|
208
240
|
Administrate's full dashboard / field / controller surface is documented
|
|
209
241
|
at <https://administrate-demo.herokuapp.com/>.
|
|
@@ -222,8 +254,9 @@ at <https://administrate-demo.herokuapp.com/>.
|
|
|
222
254
|
|
|
223
255
|
- **2FA / IP allow-list for `/admin`.** Not shipped. Wire your own via
|
|
224
256
|
`Seams::Admin.config.before_admin_action`.
|
|
225
|
-
- **Branded UI.** Stock Administrate CSS only
|
|
226
|
-
|
|
257
|
+
- **Branded UI.** Stock Administrate CSS only. `theme_css_path` is
|
|
258
|
+
accepted but not applied yet. To restyle, override Administrate's
|
|
259
|
+
views (see Administrate's documentation).
|
|
227
260
|
- **Search beyond Administrate's stock.** Administrate ships a basic
|
|
228
261
|
Ransack-backed search; rich filtering / faceted search is your job.
|
|
229
262
|
- **Batch actions.** Not in Administrate's surface; not shipped here.
|
data/lib/generators/seams/admin/templates/app/controllers/admin/application_controller.rb.tt
CHANGED
|
@@ -73,11 +73,21 @@ module Seams
|
|
|
73
73
|
# declared model so follow-up dashboards are picked up too.
|
|
74
74
|
def self.admin_route_keys_by_model
|
|
75
75
|
admin_routes.map(&:first).uniq.each_with_object({}) do |key, map|
|
|
76
|
-
|
|
77
|
-
map[
|
|
76
|
+
model = admin_model_for(key)
|
|
77
|
+
map[model.name] = key if model
|
|
78
78
|
end
|
|
79
79
|
end
|
|
80
80
|
|
|
81
|
+
# The model behind a dashboard route key, or nil when its engine is
|
|
82
|
+
# not installed (a host with auth but no billing has no
|
|
83
|
+
# Billing::Plan). Those dashboards are hidden and answer 404.
|
|
84
|
+
def self.admin_model_for(key)
|
|
85
|
+
dashboard = "Admin::#{key.classify}Dashboard".safe_constantize
|
|
86
|
+
dashboard.model if dashboard.respond_to?(:model)
|
|
87
|
+
rescue NameError
|
|
88
|
+
nil
|
|
89
|
+
end
|
|
90
|
+
|
|
81
91
|
# Accounts::Membership and Teams::Membership both have the route
|
|
82
92
|
# key `memberships` (isolated-engine model naming), so
|
|
83
93
|
# Administrate's polymorphic `[:admin, membership]` calls
|
|
@@ -153,6 +163,10 @@ module Seams
|
|
|
153
163
|
helper_method :seams_admin_tenancy_scope
|
|
154
164
|
helper_method :seams_admin_navigation
|
|
155
165
|
|
|
166
|
+
# Runs after the authentication gate, so signed-out visitors are
|
|
167
|
+
# still redirected to sign-in rather than told what exists.
|
|
168
|
+
before_action :ensure_admin_model_installed
|
|
169
|
+
|
|
156
170
|
def seams_admin_tenancy_scope
|
|
157
171
|
::Seams::Admin.config.tenancy_scope
|
|
158
172
|
end
|
|
@@ -219,6 +233,12 @@ module Seams
|
|
|
219
233
|
t("administrate.controller.#{key}", resource: resource_class.model_name.human)
|
|
220
234
|
end
|
|
221
235
|
|
|
236
|
+
def ensure_admin_model_installed
|
|
237
|
+
return if self.class.admin_model_for(controller_name)
|
|
238
|
+
|
|
239
|
+
raise ActionController::RoutingError, "#{controller_name} is not installed in this app"
|
|
240
|
+
end
|
|
241
|
+
|
|
222
242
|
def membership_route_key(record)
|
|
223
243
|
MEMBERSHIP_ROUTE_KEYS[record.class.name] || controller_name.singularize
|
|
224
244
|
end
|
|
@@ -270,11 +290,11 @@ module Seams
|
|
|
270
290
|
# an index route that the current user may list.
|
|
271
291
|
def seams_admin_navigation
|
|
272
292
|
self.class.admin_routes.select { |_key, action| action == "index" }.map(&:first).uniq.filter_map do |key|
|
|
273
|
-
|
|
274
|
-
next unless
|
|
293
|
+
model = self.class.admin_model_for(key)
|
|
294
|
+
next unless model && authorized_action?(model, :index)
|
|
275
295
|
|
|
276
296
|
{ key: key,
|
|
277
|
-
label:
|
|
297
|
+
label: model.model_name.human(count: 2),
|
|
278
298
|
path: url_for(controller: "/admin/#{key}", action: :index),
|
|
279
299
|
active: key == controller_name }
|
|
280
300
|
end
|
|
@@ -620,8 +620,12 @@ module Seams
|
|
|
620
620
|
1. bundle install
|
|
621
621
|
(picks up tailwindcss-rails, injected into the host Gemfile)
|
|
622
622
|
|
|
623
|
-
2. bin/rails tailwindcss:
|
|
624
|
-
|
|
623
|
+
2. bin/rails tailwindcss:build (required)
|
|
624
|
+
Pages using the layout fail with "The asset 'tailwind.css' was
|
|
625
|
+
not found" until the CSS is built. Rebuild after style changes,
|
|
626
|
+
or keep `bin/rails tailwindcss:watch` running.
|
|
627
|
+
Without --shell, if your layout doesn't load Tailwind yet, run
|
|
628
|
+
`bin/rails tailwindcss:install` first.
|
|
625
629
|
|
|
626
630
|
3. Use the components anywhere in the host or another engine's views:
|
|
627
631
|
<%= ui_button(variant: :primary) { "Save" } %>
|
|
@@ -37,6 +37,12 @@ env:
|
|
|
37
37
|
secret:
|
|
38
38
|
- RAILS_MASTER_KEY
|
|
39
39
|
- DATABASE_URL
|
|
40
|
+
# Rails 8 has separate cache/queue/cable databases; DATABASE_URL only
|
|
41
|
+
# covers the primary. Point these at the same server with different
|
|
42
|
+
# database names, or configure them in config/database.yml and drop them.
|
|
43
|
+
- CACHE_DATABASE_URL
|
|
44
|
+
- QUEUE_DATABASE_URL
|
|
45
|
+
- CABLE_DATABASE_URL
|
|
40
46
|
- REDIS_URL
|
|
41
47
|
- STRIPE_SECRET_KEY
|
|
42
48
|
- STRIPE_WEBHOOK_SECRET
|
data/lib/seams/version.rb
CHANGED