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.
Files changed (120) hide show
  1. checksums.yaml +4 -4
  2. data/.claude/skills/plutonium-connect-resource/SKILL.md +19 -1
  3. data/.claude/skills/plutonium-controller/SKILL.md +5 -9
  4. data/.claude/skills/plutonium-definition-query/SKILL.md +10 -2
  5. data/.claude/skills/plutonium-installation/SKILL.md +9 -7
  6. data/.claude/skills/plutonium-invites/SKILL.md +363 -0
  7. data/.claude/skills/plutonium-package/SKILL.md +2 -1
  8. data/.claude/skills/plutonium-portal/SKILL.md +30 -16
  9. data/.claude/skills/plutonium-rodauth/SKILL.md +111 -18
  10. data/CHANGELOG.md +48 -0
  11. data/app/assets/plutonium.css +1 -1
  12. data/config/initializers/sqlite_alias.rb +8 -8
  13. data/docs/.vitepress/config.ts +1 -0
  14. data/docs/getting-started/tutorial/07-author-portal.md +1 -0
  15. data/docs/getting-started/tutorial/08-customizing-ui.md +5 -2
  16. data/docs/guides/adding-resources.md +10 -0
  17. data/docs/guides/authentication.md +15 -8
  18. data/docs/guides/creating-packages.md +13 -8
  19. data/docs/guides/index.md +2 -0
  20. data/docs/guides/search-filtering.md +8 -3
  21. data/docs/guides/user-invites.md +497 -0
  22. data/docs/public/templates/base.rb +5 -1
  23. data/docs/public/templates/lite.rb +42 -0
  24. data/docs/public/templates/pluton8.rb +7 -2
  25. data/docs/reference/controller/index.md +12 -7
  26. data/docs/reference/definition/query.md +12 -3
  27. data/docs/reference/generators/index.md +70 -10
  28. data/docs/reference/portal/index.md +22 -11
  29. data/gemfiles/rails_7.gemfile.lock +1 -1
  30. data/gemfiles/rails_8.0.gemfile.lock +1 -1
  31. data/gemfiles/rails_8.1.gemfile.lock +1 -1
  32. data/lib/generators/pu/gem/active_shrine/active_shrine_generator.rb +31 -0
  33. data/lib/generators/pu/gem/active_shrine/templates/config/initializers/shrine.rb.tt +58 -0
  34. data/lib/generators/pu/gem/annotated/templates/lib/tasks/auto_annotate_models.rake +6 -1
  35. data/lib/generators/pu/gem/dotenv/templates/config/initializers/001_ensure_required_env.rb +3 -0
  36. data/lib/generators/pu/invites/USAGE +27 -0
  37. data/lib/generators/pu/invites/install_generator.rb +364 -0
  38. data/lib/generators/pu/invites/invitable/USAGE +31 -0
  39. data/lib/generators/pu/invites/invitable_generator.rb +143 -0
  40. data/lib/generators/pu/invites/templates/INSTRUCTIONS +22 -0
  41. data/lib/generators/pu/invites/templates/app/interactions/invite_user_interaction.rb.tt +24 -0
  42. data/lib/generators/pu/invites/templates/app/interactions/user_invite_user_interaction.rb.tt +26 -0
  43. data/lib/generators/pu/invites/templates/db/migrate/create_user_invites.rb.tt +47 -0
  44. data/lib/generators/pu/invites/templates/invitable/invitation.html.erb.tt +45 -0
  45. data/lib/generators/pu/invites/templates/invitable/invitation.text.erb.tt +15 -0
  46. data/lib/generators/pu/invites/templates/invitable/invite_user_interaction.rb.tt +33 -0
  47. data/lib/generators/pu/invites/templates/packages/invites/app/controllers/invites/user_invitations_controller.rb.tt +77 -0
  48. data/lib/generators/pu/invites/templates/packages/invites/app/controllers/invites/welcome_controller.rb.tt +68 -0
  49. data/lib/generators/pu/invites/templates/packages/invites/app/definitions/invites/user_invite_definition.rb.tt +23 -0
  50. data/lib/generators/pu/invites/templates/packages/invites/app/interactions/invites/cancel_invite_interaction.rb.tt +7 -0
  51. data/lib/generators/pu/invites/templates/packages/invites/app/interactions/invites/resend_invite_interaction.rb.tt +7 -0
  52. data/lib/generators/pu/invites/templates/packages/invites/app/mailers/invites/user_invite_mailer.rb.tt +34 -0
  53. data/lib/generators/pu/invites/templates/packages/invites/app/models/invites/user_invite.rb.tt +41 -0
  54. data/lib/generators/pu/invites/templates/packages/invites/app/policies/invites/user_invite_policy.rb.tt +33 -0
  55. data/lib/generators/pu/invites/templates/packages/invites/app/views/invites/user_invitations/error.html.erb.tt +24 -0
  56. data/lib/generators/pu/invites/templates/packages/invites/app/views/invites/user_invitations/landing.html.erb.tt +40 -0
  57. data/lib/generators/pu/invites/templates/packages/invites/app/views/invites/user_invitations/show.html.erb.tt +39 -0
  58. data/lib/generators/pu/invites/templates/packages/invites/app/views/invites/user_invitations/signup.html.erb.tt +49 -0
  59. data/lib/generators/pu/invites/templates/packages/invites/app/views/invites/user_invite_mailer/invitation.html.erb.tt +45 -0
  60. data/lib/generators/pu/invites/templates/packages/invites/app/views/invites/user_invite_mailer/invitation.text.erb.tt +15 -0
  61. data/lib/generators/pu/invites/templates/packages/invites/app/views/invites/welcome/pending_invitation.html.erb.tt +23 -0
  62. data/lib/generators/pu/invites/templates/packages/invites/app/views/layouts/invites/invitation.html.erb.tt +33 -0
  63. data/lib/generators/pu/lib/plutonium_generators/concerns/actions.rb +23 -2
  64. data/lib/generators/pu/lib/plutonium_generators/concerns/configures_sqlite.rb +130 -0
  65. data/lib/generators/pu/lib/plutonium_generators/concerns/mounts_engines.rb +72 -0
  66. data/lib/generators/pu/lib/plutonium_generators/concerns/package_selector.rb +4 -2
  67. data/lib/generators/pu/lib/plutonium_generators/model_generator_base.rb +7 -1
  68. data/lib/generators/pu/lite/litestream/litestream_generator.rb +105 -0
  69. data/lib/generators/pu/lite/rails_pulse/rails_pulse_generator.rb +88 -0
  70. data/lib/generators/pu/lite/rails_pulse/templates/config/initializers/rails_pulse.rb.tt +14 -0
  71. data/lib/generators/pu/lite/setup/setup_generator.rb +54 -0
  72. data/lib/generators/pu/lite/solid_cable/solid_cable_generator.rb +65 -0
  73. data/lib/generators/pu/lite/solid_cache/solid_cache_generator.rb +66 -0
  74. data/lib/generators/pu/lite/solid_errors/solid_errors_generator.rb +61 -0
  75. data/lib/generators/pu/lite/solid_queue/solid_queue_generator.rb +107 -0
  76. data/lib/generators/pu/pkg/portal/USAGE +8 -2
  77. data/lib/generators/pu/pkg/portal/portal_generator.rb +11 -1
  78. data/lib/generators/pu/pkg/portal/templates/app/controllers/concerns/controller.rb.tt +2 -0
  79. data/lib/generators/pu/pkg/portal/templates/app/controllers/plutonium_controller.rb.tt +1 -0
  80. data/lib/generators/pu/pkg/portal/templates/app/controllers/resource_controller.rb.tt +7 -0
  81. data/lib/generators/pu/pkg/portal/templates/lib/engine.rb.tt +3 -0
  82. data/lib/generators/pu/res/conn/USAGE +5 -0
  83. data/lib/generators/pu/res/conn/conn_generator.rb +30 -4
  84. data/lib/generators/pu/res/scaffold/scaffold_generator.rb +6 -3
  85. data/lib/generators/pu/res/scaffold/templates/policy.rb.tt +6 -6
  86. data/lib/generators/pu/rodauth/account_generator.rb +36 -11
  87. data/lib/generators/pu/rodauth/admin_generator.rb +55 -0
  88. data/lib/generators/pu/rodauth/install_generator.rb +1 -8
  89. data/lib/generators/pu/rodauth/templates/app/interactions/invite_admin_interaction.rb.tt +25 -0
  90. data/lib/generators/pu/rodauth/templates/app/models/account.rb.tt +6 -2
  91. data/lib/generators/pu/saas/USAGE +22 -0
  92. data/lib/generators/pu/saas/entity/USAGE +19 -0
  93. data/lib/generators/pu/saas/entity_generator.rb +55 -0
  94. data/lib/generators/pu/saas/membership/USAGE +25 -0
  95. data/lib/generators/pu/saas/membership_generator.rb +165 -0
  96. data/lib/generators/pu/saas/setup/USAGE +27 -0
  97. data/lib/generators/pu/saas/setup_generator.rb +98 -0
  98. data/lib/generators/pu/saas/user/USAGE +21 -0
  99. data/lib/generators/pu/saas/user_generator.rb +66 -0
  100. data/lib/plutonium/core/controller.rb +9 -5
  101. data/lib/plutonium/definition/base.rb +3 -1
  102. data/lib/plutonium/definition/scoping.rb +20 -0
  103. data/lib/plutonium/invites/concerns/cancel_invite.rb +44 -0
  104. data/lib/plutonium/invites/concerns/invitable.rb +98 -0
  105. data/lib/plutonium/invites/concerns/invite_token.rb +186 -0
  106. data/lib/plutonium/invites/concerns/invite_user.rb +147 -0
  107. data/lib/plutonium/invites/concerns/resend_invite.rb +66 -0
  108. data/lib/plutonium/invites/controller.rb +226 -0
  109. data/lib/plutonium/invites/pending_invite_check.rb +76 -0
  110. data/lib/plutonium/invites.rb +6 -0
  111. data/lib/plutonium/resource/controllers/queryable.rb +4 -0
  112. data/lib/plutonium/resource/query_object.rb +3 -5
  113. data/lib/plutonium/version.rb +1 -1
  114. data/package.json +1 -1
  115. metadata +64 -7
  116. data/lib/generators/pu/res/entity/entity_generator.rb +0 -158
  117. data/lib/generators/pu/rodauth/customer_generator.rb +0 -101
  118. data/public/plutonium-assets/plutonium-logo-original.png +0 -0
  119. data/public/plutonium-assets/plutonium-logo-white.png +0 -0
  120. data/public/plutonium-assets/plutonium-logo.png +0 -0
