plutonium 0.33.1 → 0.34.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 (143) hide show
  1. checksums.yaml +4 -4
  2. data/# Plutonium: The pre-alpha demo.md +4 -2
  3. data/.claude/skills/assets/SKILL.md +416 -0
  4. data/.claude/skills/connect-resource/SKILL.md +112 -0
  5. data/.claude/skills/controller/SKILL.md +302 -0
  6. data/.claude/skills/create-resource/SKILL.md +240 -0
  7. data/.claude/skills/definition/SKILL.md +218 -0
  8. data/.claude/skills/definition-actions/SKILL.md +386 -0
  9. data/.claude/skills/definition-fields/SKILL.md +474 -0
  10. data/.claude/skills/definition-query/SKILL.md +334 -0
  11. data/.claude/skills/forms/SKILL.md +439 -0
  12. data/.claude/skills/installation/SKILL.md +300 -0
  13. data/.claude/skills/interaction/SKILL.md +382 -0
  14. data/.claude/skills/model/SKILL.md +267 -0
  15. data/.claude/skills/model-features/SKILL.md +286 -0
  16. data/.claude/skills/nested-resources/SKILL.md +274 -0
  17. data/.claude/skills/package/SKILL.md +191 -0
  18. data/.claude/skills/policy/SKILL.md +352 -0
  19. data/.claude/skills/portal/SKILL.md +400 -0
  20. data/.claude/skills/resource/SKILL.md +281 -0
  21. data/.claude/skills/rodauth/SKILL.md +452 -0
  22. data/.claude/skills/views/SKILL.md +563 -0
  23. data/Appraisals +46 -4
  24. data/CHANGELOG.md +32 -1
  25. data/app/assets/plutonium.css +2 -2
  26. data/config/brakeman.ignore +239 -0
  27. data/config/initializers/action_policy.rb +1 -1
  28. data/docs/.vitepress/config.ts +132 -47
  29. data/docs/concepts/architecture.md +226 -0
  30. data/docs/concepts/auto-detection.md +254 -0
  31. data/docs/concepts/index.md +61 -0
  32. data/docs/concepts/packages-portals.md +304 -0
  33. data/docs/concepts/resources.md +224 -0
  34. data/docs/cookbook/blog.md +412 -0
  35. data/docs/cookbook/index.md +289 -0
  36. data/docs/cookbook/saas.md +481 -0
  37. data/docs/getting-started/index.md +56 -0
  38. data/docs/getting-started/installation.md +146 -0
  39. data/docs/getting-started/tutorial/01-setup.md +118 -0
  40. data/docs/getting-started/tutorial/02-first-resource.md +180 -0
  41. data/docs/getting-started/tutorial/03-authentication.md +246 -0
  42. data/docs/getting-started/tutorial/04-authorization.md +170 -0
  43. data/docs/getting-started/tutorial/05-custom-actions.md +202 -0
  44. data/docs/getting-started/tutorial/06-nested-resources.md +147 -0
  45. data/docs/getting-started/tutorial/07-customizing-ui.md +254 -0
  46. data/docs/getting-started/tutorial/index.md +64 -0
  47. data/docs/guides/adding-resources.md +420 -0
  48. data/docs/guides/authentication.md +551 -0
  49. data/docs/guides/authorization.md +468 -0
  50. data/docs/guides/creating-packages.md +380 -0
  51. data/docs/guides/custom-actions.md +523 -0
  52. data/docs/guides/index.md +45 -0
  53. data/docs/guides/multi-tenancy.md +302 -0
  54. data/docs/guides/nested-resources.md +411 -0
  55. data/docs/guides/search-filtering.md +266 -0
  56. data/docs/guides/theming.md +321 -0
  57. data/docs/index.md +67 -26
  58. data/docs/public/CLAUDE.md +64 -21
  59. data/docs/reference/assets/index.md +496 -0
  60. data/docs/reference/controller/index.md +363 -0
  61. data/docs/reference/definition/actions.md +400 -0
  62. data/docs/reference/definition/fields.md +350 -0
  63. data/docs/reference/definition/index.md +252 -0
  64. data/docs/reference/definition/query.md +342 -0
  65. data/docs/reference/generators/index.md +469 -0
  66. data/docs/reference/index.md +49 -0
  67. data/docs/reference/interaction/index.md +445 -0
  68. data/docs/reference/model/features.md +248 -0
  69. data/docs/reference/model/index.md +219 -0
  70. data/docs/reference/policy/index.md +385 -0
  71. data/docs/reference/portal/index.md +382 -0
  72. data/docs/reference/views/forms.md +396 -0
  73. data/docs/reference/views/index.md +479 -0
  74. data/gemfiles/rails_7.gemfile +9 -2
  75. data/gemfiles/rails_7.gemfile.lock +146 -111
  76. data/gemfiles/rails_8.0.gemfile +20 -0
  77. data/gemfiles/rails_8.0.gemfile.lock +417 -0
  78. data/gemfiles/rails_8.1.gemfile +20 -0
  79. data/gemfiles/rails_8.1.gemfile.lock +419 -0
  80. data/lib/generators/pu/gem/dotenv/templates/.env +2 -0
  81. data/lib/generators/pu/gem/dotenv/templates/config/initializers/001_ensure_required_env.rb +3 -1
  82. data/lib/generators/pu/lib/plutonium_generators/model_generator_base.rb +13 -16
  83. data/lib/generators/pu/pkg/portal/USAGE +65 -0
  84. data/lib/generators/pu/pkg/portal/portal_generator.rb +22 -9
  85. data/lib/generators/pu/res/conn/USAGE +71 -0
  86. data/lib/generators/pu/res/model/USAGE +106 -110
  87. data/lib/generators/pu/res/model/templates/model.rb.tt +6 -2
  88. data/lib/generators/pu/res/scaffold/USAGE +85 -0
  89. data/lib/generators/pu/rodauth/install_generator.rb +2 -6
  90. data/lib/generators/pu/rodauth/templates/config/initializers/url_options.rb +17 -0
  91. data/lib/generators/pu/skills/sync/USAGE +14 -0
  92. data/lib/generators/pu/skills/sync/sync_generator.rb +66 -0
  93. data/lib/plutonium/action_policy/sti_policy_lookup.rb +1 -1
  94. data/lib/plutonium/core/controller.rb +2 -2
  95. data/lib/plutonium/interaction/base.rb +1 -0
  96. data/lib/plutonium/package/engine.rb +2 -2
  97. data/lib/plutonium/query/adhoc_block.rb +6 -2
  98. data/lib/plutonium/query/model_scope.rb +1 -1
  99. data/lib/plutonium/railtie.rb +4 -0
  100. data/lib/plutonium/resource/controllers/crud_actions/index_action.rb +1 -1
  101. data/lib/plutonium/resource/query_object.rb +38 -8
  102. data/lib/plutonium/ui/table/components/scopes_bar.rb +39 -34
  103. data/lib/plutonium/version.rb +1 -1
  104. data/lib/tasks/release.rake +19 -4
  105. data/package.json +1 -1
  106. metadata +76 -39
  107. data/brakeman.ignore +0 -28
  108. data/docs/api-examples.md +0 -49
  109. data/docs/guide/claude-code-guide.md +0 -74
  110. data/docs/guide/deep-dive/authorization.md +0 -189
  111. data/docs/guide/deep-dive/multitenancy.md +0 -256
  112. data/docs/guide/deep-dive/resources.md +0 -390
  113. data/docs/guide/getting-started/01-installation.md +0 -165
  114. data/docs/guide/index.md +0 -28
  115. data/docs/guide/introduction/01-what-is-plutonium.md +0 -211
  116. data/docs/guide/introduction/02-core-concepts.md +0 -440
  117. data/docs/guide/tutorial/01-project-setup.md +0 -75
  118. data/docs/guide/tutorial/02-creating-a-feature-package.md +0 -45
  119. data/docs/guide/tutorial/03-defining-resources.md +0 -90
  120. data/docs/guide/tutorial/04-creating-a-portal.md +0 -101
  121. data/docs/guide/tutorial/05-customizing-the-ui.md +0 -128
  122. data/docs/guide/tutorial/06-adding-custom-actions.md +0 -101
  123. data/docs/guide/tutorial/07-implementing-authorization.md +0 -90
  124. data/docs/markdown-examples.md +0 -85
  125. data/docs/modules/action.md +0 -244
  126. data/docs/modules/authentication.md +0 -236
  127. data/docs/modules/configuration.md +0 -599
  128. data/docs/modules/controller.md +0 -443
  129. data/docs/modules/core.md +0 -316
  130. data/docs/modules/definition.md +0 -1308
  131. data/docs/modules/display.md +0 -759
  132. data/docs/modules/form.md +0 -495
  133. data/docs/modules/generator.md +0 -400
  134. data/docs/modules/index.md +0 -167
  135. data/docs/modules/interaction.md +0 -642
  136. data/docs/modules/package.md +0 -151
  137. data/docs/modules/policy.md +0 -176
  138. data/docs/modules/portal.md +0 -710
  139. data/docs/modules/query.md +0 -297
  140. data/docs/modules/resource_record.md +0 -618
  141. data/docs/modules/routing.md +0 -690
  142. data/docs/modules/table.md +0 -301
  143. data/docs/modules/ui.md +0 -631
