plutonium 0.39.1 โ 0.40.0
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/.claude/skills/plutonium-connect-resource/SKILL.md +19 -1
- data/.claude/skills/plutonium-controller/SKILL.md +5 -9
- data/.claude/skills/plutonium-definition-query/SKILL.md +10 -2
- data/.claude/skills/plutonium-installation/SKILL.md +9 -7
- data/.claude/skills/plutonium-invites/SKILL.md +363 -0
- data/.claude/skills/plutonium-package/SKILL.md +2 -1
- data/.claude/skills/plutonium-portal/SKILL.md +30 -16
- data/.claude/skills/plutonium-rodauth/SKILL.md +111 -18
- data/CHANGELOG.md +48 -0
- data/app/assets/plutonium.css +1 -1
- data/config/initializers/sqlite_alias.rb +8 -8
- data/docs/.vitepress/config.ts +1 -0
- data/docs/getting-started/tutorial/07-author-portal.md +1 -0
- data/docs/getting-started/tutorial/08-customizing-ui.md +5 -2
- data/docs/guides/adding-resources.md +10 -0
- data/docs/guides/authentication.md +15 -8
- data/docs/guides/creating-packages.md +13 -8
- data/docs/guides/index.md +2 -0
- data/docs/guides/search-filtering.md +8 -3
- data/docs/guides/user-invites.md +497 -0
- data/docs/public/templates/base.rb +5 -1
- data/docs/public/templates/lite.rb +42 -0
- data/docs/public/templates/pluton8.rb +7 -2
- data/docs/reference/controller/index.md +12 -7
- data/docs/reference/definition/query.md +12 -3
- data/docs/reference/generators/index.md +70 -10
- data/docs/reference/portal/index.md +22 -11
- data/gemfiles/rails_7.gemfile.lock +1 -1
- data/gemfiles/rails_8.0.gemfile.lock +1 -1
- data/gemfiles/rails_8.1.gemfile.lock +1 -1
- data/lib/generators/pu/gem/active_shrine/active_shrine_generator.rb +31 -0
- data/lib/generators/pu/gem/active_shrine/templates/config/initializers/shrine.rb.tt +58 -0
- data/lib/generators/pu/gem/annotated/templates/lib/tasks/auto_annotate_models.rake +6 -1
- data/lib/generators/pu/gem/dotenv/templates/config/initializers/001_ensure_required_env.rb +3 -0
- data/lib/generators/pu/invites/USAGE +27 -0
- data/lib/generators/pu/invites/install_generator.rb +364 -0
- data/lib/generators/pu/invites/invitable/USAGE +31 -0
- data/lib/generators/pu/invites/invitable_generator.rb +143 -0
- data/lib/generators/pu/invites/templates/INSTRUCTIONS +22 -0
- data/lib/generators/pu/invites/templates/app/interactions/invite_user_interaction.rb.tt +24 -0
- data/lib/generators/pu/invites/templates/app/interactions/user_invite_user_interaction.rb.tt +26 -0
- data/lib/generators/pu/invites/templates/db/migrate/create_user_invites.rb.tt +47 -0
- data/lib/generators/pu/invites/templates/invitable/invitation.html.erb.tt +45 -0
- data/lib/generators/pu/invites/templates/invitable/invitation.text.erb.tt +15 -0
- data/lib/generators/pu/invites/templates/invitable/invite_user_interaction.rb.tt +33 -0
- data/lib/generators/pu/invites/templates/packages/invites/app/controllers/invites/user_invitations_controller.rb.tt +77 -0
- data/lib/generators/pu/invites/templates/packages/invites/app/controllers/invites/welcome_controller.rb.tt +68 -0
- data/lib/generators/pu/invites/templates/packages/invites/app/definitions/invites/user_invite_definition.rb.tt +23 -0
- data/lib/generators/pu/invites/templates/packages/invites/app/interactions/invites/cancel_invite_interaction.rb.tt +7 -0
- data/lib/generators/pu/invites/templates/packages/invites/app/interactions/invites/resend_invite_interaction.rb.tt +7 -0
- data/lib/generators/pu/invites/templates/packages/invites/app/mailers/invites/user_invite_mailer.rb.tt +34 -0
- data/lib/generators/pu/invites/templates/packages/invites/app/models/invites/user_invite.rb.tt +41 -0
- data/lib/generators/pu/invites/templates/packages/invites/app/policies/invites/user_invite_policy.rb.tt +33 -0
- data/lib/generators/pu/invites/templates/packages/invites/app/views/invites/user_invitations/error.html.erb.tt +24 -0
- data/lib/generators/pu/invites/templates/packages/invites/app/views/invites/user_invitations/landing.html.erb.tt +40 -0
- data/lib/generators/pu/invites/templates/packages/invites/app/views/invites/user_invitations/show.html.erb.tt +39 -0
- data/lib/generators/pu/invites/templates/packages/invites/app/views/invites/user_invitations/signup.html.erb.tt +49 -0
- data/lib/generators/pu/invites/templates/packages/invites/app/views/invites/user_invite_mailer/invitation.html.erb.tt +45 -0
- data/lib/generators/pu/invites/templates/packages/invites/app/views/invites/user_invite_mailer/invitation.text.erb.tt +15 -0
- data/lib/generators/pu/invites/templates/packages/invites/app/views/invites/welcome/pending_invitation.html.erb.tt +23 -0
- data/lib/generators/pu/invites/templates/packages/invites/app/views/layouts/invites/invitation.html.erb.tt +33 -0
- data/lib/generators/pu/lib/plutonium_generators/concerns/actions.rb +23 -2
- data/lib/generators/pu/lib/plutonium_generators/concerns/configures_sqlite.rb +130 -0
- data/lib/generators/pu/lib/plutonium_generators/concerns/mounts_engines.rb +72 -0
- data/lib/generators/pu/lib/plutonium_generators/concerns/package_selector.rb +4 -2
- data/lib/generators/pu/lib/plutonium_generators/model_generator_base.rb +7 -1
- data/lib/generators/pu/lite/litestream/litestream_generator.rb +105 -0
- data/lib/generators/pu/lite/rails_pulse/rails_pulse_generator.rb +88 -0
- data/lib/generators/pu/lite/rails_pulse/templates/config/initializers/rails_pulse.rb.tt +14 -0
- data/lib/generators/pu/lite/setup/setup_generator.rb +54 -0
- data/lib/generators/pu/lite/solid_cable/solid_cable_generator.rb +65 -0
- data/lib/generators/pu/lite/solid_cache/solid_cache_generator.rb +66 -0
- data/lib/generators/pu/lite/solid_errors/solid_errors_generator.rb +61 -0
- data/lib/generators/pu/lite/solid_queue/solid_queue_generator.rb +107 -0
- data/lib/generators/pu/pkg/portal/USAGE +8 -2
- data/lib/generators/pu/pkg/portal/portal_generator.rb +11 -1
- data/lib/generators/pu/pkg/portal/templates/app/controllers/concerns/controller.rb.tt +2 -0
- data/lib/generators/pu/pkg/portal/templates/app/controllers/plutonium_controller.rb.tt +1 -0
- data/lib/generators/pu/pkg/portal/templates/app/controllers/resource_controller.rb.tt +7 -0
- data/lib/generators/pu/pkg/portal/templates/lib/engine.rb.tt +3 -0
- data/lib/generators/pu/res/conn/USAGE +5 -0
- data/lib/generators/pu/res/conn/conn_generator.rb +30 -4
- data/lib/generators/pu/res/scaffold/scaffold_generator.rb +6 -3
- data/lib/generators/pu/res/scaffold/templates/policy.rb.tt +6 -6
- data/lib/generators/pu/rodauth/account_generator.rb +36 -11
- data/lib/generators/pu/rodauth/admin_generator.rb +55 -0
- data/lib/generators/pu/rodauth/install_generator.rb +1 -8
- data/lib/generators/pu/rodauth/templates/app/interactions/invite_admin_interaction.rb.tt +25 -0
- data/lib/generators/pu/rodauth/templates/app/models/account.rb.tt +6 -2
- data/lib/generators/pu/saas/USAGE +22 -0
- data/lib/generators/pu/saas/entity/USAGE +19 -0
- data/lib/generators/pu/saas/entity_generator.rb +55 -0
- data/lib/generators/pu/saas/membership/USAGE +25 -0
- data/lib/generators/pu/saas/membership_generator.rb +165 -0
- data/lib/generators/pu/saas/setup/USAGE +27 -0
- data/lib/generators/pu/saas/setup_generator.rb +98 -0
- data/lib/generators/pu/saas/user/USAGE +21 -0
- data/lib/generators/pu/saas/user_generator.rb +66 -0
- data/lib/plutonium/core/controller.rb +9 -5
- data/lib/plutonium/definition/base.rb +3 -1
- data/lib/plutonium/definition/scoping.rb +20 -0
- data/lib/plutonium/invites/concerns/cancel_invite.rb +44 -0
- data/lib/plutonium/invites/concerns/invitable.rb +98 -0
- data/lib/plutonium/invites/concerns/invite_token.rb +186 -0
- data/lib/plutonium/invites/concerns/invite_user.rb +147 -0
- data/lib/plutonium/invites/concerns/resend_invite.rb +66 -0
- data/lib/plutonium/invites/controller.rb +226 -0
- data/lib/plutonium/invites/pending_invite_check.rb +76 -0
- data/lib/plutonium/invites.rb +6 -0
- data/lib/plutonium/resource/controllers/queryable.rb +4 -0
- data/lib/plutonium/resource/query_object.rb +3 -5
- data/lib/plutonium/version.rb +1 -1
- data/package.json +1 -1
- metadata +64 -7
- data/lib/generators/pu/res/entity/entity_generator.rb +0 -158
- data/lib/generators/pu/rodauth/customer_generator.rb +0 -101
- data/public/plutonium-assets/plutonium-logo-original.png +0 -0
- data/public/plutonium-assets/plutonium-logo-white.png +0 -0
- data/public/plutonium-assets/plutonium-logo.png +0 -0
|
@@ -35,8 +35,8 @@ rails generate pu:rodauth:account user
|
|
|
35
35
|
# Admin with 2FA and security features
|
|
36
36
|
rails generate pu:rodauth:admin admin
|
|
37
37
|
|
|
38
|
-
#
|
|
39
|
-
rails generate pu:
|
|
38
|
+
# SaaS user with entity/organization (multi-tenant)
|
|
39
|
+
rails generate pu:saas:setup --user Customer --entity Organization
|
|
40
40
|
```
|
|
41
41
|
|
|
42
42
|
## Account Generators
|
|
@@ -94,40 +94,132 @@ Creates a secure admin account with:
|
|
|
94
94
|
- Account lockout
|
|
95
95
|
- Active sessions tracking
|
|
96
96
|
- Audit logging
|
|
97
|
-
-
|
|
97
|
+
- Role-based access control
|
|
98
|
+
- Invite interaction for adding new admins
|
|
99
|
+
- No public signup (accounts created via rake task or invite)
|
|
98
100
|
|
|
99
101
|
```bash
|
|
100
102
|
rails generate pu:rodauth:admin admin
|
|
103
|
+
rails generate pu:rodauth:admin admin --roles=super_admin,admin,viewer
|
|
104
|
+
rails generate pu:rodauth:admin admin --extra-attributes=name:string,department:string
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
**Options:**
|
|
108
|
+
|
|
109
|
+
| Option | Default | Description |
|
|
110
|
+
|--------|---------|-------------|
|
|
111
|
+
| `--roles` | super_admin,admin | Comma-separated roles for admin accounts |
|
|
112
|
+
| `--extra_attributes` | | Additional model attributes (e.g., name:string) |
|
|
113
|
+
|
|
114
|
+
**Generated role enum:**
|
|
115
|
+
```ruby
|
|
116
|
+
# app/models/admin.rb
|
|
117
|
+
enum :role, super_admin: 0, admin: 1
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
**Generated invite interaction:**
|
|
121
|
+
```ruby
|
|
122
|
+
# app/interactions/admin/invite_interaction.rb
|
|
123
|
+
class Admin::InviteInteraction < Plutonium::Interaction::Base
|
|
124
|
+
attribute :email, :string
|
|
125
|
+
attribute :role, default: :admin # Second role is default
|
|
126
|
+
|
|
127
|
+
def execute
|
|
128
|
+
# Creates admin via internal request and sends invite email
|
|
129
|
+
end
|
|
130
|
+
end
|
|
101
131
|
```
|
|
102
132
|
|
|
103
133
|
**Creates rake task:**
|
|
104
134
|
```bash
|
|
105
|
-
# Create admin account
|
|
135
|
+
# Create admin account directly
|
|
106
136
|
rails rodauth_admin:create[admin@example.com,password123]
|
|
107
137
|
```
|
|
108
138
|
|
|
109
|
-
###
|
|
139
|
+
### SaaS Setup (`pu:saas:setup`)
|
|
110
140
|
|
|
111
|
-
Creates a
|
|
141
|
+
Creates a complete multi-tenant SaaS setup with user account, entity, and membership:
|
|
112
142
|
|
|
113
143
|
```bash
|
|
114
|
-
rails generate pu:
|
|
115
|
-
rails generate pu:
|
|
116
|
-
rails generate pu:
|
|
144
|
+
rails generate pu:saas:setup --user Customer --entity Organization
|
|
145
|
+
rails generate pu:saas:setup --user Customer --entity Organization --roles=member,admin,owner
|
|
146
|
+
rails generate pu:saas:setup --user Customer --entity Organization --no-allow-signup
|
|
147
|
+
rails generate pu:saas:setup --user Customer --entity Organization --user-attributes=name:string --entity-attributes=slug:string
|
|
117
148
|
```
|
|
118
149
|
|
|
119
150
|
**Options:**
|
|
120
151
|
|
|
121
|
-
| Option | Description |
|
|
122
|
-
|
|
123
|
-
| `--
|
|
124
|
-
| `--
|
|
152
|
+
| Option | Default | Description |
|
|
153
|
+
|--------|---------|-------------|
|
|
154
|
+
| `--user=NAME` | (required) | User account model name (e.g., Customer) |
|
|
155
|
+
| `--entity=NAME` | (required) | Entity model name (e.g., Organization) |
|
|
156
|
+
| `--allow-signup` | true | Allow public registration |
|
|
157
|
+
| `--roles` | member,owner | Comma-separated membership roles |
|
|
158
|
+
| `--skip-entity` | false | Skip entity model generation |
|
|
159
|
+
| `--skip-membership` | false | Skip membership model generation |
|
|
160
|
+
| `--user-attributes` | | Additional user model attributes |
|
|
161
|
+
| `--entity-attributes` | | Additional entity model attributes (name is always included) |
|
|
162
|
+
| `--membership-attributes` | | Additional membership model attributes |
|
|
163
|
+
|
|
164
|
+
**Individual Generators:**
|
|
165
|
+
|
|
166
|
+
You can also run each component separately:
|
|
167
|
+
|
|
168
|
+
```bash
|
|
169
|
+
# Just the user account
|
|
170
|
+
rails g pu:saas:user Customer
|
|
171
|
+
|
|
172
|
+
# Just the entity model
|
|
173
|
+
rails g pu:saas:entity Organization
|
|
174
|
+
|
|
175
|
+
# Just the membership (requires user and entity to exist)
|
|
176
|
+
rails g pu:saas:membership --user Customer --entity Organization
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
**Generated Models:**
|
|
180
|
+
|
|
181
|
+
1. **User account** - The user model with Rodauth authentication
|
|
182
|
+
2. **Entity model** - The organization/company with unique name
|
|
183
|
+
3. **Membership model** - Join table `{entity}_{user}` (e.g., `OrganizationCustomer`)
|
|
125
184
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
185
|
+
```ruby
|
|
186
|
+
# app/models/customer.rb
|
|
187
|
+
class Customer < ApplicationRecord
|
|
188
|
+
include Rodauth::Rails.model(:customer)
|
|
189
|
+
|
|
190
|
+
has_many :organization_customers, dependent: :destroy
|
|
191
|
+
has_many :organizations, through: :organization_customers
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
# app/models/organization.rb
|
|
195
|
+
class Organization < ApplicationRecord
|
|
196
|
+
has_many :organization_customers, dependent: :destroy
|
|
197
|
+
has_many :customers, through: :organization_customers
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
# app/models/organization_customer.rb
|
|
201
|
+
class OrganizationCustomer < ApplicationRecord
|
|
202
|
+
belongs_to :organization
|
|
203
|
+
belongs_to :customer
|
|
204
|
+
|
|
205
|
+
enum :role, member: 0, owner: 1
|
|
206
|
+
|
|
207
|
+
validates :customer, uniqueness: {
|
|
208
|
+
scope: :organization_id,
|
|
209
|
+
message: "is already a member of this organization"
|
|
210
|
+
}
|
|
211
|
+
end
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
**Membership Roles:**
|
|
215
|
+
|
|
216
|
+
The membership model includes a role enum for access control within the entity:
|
|
217
|
+
|
|
218
|
+
```ruby
|
|
219
|
+
membership = OrganizationCustomer.find_by(organization: org, customer: current_user)
|
|
220
|
+
membership.member? # Default role
|
|
221
|
+
membership.owner? # Admin role for the entity
|
|
222
|
+
```
|
|
131
223
|
|
|
132
224
|
## Connecting Auth to Controllers
|
|
133
225
|
|
|
@@ -450,3 +542,4 @@ User.create!(
|
|
|
450
542
|
- `plutonium-installation` - Initial Plutonium setup
|
|
451
543
|
- `plutonium-portal` - Portal configuration
|
|
452
544
|
- `plutonium-policy` - Authorization after authentication
|
|
545
|
+
- `plutonium-invites` - User invitation system for multi-tenant apps
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,51 @@
|
|
|
1
|
+
## [0.40.0] - 2026-02-04
|
|
2
|
+
|
|
3
|
+
### ๐ Features
|
|
4
|
+
|
|
5
|
+
- *(invites)* Add user invitation system for multi-tenant apps
|
|
6
|
+
- *(generators)* Add roles and extra_attributes options to rodauth generators
|
|
7
|
+
- *(generator)* Add --scope flag to portal generator for entity scoping
|
|
8
|
+
- *(generator)* Add --singular flag to pu:res:conn for singular resources
|
|
9
|
+
- *(generators)* Add pu:lite namespace for SQLite-based services
|
|
10
|
+
- *(generators)* Add pu:saas namespace for multi-tenant SaaS setup
|
|
11
|
+
- *(definition)* Add default_scope method for setting default query scope
|
|
12
|
+
|
|
13
|
+
### ๐ Bug Fixes
|
|
14
|
+
|
|
15
|
+
- *(rodauth)* Scope load_memory to account-specific paths
|
|
16
|
+
- *(generators)* Resolve Thor invoke caching in entity generator
|
|
17
|
+
- *(test)* Use dynamic migration versioning for Rails compatibility
|
|
18
|
+
- *(config)* Wrap SQLite alias in defined? check for compatibility
|
|
19
|
+
- *(test)* Add variants to product policy permitted attributes
|
|
20
|
+
- *(test)* Improve has_one url assertion in resource_url_for test
|
|
21
|
+
- *(generators)* Normalize CamelCase package names and validate resource records
|
|
22
|
+
- *(generators)* Dedupe namespace and read model attrs with --no-model
|
|
23
|
+
- *(templates)* Use local gem path when LOCAL=1
|
|
24
|
+
- *(generators)* Guard against envs gems during template execution
|
|
25
|
+
- *(generators)* Run db:prepare after config in lite generators
|
|
26
|
+
- *(generators)* Restore ResourceController to portal generator
|
|
27
|
+
|
|
28
|
+
### ๐ Refactor
|
|
29
|
+
|
|
30
|
+
- *(generators)* Comment out default policy methods
|
|
31
|
+
|
|
32
|
+
### ๐ Documentation
|
|
33
|
+
|
|
34
|
+
- *(skills)* Add invites skill and update rodauth skill
|
|
35
|
+
- *(guides)* Add user invites guide
|
|
36
|
+
|
|
37
|
+
### ๐งช Testing
|
|
38
|
+
|
|
39
|
+
- *(generators)* Add tests for rodauth and invites generators
|
|
40
|
+
|
|
41
|
+
### โ๏ธ Miscellaneous Tasks
|
|
42
|
+
|
|
43
|
+
- Remove old assets
|
|
44
|
+
## [0.39.2] - 2026-01-27
|
|
45
|
+
|
|
46
|
+
### ๐ Bug Fixes
|
|
47
|
+
|
|
48
|
+
- Handle create and update nested routes
|
|
1
49
|
## [0.39.1] - 2026-01-26
|
|
2
50
|
|
|
3
51
|
### ๐ Bug Fixes
|