@@ -87,6 +87,13 @@ rails generate pu:res:conn Post --dest=admin_portal
87
87
 
88
88
  Creates portal-specific controller, definition, and policy (if needed) and registers the resource in the portal routes.
89
89
 
90
+ #### Options
91
+
92
+ | Option | Description |
93
+ |--------|-------------|
94
+ | `--dest NAME` | Destination portal (prompted if not provided) |
95
+ | `--singular` | Register as a singular resource (e.g., profile, dashboard) |
96
+
90
97
  #### Examples
91
98
 
92
99
  ```bash
@@ -96,6 +103,9 @@ rails generate pu:res:conn Post --dest=admin_portal
96
103
  # Connect multiple resources
97
104
  rails generate pu:res:conn Post Comment --dest=admin_portal
98
105
 
106
+ # Connect a singular resource
107
+ rails generate pu:res:conn Profile --dest=customer_portal --singular
108
+
99
109
  # Interactive mode (prompts for resource and portal)
100
110
  rails generate pu:res:conn
101
111
  ```
@@ -152,6 +162,7 @@ rails generate pu:pkg:portal admin
152
162
  | `--auth NAME` | Rodauth account to authenticate with (e.g., `--auth=user`) |
153
163
  | `--public` | Grant public access (no authentication) |