@@ -0,0 +1,452 @@
1
+ ---
2
+ name: rodauth
3
+ description: Plutonium Rodauth integration - authentication setup, account types, and configuration
4
+ ---
5
+
6
+ # Plutonium Rodauth Authentication
7
+
8
+ Plutonium integrates with [Rodauth](http://rodauth.jeremyevans.net/) via [rodauth-rails](https://github.com/janko/rodauth-rails) for authentication. This provides a full-featured, secure authentication system.
9
+
10
+ ## Installation
11
+
12
+ ### Step 1: Install Rodauth Base
13
+
14
+ ```bash
15
+ rails generate pu:rodauth:install
16
+ ```
17
+
18
+ This installs:
19
+ - Required gems (`rodauth-rails`, `bcrypt`, `sequel-activerecord_connection`)
20
+ - `app/rodauth/rodauth_app.rb` - Main Roda app
21
+ - `app/rodauth/rodauth_plugin.rb` - Base plugin
22
+ - `app/controllers/rodauth_controller.rb` - Base controller
23
+ - `config/initializers/rodauth.rb` - Configuration
24
+ - `app/views/layouts/rodauth.html.erb` - Auth layout
25
+ - PostgreSQL extension migration (if using PostgreSQL)
26
+
27
+ ### Step 2: Create Account Type
28
+
29
+ Choose the appropriate generator for your use case:
30
+
31
+ ```bash
32
+ # Basic user account
33
+ rails generate pu:rodauth:account user
34
+
35
+ # Admin with 2FA and security features
36
+ rails generate pu:rodauth:admin admin
37
+
38
+ # Customer with entity association
39
+ rails generate pu:rodauth:customer customer
40
+ ```
41
+
42
+ ## Account Generators
43
+
44
+ ### Basic Account (`pu:rodauth:account`)
45
+
46
+ Creates a standard user account with configurable features:
47
+
48
+ ```bash
49
+ rails generate pu:rodauth:account user [options]
50
+ ```
51
+
52
+ **Options:**
53
+
54
+ | Option | Description |
55
+ |--------|-------------|
56
+ | `--defaults` | Enable default features (login, logout, remember, password reset) |
57
+ | `--kitchen_sink` | Enable ALL available features |
58
+ | `--primary` | Mark as primary account (no URL prefix) |
59
+ | `--no-mails` | Skip mailer setup |
60
+ | `--argon2` | Use Argon2 instead of bcrypt for password hashing |
61
+ | `--api_only` | Configure for JSON API only (no sessions) |
62
+
63
+ **Feature Options:**
64
+
65
+ | Option | Default | Description |
66
+ |--------|---------|-------------|
67
+ | `--login` | ✓ | Login functionality |
68
+ | `--logout` | ✓ | Logout functionality |
69
+ | `--remember` | ✓ | "Remember me" cookies |
70
+ | `--create_account` | ✓ | User registration |
71
+ | `--verify_account` | ✓ | Email verification |
72
+ | `--reset_password` | ✓ | Password reset via email |
73
+ | `--change_password` | ✓ | Change password |
74
+ | `--change_login` | ✓ | Change email |
75
+ | `--verify_login_change` | ✓ | Verify email change |
76
+ | `--otp` | | TOTP two-factor auth |
77
+ | `--webauthn` | | WebAuthn/passkeys |
78
+ | `--recovery_codes` | | Recovery codes for 2FA |
79
+ | `--lockout` | | Account lockout after failed attempts |
80
+ | `--active_sessions` | | Track active sessions |
81
+ | `--audit_logging` | | Audit authentication events |
82
+ | `--close_account` | | Allow account deletion |
83
+ | `--email_auth` | | Passwordless login via email |
84
+ | `--sms_codes` | | SMS-based 2FA |
85
+ | `--jwt` | | JWT token authentication |
86
+ | `--jwt_refresh` | | JWT refresh tokens |
87
+
88
+ ### Admin Account (`pu:rodauth:admin`)
89
+
90
+ Creates a secure admin account with:
91
+ - Multi-phase login (email first, then password)
92
+ - TOTP two-factor authentication (required)
93
+ - Recovery codes
94
+ - Account lockout
95
+ - Active sessions tracking
96
+ - Audit logging
97
+ - No public signup (accounts created via rake task)
98
+
99
+ ```bash
100
+ rails generate pu:rodauth:admin admin
101
+ ```
102
+
103
+ **Creates rake task:**
104
+ ```bash
105
+ # Create admin account
106
+ rails rodauth_admin:create[admin@example.com,password123]
107
+ ```
108
+
109
+ ### Customer Account (`pu:rodauth:customer`)
110
+
111
+ Creates a customer account with an associated entity (organization/company):
112
+
113
+ ```bash
114
+ rails generate pu:rodauth:customer customer
115
+ rails generate pu:rodauth:customer customer --entity=Organization
116
+ rails generate pu:rodauth:customer customer --no-allow_signup
117
+ ```
118
+
119
+ **Options:**
120
+
121
+ | Option | Description |
122
+ |--------|-------------|
123
+ | `--entity=NAME` | Entity model name (default: "Entity") |
124
+ | `--no-allow_signup` | Disable public registration |
125
+
126
+ This creates:
127
+ - Customer account model
128
+ - Entity model (Organization, Company, etc.)
129
+ - Membership join model
130
+ - Has-many-through associations
131
+
132
+ ## Connecting Auth to Controllers
133
+
134
+ ### Include in Resource Controller
135
+
136
+ ```ruby
137
+ # app/controllers/resource_controller.rb
138
+ class ResourceController < PlutoniumController
139
+ include Plutonium::Resource::Controller
140
+ include Plutonium::Auth::Rodauth(:user) # Use :user account
141
+ end
142
+ ```
143
+
144
+ ### Multiple Account Types
145
+
146
+ ```ruby
147
+ # app/controllers/admin_controller.rb
148
+ class AdminController < PlutoniumController
149
+ include Plutonium::Resource::Controller
150
+ include Plutonium::Auth::Rodauth(:admin)
151
+ end
152
+
153
+ # app/controllers/customer_controller.rb
154
+ class CustomerController < PlutoniumController
155
+ include Plutonium::Resource::Controller
156
+ include Plutonium::Auth::Rodauth(:customer)
157
+ end
158
+ ```
159
+
160
+ ### What It Provides
161
+
162
+ Including `Plutonium::Auth::Rodauth(:name)` adds:
163
+
164
+ | Method | Description |
165
+ |--------|-------------|
166
+ | `current_user` | The authenticated account |
167
+ | `logout_url` | URL to logout |
168
+ | `rodauth` | Access to Rodauth instance |
169
+
170
+ ## Generated Files
171
+
172
+ ### Account Structure
173
+
174
+ ```
175
+ app/
176
+ ├── controllers/
177
+ │ └── rodauth/
178
+ │ └── user_controller.rb # Account-specific controller
179
+ ├── mailers/
180
+ │ └── rodauth/
181
+ │ └── user_mailer.rb # Account-specific mailer
182
+ ├── models/
183
+ │ └── user.rb # Account model
184
+ ├── rodauth/
185
+ │ ├── rodauth_app.rb # Main Roda app
186
+ │ ├── rodauth_plugin.rb # Base plugin
187
+ │ └── user_rodauth_plugin.rb # Account-specific config
188
+ ├── policies/
189
+ │ └── user_policy.rb # Account policy
190
+ ├── definitions/
191
+ │ └── user_definition.rb # Account definition
192
+ └── views/
193
+ ├── layouts/
194
+ │ └── rodauth.html.erb # Auth layout
195
+ └── rodauth/
196
+ └── user_mailer/ # Email templates
197
+ ├── reset_password.text.erb
198
+ ├── verify_account.text.erb
199
+ └── ...
200
+ ```
201
+
202
+ ### Plugin Configuration
203
+
204
+ ```ruby
205
+ # app/rodauth/user_rodauth_plugin.rb
206
+ class UserRodauthPlugin < RodauthPlugin
207
+ configure do
208
+ # Features enabled for this account
209
+ enable :login, :logout, :remember, :create_account, ...
210
+
211
+ # URL prefix (non-primary accounts)
212
+ prefix "/users"
213
+
214
+ # Password storage
215
+ account_password_hash_column :password_hash
216
+
217
+ # Controller for views
218
+ rails_controller { Rodauth::UserController }
219
+
220
+ # Model
221
+ rails_account_model { User }
222
+
223
+ # Redirects
224
+ login_redirect "/"
225
+ logout_redirect "/"
226
+
227
+ # Session configuration
228
+ session_key "_user_session"
229
+ remember_cookie_key "_user_remember"
230
+ end
231
+ end
232
+ ```
233
+
234
+ ## Customization
235
+
236
+ ### Custom Login Redirect
237
+
238
+ ```ruby
239
+ # app/rodauth/user_rodauth_plugin.rb
240
+ configure do
241
+ login_redirect { "/dashboard" }
242
+
243
+ # Or dynamically based on user
244
+ login_redirect do
245
+ if rails_account.admin?
246
+ "/admin"
247
+ else
248
+ "/dashboard"
249
+ end
250
+ end
251
+ end
252
+ ```
253
+
254
+ ### Custom Validation
255
+
256
+ ```ruby
257
+ configure do
258
+ # Add custom field validation
259
+ before_create_account do
260
+ throw_error_status(422, "name", "must be present") if param("name").empty?
261
+ end
262
+
263
+ # After account creation
264
+ after_create_account do
265
+ Profile.create!(account_id: account_id, name: param("name"))
266
+ end
267
+ end
268
+ ```
269
+
270
+ ### Password Requirements
271
+
272
+ ```ruby
273
+ configure do
274
+ # Minimum length
275
+ password_minimum_length 12
276
+
277
+ # Custom complexity
278
+ password_meets_requirements? do |password|
279
+ super(password) && password.match?(/\d/) && password.match?(/[^a-zA-Z\d]/)
280
+ end
281
+ end
282
+ ```
283
+
284
+ ### Multi-Phase Login
285
+
286
+ ```ruby
287
+ configure do
288
+ # Ask for email first, then password
289
+ use_multi_phase_login? true
290
+ end
291
+ ```
292
+
293
+ ### Prevent Public Signup
294
+
295
+ ```ruby
296
+ configure do
297
+ before_create_account_route do
298
+ request.halt unless internal_request?
299
+ end
300
+ end
301
+ ```
302
+
303
+ ## Email Configuration
304
+
305
+ Emails are sent via Action Mailer. Configure delivery in your environment:
306
+
307
+ ```ruby
308
+ # config/environments/production.rb
309
+ config.action_mailer.delivery_method = :smtp
310
+ config.action_mailer.smtp_settings = {
311
+ address: "smtp.example.com",
312
+ port: 587,
313
+ user_name: ENV["SMTP_USER"],
314
+ password: ENV["SMTP_PASSWORD"]
315
+ }
316
+ ```
317
+
318
+ ### Custom Email Templates
319
+
320
+ Override templates in `app/views/rodauth/user_mailer/`:
321
+
322
+ ```erb
323
+ <%# app/views/rodauth/user_mailer/reset_password.text.erb %>
324
+ Hi <%= @account.email %>,
325
+
326
+ Someone requested a password reset for your account.
327
+
328
+ Reset your password: <%= @reset_password_url %>
329
+
330
+ If you didn't request this, ignore this email.
331
+ ```
332
+
333
+ ## Portal Integration
334
+
335
+ ### Selecting Auth for Portal
336
+
337
+ When generating a portal, select the Rodauth account:
338
+
339
+ ```bash
340
+ rails generate pu:pkg:portal admin
341
+ # Select "Rodauth account" when prompted
342
+ # Choose "admin" account
343
+ ```
344
+
345
+ ### Manual Portal Auth Setup
346
+
347
+ ```ruby
348
+ # packages/admin_portal/lib/engine.rb
349
+ module AdminPortal
350
+ class Engine < Rails::Engine
351
+ include Plutonium::Portal::Engine
352
+
353
+ # Require authentication
354
+ config.before_initialize do
355
+ config.to_prepare do
356
+ AdminPortal::ResourceController.class_eval do
357
+ include Plutonium::Auth::Rodauth(:admin)
358
+
359
+ before_action :require_authenticated
360
+
361
+ private
362
+
363
+ def require_authenticated
364
+ redirect_to rodauth.login_path unless current_user
365
+ end
366
+ end
367
+ end
368
+ end
369
+ end
370
+ end
371
+ ```
372
+
373
+ ## API Authentication
374
+
375
+ For JSON API authentication:
376
+
377
+ ```bash
378
+ rails generate pu:rodauth:account api_user --api_only --jwt --jwt_refresh
379
+ ```
380
+
381
+ This enables:
382
+ - JWT token authentication
383
+ - Refresh tokens
384
+ - No session/cookie handling
385
+
386
+ ### Using JWT
387
+
388
+ ```ruby
389
+ # Login
390
+ POST /api_users/login
391
+ Content-Type: application/json
392
+
393
+ {"login": "user@example.com", "password": "secret"}
394
+
395
+ # Response includes JWT
396
+ {"access_token": "...", "refresh_token": "..."}
397
+
398
+ # Authenticated requests
399
+ GET /api/posts
400
+ Authorization: Bearer <access_token>
401
+ ```
402
+
403
+ ## Internal Requests
404
+
405
+ Create accounts programmatically:
406
+
407
+ ```ruby
408
+ # Using internal request
409
+ Rodauth::Rails.app(:user).rodauth(:user).create_account(
410
+ login: "user@example.com",
411
+ password: "secure_password"
412
+ )
413
+
414
+ # Or via model (if allowed)
415
+ User.create!(
416
+ email: "user@example.com",
417
+ password_hash: BCrypt::Password.create("secure_password"),
418
+ status: 2 # verified
419
+ )
420
+ ```
421
+
422
+ ## Feature Reference
423
+
424
+ | Feature | Description |
425
+ |---------|-------------|
426
+ | `login` | Basic login/logout |
427
+ | `create_account` | User registration |
428
+ | `verify_account` | Email verification |
429
+ | `reset_password` | Password reset via email |
430
+ | `change_password` | Change password when logged in |
431
+ | `change_login` | Change email address |
432
+ | `verify_login_change` | Verify email change |
433
+ | `remember` | "Remember me" functionality |
434
+ | `otp` | TOTP two-factor authentication |
435
+ | `sms_codes` | SMS-based 2FA |
436
+ | `recovery_codes` | Backup codes for 2FA |
437
+ | `webauthn` | WebAuthn/passkey authentication |
438
+ | `lockout` | Lock account after failed attempts |
439
+ | `active_sessions` | Track/manage active sessions |
440
+ | `audit_logging` | Log authentication events |
441
+ | `email_auth` | Passwordless email login |
442
+ | `jwt` | JWT token authentication |
443
+ | `jwt_refresh` | JWT refresh tokens |
444
+ | `close_account` | Allow account deletion |
445
+ | `password_expiration` | Force password changes |
446
+ | `disallow_password_reuse` | Prevent password reuse |
447
+
448
+ ## Related Skills
449
+
450
+ - `installation` - Initial Plutonium setup
451
+ - `portal` - Portal configuration
452
+ - `policy` - Authorization after authentication