154
164
  | `--byo` | Bring your own authentication |
165
+ | `--scope CLASS` | Entity class to scope to for multi-tenancy (e.g., `--scope=Organization`) |
155
166
 
156
167
  #### Examples
157
168
 
@@ -167,6 +178,9 @@ rails generate pu:pkg:portal api --public
167
178
 
168
179
  # Bring your own authentication
169
180
  rails generate pu:pkg:portal custom --byo
181
+
182
+ # With entity scoping (multi-tenancy)
183
+ rails generate pu:pkg:portal admin --auth=admin --scope=Organization
170
184
  ```
171
185
 
172
186
  Without flags, the generator prompts for authentication configuration:
@@ -182,6 +196,7 @@ packages/admin_portal/
182
196
  │ ├── controllers/admin_portal/
183
197
  │ │ ├── concerns/controller.rb
184
198
  │ │ ├── plutonium_controller.rb
199
+ │ │ ├── resource_controller.rb
185
200
  │ │ └── dashboard_controller.rb
186
201
  │ ├── definitions/admin_portal/
187
202
  │ ├── policies/admin_portal/
@@ -309,20 +324,65 @@ Creates a rake task for account creation:
309
324
  rails rodauth_admin:create[admin@example.com,password123]
310
325
  ```
311
326
 
312
- ### pu:rodauth:customer
327
+ ## SaaS Generators
313
328
 
314
- Generate a customer account with entity (organization) association.
329
+ ### pu:saas:setup
330
+
331
+ Generate a complete multi-tenant SaaS setup with user, entity, and membership.
315
332
 
316
333
  ```bash
317
- rails generate pu:rodauth:customer customer
318
- rails generate pu:rodauth:customer customer --entity=Organization
334
+ rails generate pu:saas:setup --user Customer --entity Organization
335
+ rails generate pu:saas:setup --user Customer --entity Organization --roles=member,admin,owner
336
+ rails generate pu:saas:setup --user Customer --entity Organization --no-allow-signup
319
337
  ```
320
338
 
339
+ #### Options
340
+
341
+ | Option | Description |
342
+ |--------|-------------|
343
+ | `--user NAME` | User account model name (required) |
344
+ | `--entity NAME` | Entity model name (required) |
345
+ | `--allow-signup` | Allow public registration (default: true) |
346
+ | `--roles` | Comma-separated membership roles (default: member,owner) |
347
+ | `--skip-entity` | Skip entity model generation |
348
+ | `--skip-membership` | Skip membership model generation |
349
+ | `--user-attributes` | Additional user model attributes |
350
+ | `--entity-attributes` | Additional entity model attributes |
351
+ | `--membership-attributes` | Additional membership model attributes |
352
+
321
353
  Creates:
322
- - Customer account model
323
- - Entity model (default: "Entity")
324
- - Membership join model
325
- - Has-many-through associations
354
+ - User account model with Rodauth authentication
355
+ - Entity model with unique name
356
+ - Membership join model with role enum
357
+ - Has-many-through associations with `dependent: :destroy`
358
+
359
+ ### pu:saas:user
360
+
361
+ Generate just a SaaS user account.
362
+
363
+ ```bash
364
+ rails generate pu:saas:user Customer
365
+ rails generate pu:saas:user Customer --no-allow-signup
366
+ rails generate pu:saas:user Customer --extra-attributes=name:string
367
+ ```
368
+
369
+ ### pu:saas:entity
370
+
371
+ Generate just an entity model.
372
+
373
+ ```bash
374
+ rails generate pu:saas:entity Organization
375
+ rails generate pu:saas:entity Organization --extra-attributes=slug:string
376
+ ```
377
+
378
+ ### pu:saas:membership
379
+
380
+ Generate just a membership model (requires user and entity to exist).
381
+
382
+ ```bash
383
+ rails generate pu:saas:membership --user Customer --entity Organization
384
+ rails generate pu:saas:membership --user Customer --entity Organization --roles=member,admin,owner
385
+ ```
326
386
 
327
387
  ## Core Generators
328
388
 
@@ -423,8 +483,8 @@ rails db:migrate
423
483
  ### Adding a New Portal
424
484
 
425
485
  ```bash
426
- # Create customer account type
427
- rails generate pu:rodauth:customer customer
486
+ # Create SaaS setup (user + entity + membership)
487
+ rails generate pu:saas:setup --user Customer --entity Organization
428
488
 
429
489
  # Create portal
430
490
  rails generate pu:pkg:portal customer
@@ -23,12 +23,16 @@ rails generate pu:pkg:portal admin
23
23
  | `--auth NAME` | Rodauth account to authenticate with (e.g., `--auth=user`) |
24
24
  | `--public` | Grant public access (no authentication) |
25
25
  | `--byo` | Bring your own authentication |
26
+ | `--scope CLASS` | Entity class to scope to for multi-tenancy (e.g., `--scope=Organization`) |
26
27
 
27
28
  ```bash
28
29
  # Non-interactive examples
29
30
  rails generate pu:pkg:portal admin --auth=admin
30
31
  rails generate pu:pkg:portal api --public
31
32
  rails generate pu:pkg:portal custom --byo
33
+
34
+ # With entity scoping (multi-tenancy)
35
+ rails generate pu:pkg:portal admin --auth=admin --scope=Organization
32
36
  ```
33
37
 
34
38
  Without flags, the generator prompts interactively for authentication choice.
@@ -174,27 +178,34 @@ end
174
178
 
175
179
  ## Controllers
176
180
 
177
- ### Resource Controllers
181
+ ### Base Controller
178
182
 
179
- Portal-specific controllers inherit from the feature package's controller and include the portal's controller concern:
183
+ ```ruby
184
+ # packages/admin_portal/app/controllers/admin_portal/resource_controller.rb
185
+ module AdminPortal
186
+ class ResourceController < ::ResourceController
187
+ include AdminPortal::Concerns::Controller
188
+ end
189
+ end
190
+ ```
191
+
192
+ ### Resource Controllers
180
193
 
181
194
  ```ruby
182
195
  # packages/admin_portal/app/controllers/admin_portal/posts_controller.rb
183
- class AdminPortal::PostsController < ::PostsController
184
- include AdminPortal::Concerns::Controller
185
-
186
- private
196
+ module AdminPortal
197
+ class PostsController < ResourceController
198
+ private
187
199
 
188
- def build_resource
189
- super.tap do |post|
190
- post.user = current_user
200
+ def build_resource
201
+ super.tap do |post|
202
+ post.user = current_user
203
+ end
191
204
  end
192
205
  end
193
206
  end
194
207
  ```
195
208
 
196
- Controllers are auto-created if not defined. When accessing `AdminPortal::PostsController`, Plutonium will dynamically create it by inheriting from `::PostsController` and including `AdminPortal::Concerns::Controller`.
197
-
198
209
  ## Portal-Specific Overrides
199
210
 
200
211
  ### Definitions
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: ..
3
3
  specs:
4
- plutonium (0.39.0)
4
+ plutonium (0.39.2)
5
5
  action_policy (~> 0.7.0)
6
6
  listen (~> 3.8)
7
7
  pagy (~> 9.0)
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: ..
3
3
  specs:
4
- plutonium (0.39.0)
4
+ plutonium (0.39.2)
5
5
  action_policy (~> 0.7.0)
6
6
  listen (~> 3.8)
7
7
  pagy (~> 9.0)
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: ..
3
3
  specs:
4
- plutonium (0.39.0)
4
+ plutonium (0.39.2)
5
5
  action_policy (~> 0.7.0)
6
6
  listen (~> 3.8)
7
7
  pagy (~> 9.0)
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../../lib/plutonium_generators"
4
+
5
+ module Pu
6
+ module Gem
7
+ class ActiveShrineGenerator < Rails::Generators::Base
8
+ include PlutoniumGenerators::Generator
9
+
10
+ source_root File.expand_path("templates", __dir__)
11
+
12
+ desc "Set up active_shrine for file uploads"
13
+
14
+ class_option :s3, type: :boolean, default: false,
15
+ desc: "Configure S3 storage (adds aws-sdk-s3 gem)"
16
+ class_option :store_dimensions, type: :boolean, default: false,
17
+ desc: "Enable image dimension storage (adds fastimage gem)"
18
+
19
+ def start
20
+ bundle "active_shrine"
21
+ bundle "aws-sdk-s3" if options[:s3]
22
+ bundle "fastimage" if options[:store_dimensions]
23
+
24
+ generate "active_shrine:install"
25
+ template "config/initializers/shrine.rb", force: true
26
+ rescue => e
27
+ exception "#{self.class} failed:", e
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "shrine"
4
+ <%- if options[:s3] -%>
5
+ require "shrine/storage/s3"
6
+ <%- else -%>
7
+ require "shrine/storage/file_system"
8
+ <%- end -%>
9
+
10
+ Shrine.logger = Rails.logger
11
+
12
+ <%- if options[:s3] -%>
13
+ s3_options = {
14
+ bucket: ENV.fetch("S3_BUCKET"),
15
+ region: ENV.fetch("AWS_REGION", "us-east-1"),
16
+ access_key_id: ENV.fetch("AWS_ACCESS_KEY_ID"),
17
+ secret_access_key: ENV.fetch("AWS_SECRET_ACCESS_KEY")
18
+ }
19
+
20
+ Shrine.storages = {
21
+ cache: Shrine::Storage::S3.new(prefix: "cache", **s3_options),
22
+ store: Shrine::Storage::S3.new(**s3_options)
23
+ }
24
+ <%- else -%>
25
+ Shrine.storages = {
26
+ cache: Shrine::Storage::FileSystem.new("public", prefix: "uploads/cache"), # temporary
27
+ store: Shrine::Storage::FileSystem.new("public", prefix: "uploads") # permanent
28
+ }
29
+ <%- end -%>
30
+
31
+ Shrine.plugin :activerecord
32
+ Shrine.plugin :determine_mime_type, analyzer: lambda { |io, analyzers|
33
+ mime_type = analyzers[:marcel].call(io)
34
+ mime_type = analyzers[:file].call(io) if mime_type == "application/octet-stream" || mime_type.nil?
35
+ mime_type = analyzers[:mime_types].call(io) if mime_type == "text/plain"
36
+ mime_type
37
+ }
38
+ Shrine.plugin :instrumentation
39
+ Shrine.plugin :infer_extension, force: true
40
+ <%- if options[:store_dimensions] -%>
41
+ Shrine.plugin :store_dimensions
42
+ <%- end -%>
43
+ Shrine.plugin :pretty_location
44
+ Shrine.plugin :refresh_metadata
45
+ Shrine.plugin :remove_invalid
46
+
47
+ Shrine.plugin :backgrounding
48
+
49
+ Shrine::Attacher.promote_block do
50
+ PromoteShrineAttachmentJob.perform_later(self.class.name, record.class.name, record.id, record.record_type, name.to_s, file_data)
51
+ end
52
+
53
+ Shrine::Attacher.destroy_block do
54
+ DestroyShrineAttachmentJob.perform_later(self.class.name, record.record_type, data)
55
+ end
56
+
57
+ Shrine.plugin :upload_endpoint, url: true
58
+ Shrine.plugin :derivatives, create_on_promote: true
@@ -3,7 +3,12 @@
3
3
  # NOTE: to have a dev-mode tool do its thing in production.
4
4
  return unless Rails.env.development?
5
5
 
6
- require "annotated"
6
+ begin
7
+ require "annotated"
8
+ rescue LoadError
9
+ return
10
+ end
11
+
7
12
  task :set_annotation_options do
8
13
  # You can override any of these by setting an environment variable of the
9
14
  # same name.
@@ -1,5 +1,8 @@
1
1
  return if ENV["SECRET_KEY_BASE_DUMMY"].present?
2
2
 
3
+ # In development/test, only check if dotenv is loaded (process may not have reloaded yet)
4
+ return if Rails.env.local? && !defined?(Dotenv)
5
+
3
6
  # Add required env vars to this list
4
7
  required_env_vars = %w[
5
8
  RAILS_DEFAULT_URL
@@ -0,0 +1,27 @@
1
+ Description:
2
+ Install user invites package with all required files.
3
+
4
+ Example:
5
+ rails g pu:invites:install
6
+
7
+ This will create a packages/invites/ package with:
8
+ packages/invites/app/models/invites/user_invite.rb
9
+ packages/invites/app/mailers/invites/user_invite_mailer.rb
10
+ packages/invites/app/controllers/invites/user_invitations_controller.rb
11
+ packages/invites/app/views/invites/...
12
+ packages/invites/app/interactions/invites/resend_invite_interaction.rb
13
+ packages/invites/app/definitions/invites/user_invite_definition.rb
14
+ packages/invites/app/policies/invites/user_invite_policy.rb
15
+ db/migrate/TIMESTAMP_create_user_invites.rb
16
+
17
+ Options:
18
+ --entity-model=NAME Entity model name for scoping (default: Entity)
19
+ --user-model=NAME User model name (default: User)
20
+ --membership-model=NAME Membership model name (default: <Entity>User)
21
+ --roles=ROLES Comma-separated roles (default: member,admin)
22
+ --rodauth=NAME Rodauth configuration for signup (default: user)
23
+ --enforce-domain Require user email domain to match entity domain
24
+
25
+ After installation, use pu:invites:invitable to connect invitables:
26
+ rails g pu:invites:invitable Tenant
27
+ rails g pu:invites:invitable TeamMember --role=member