plutonium 0.50.0 → 0.51.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 (132) hide show
  1. checksums.yaml +4 -4
  2. data/.claude/skills/plutonium/SKILL.md +85 -102
  3. data/.claude/skills/plutonium-app/SKILL.md +572 -0
  4. data/.claude/skills/plutonium-auth/SKILL.md +163 -300
  5. data/.claude/skills/plutonium-behavior/SKILL.md +838 -0
  6. data/.claude/skills/plutonium-resource/SKILL.md +1176 -0
  7. data/.claude/skills/plutonium-tenancy/SKILL.md +655 -0
  8. data/.claude/skills/plutonium-testing/SKILL.md +6 -5
  9. data/.claude/skills/plutonium-ui/SKILL.md +900 -0
  10. data/CHANGELOG.md +27 -2
  11. data/Rakefile +2 -1
  12. data/app/assets/plutonium.css +1 -11
  13. data/app/assets/plutonium.js +1009 -1214
  14. data/app/assets/plutonium.js.map +3 -3
  15. data/app/assets/plutonium.min.js +52 -51
  16. data/app/assets/plutonium.min.js.map +3 -3
  17. data/docs/.vitepress/config.ts +37 -27
  18. data/docs/getting-started/index.md +22 -29
  19. data/docs/getting-started/installation.md +37 -80
  20. data/docs/getting-started/tutorial/index.md +4 -5
  21. data/docs/guides/adding-resources.md +66 -377
  22. data/docs/guides/authentication.md +94 -463
  23. data/docs/guides/authorization.md +124 -370
  24. data/docs/guides/creating-packages.md +94 -296
  25. data/docs/guides/custom-actions.md +121 -441
  26. data/docs/guides/index.md +22 -42
  27. data/docs/guides/multi-tenancy.md +116 -187
  28. data/docs/guides/nested-resources.md +103 -431
  29. data/docs/guides/search-filtering.md +123 -240
  30. data/docs/guides/testing.md +5 -4
  31. data/docs/guides/theming.md +157 -407
  32. data/docs/guides/troubleshooting.md +5 -3
  33. data/docs/guides/user-invites.md +106 -425
  34. data/docs/guides/user-profile.md +76 -243
  35. data/docs/index.md +1 -1
  36. data/docs/reference/app/generators.md +517 -0
  37. data/docs/reference/app/index.md +158 -0
  38. data/docs/reference/app/packages.md +146 -0
  39. data/docs/reference/app/portals.md +377 -0
  40. data/docs/reference/auth/accounts.md +230 -0
  41. data/docs/reference/auth/index.md +88 -0
  42. data/docs/reference/auth/profile.md +185 -0
  43. data/docs/reference/behavior/controllers.md +395 -0
  44. data/docs/reference/behavior/index.md +22 -0
  45. data/docs/reference/behavior/interactions.md +341 -0
  46. data/docs/reference/behavior/policies.md +417 -0
  47. data/docs/reference/index.md +56 -49
  48. data/docs/reference/resource/actions.md +423 -0
  49. data/docs/reference/resource/definition.md +508 -0
  50. data/docs/reference/resource/index.md +50 -0
  51. data/docs/reference/resource/model.md +348 -0
  52. data/docs/reference/resource/query.md +305 -0
  53. data/docs/reference/tenancy/entity-scoping.md +361 -0
  54. data/docs/reference/tenancy/index.md +36 -0
  55. data/docs/reference/tenancy/invites.md +393 -0
  56. data/docs/reference/tenancy/nested-resources.md +267 -0
  57. data/docs/reference/testing/index.md +287 -0
  58. data/docs/reference/ui/assets.md +400 -0
  59. data/docs/reference/ui/components.md +165 -0
  60. data/docs/reference/ui/displays.md +104 -0
  61. data/docs/reference/ui/forms.md +284 -0
  62. data/docs/reference/ui/index.md +30 -0
  63. data/docs/reference/ui/layouts.md +106 -0
  64. data/docs/reference/ui/pages.md +189 -0
  65. data/docs/reference/ui/tables.md +117 -0
  66. data/docs/superpowers/specs/2026-05-09-typeahead-endpoint-design.md +203 -0
  67. data/docs/superpowers/specs/2026-05-12-skill-compaction-design.md +99 -0
  68. data/docs/superpowers/specs/2026-05-13-docs-restructure-design.md +186 -0
  69. data/gemfiles/rails_7.gemfile.lock +1 -1
  70. data/gemfiles/rails_8.0.gemfile.lock +1 -1
  71. data/gemfiles/rails_8.1.gemfile.lock +1 -1
  72. data/lib/generators/pu/core/update/update_generator.rb +0 -20
  73. data/lib/generators/pu/invites/install_generator.rb +1 -0
  74. data/lib/plutonium/definition/base.rb +1 -1
  75. data/lib/plutonium/definition/{views.rb → index_views.rb} +21 -20
  76. data/lib/plutonium/helpers/turbo_helper.rb +11 -0
  77. data/lib/plutonium/helpers/turbo_stream_actions_helper.rb +14 -0
  78. data/lib/plutonium/resource/controller.rb +1 -0
  79. data/lib/plutonium/resource/controllers/crud_actions.rb +19 -1
  80. data/lib/plutonium/resource/controllers/typeahead.rb +180 -0
  81. data/lib/plutonium/resource/policy.rb +7 -0
  82. data/lib/plutonium/routing/mapper_extensions.rb +15 -0
  83. data/lib/plutonium/ui/component/methods.rb +4 -0
  84. data/lib/plutonium/ui/form/base.rb +6 -2
  85. data/lib/plutonium/ui/form/components/json.rb +58 -0
  86. data/lib/plutonium/ui/form/components/resource_select.rb +62 -8
  87. data/lib/plutonium/ui/form/components/secure_association.rb +98 -22
  88. data/lib/plutonium/ui/form/concerns/typeahead_attributes.rb +83 -0
  89. data/lib/plutonium/ui/form/resource.rb +0 -4
  90. data/lib/plutonium/ui/grid/resource.rb +1 -1
  91. data/lib/plutonium/ui/layout/base.rb +1 -0
  92. data/lib/plutonium/ui/page/base.rb +0 -7
  93. data/lib/plutonium/ui/page/index.rb +4 -4
  94. data/lib/plutonium/ui/table/resource.rb +1 -1
  95. data/lib/plutonium/version.rb +1 -1
  96. data/lib/plutonium.rb +8 -0
  97. data/lib/tasks/release.rake +15 -1
  98. data/package.json +10 -10
  99. data/src/css/slim_select.css +4 -0
  100. data/src/js/controllers/slim_select_controller.js +61 -0
  101. data/src/js/turbo/turbo_actions.js +33 -0
  102. data/yarn.lock +553 -543
  103. metadata +44 -33
  104. data/.claude/skills/plutonium-assets/SKILL.md +0 -512
  105. data/.claude/skills/plutonium-controller/SKILL.md +0 -396
  106. data/.claude/skills/plutonium-create-resource/SKILL.md +0 -303
  107. data/.claude/skills/plutonium-definition/SKILL.md +0 -1223
  108. data/.claude/skills/plutonium-entity-scoping/SKILL.md +0 -317
  109. data/.claude/skills/plutonium-forms/SKILL.md +0 -465
  110. data/.claude/skills/plutonium-installation/SKILL.md +0 -331
  111. data/.claude/skills/plutonium-interaction/SKILL.md +0 -413
  112. data/.claude/skills/plutonium-invites/SKILL.md +0 -408
  113. data/.claude/skills/plutonium-model/SKILL.md +0 -440
  114. data/.claude/skills/plutonium-nested-resources/SKILL.md +0 -360
  115. data/.claude/skills/plutonium-package/SKILL.md +0 -198
  116. data/.claude/skills/plutonium-policy/SKILL.md +0 -456
  117. data/.claude/skills/plutonium-portal/SKILL.md +0 -410
  118. data/.claude/skills/plutonium-views/SKILL.md +0 -651
  119. data/docs/reference/assets/index.md +0 -496
  120. data/docs/reference/controller/index.md +0 -412
  121. data/docs/reference/definition/actions.md +0 -462
  122. data/docs/reference/definition/fields.md +0 -383
  123. data/docs/reference/definition/index.md +0 -326
  124. data/docs/reference/definition/query.md +0 -351
  125. data/docs/reference/generators/index.md +0 -648
  126. data/docs/reference/interaction/index.md +0 -449
  127. data/docs/reference/model/features.md +0 -248
  128. data/docs/reference/model/index.md +0 -218
  129. data/docs/reference/policy/index.md +0 -456
  130. data/docs/reference/portal/index.md +0 -379
  131. data/docs/reference/views/forms.md +0 -411
  132. data/docs/reference/views/index.md +0 -544
@@ -1,559 +1,190 @@
1
1
  # Authentication
2
2
 
3
- This guide covers setting up user authentication with Rodauth.
3
+ Add Rodauth-based authentication to your Plutonium app.
4
4
 
5
- ## Overview
5
+ ## Goal
6
6
 
7
- Plutonium uses [Rodauth](http://rodauth.jeremyevans.net/) via [rodauth-rails](https://github.com/janko/rodauth-rails) for authentication, providing:
8
- - User registration and login
9
- - Password reset
10
- - Email verification
11
- - Multi-factor authentication (OTP, WebAuthn, SMS)
12
- - Session management
13
- - Account lockout
7
+ Authenticated users can sign up, log in, change passwords, and reset forgotten passwords. Pages in protected portals are gated.
14
8
 
15
- ## Installation
9
+ ## Quick path — basic user auth
16
10
 
17
- ### New Applications
11
+ ```bash
12
+ # 1. Install Rodauth
13
+ rails generate pu:rodauth:install
18
14
 
19
- The Plutonium template installs Rodauth automatically:
15
+ # 2. Create a user account type
16
+ rails generate pu:rodauth:account user
20
17
 
21
- ```bash
22
- rails new myapp -a propshaft -j esbuild -c tailwind \
23
- -m https://radioactive-labs.github.io/plutonium-core/templates/plutonium.rb
18
+ # 3. Run migrations
19
+ rails db:migrate
20
+
21
+ # 4. Wire auth into a portal
22
+ # (when you run `pu:pkg:portal admin --auth=user`, this happens automatically)
24
23
  ```
25
24
 
26
- ### Existing Applications
25
+ Then mount your portal with the auth constraint:
27
26
 
28
- ```bash
29
- rails g pu:rodauth:install
30
- rails db:migrate
27
+ ```ruby
28
+ # config/routes.rb
29
+ Rails.application.routes.draw do
30
+ constraints Rodauth::Rails.authenticate(:user) do
31
+ mount AdminPortal::Engine, at: "/admin"
32
+ end
33
+ end
31
34
  ```
32
35
 
33
- This installs:
34
- - Required gems (`rodauth-rails`, `bcrypt`, `sequel-activerecord_connection`)
35
- - `app/rodauth/rodauth_app.rb` - Main Roda app
36
- - `app/rodauth/rodauth_plugin.rb` - Base plugin
37
- - `app/controllers/rodauth_controller.rb` - Base controller
38
- - `config/initializers/rodauth.rb` - Configuration
36
+ For accounts with more features, options, and admin patterns: see [Reference › Auth › Accounts](/reference/auth/accounts).
39
37
 
40
- ## Creating Account Types
38
+ ## Common variations
41
39
 
42
- ### Basic User Account
40
+ ### Multi-factor auth (TOTP)
43
41
 
44
42
  ```bash
45
- rails g pu:rodauth:account user
46
- rails db:migrate
43
+ rails generate pu:rodauth:account user --otp --recovery_codes
47
44
  ```
48
45
 
49
- **Default features** (enabled with `--defaults`, which is on by default):
50
- - `login`, `logout`, `remember`
51
- - `create_account`, `verify_account`, `verify_account_grace_period`
52
- - `reset_password`, `reset_password_notify`
53
- - `change_login`, `verify_login_change`
54
- - `change_password`, `change_password_notify`
55
- - `case_insensitive_login`, `internal_request`
46
+ Then enable in the user-facing security section (see [User profile](./user-profile)).
56
47
 
57
- ### Admin Account
48
+ ### Hardened admin account
49
+
50
+ For an admin role with 2FA required, lockout, audit logging, and no public signup:
58
51
 
59
52
  ```bash
60
- rails g pu:rodauth:admin admin
61
- rails db:migrate
53
+ rails generate pu:rodauth:admin admin
62
54
  ```
63
55
 
64
- Includes all base features plus:
65
- - Multi-phase login (email first, then password)
66
- - TOTP two-factor authentication (required)
67
- - Recovery codes
68
- - Account lockout
69
- - Active sessions tracking
70
- - Audit logging
71
- - **No public signup** - accounts created via rake task
72
-
73
- ### SaaS Account (Multi-tenant)
56
+ Create the first admin with the rake task:
74
57
 
75
58
  ```bash
76
- rails g pu:saas:setup --user Customer --entity Organization
77
- rails g pu:saas:setup --user Customer --entity Organization --roles=member,admin,owner
78
- rails g pu:saas:setup --user Customer --entity Organization --no-allow-signup
79
- rails db:migrate
59
+ rails rodauth_admin:create[admin@example.com,password123]
80
60
  ```
81
61
 
82
- Creates a complete multi-tenant setup:
83
- - Customer account model with Rodauth authentication
84
- - Organization entity model with unique name
85
- - OrganizationCustomer membership join model with role enum
62
+ ### Multi-tenant SaaS — user + entity + membership in one shot
86
63
 
87
- You can also run individual generators:
88
64
  ```bash
89
- rails g pu:saas:user Customer # Just the user account
90
- rails g pu:saas:entity Organization # Just the entity model
91
- rails g pu:saas:membership --user Customer --entity Organization # Just the membership
65
+ rails generate pu:saas:setup --user Customer --entity Organization
92
66
  ```
93
67
 
94
- ## Generator Options
68
+ ⚠️ This is a **meta-generator** — it also runs `pu:saas:portal`, `pu:profile:setup`, `pu:saas:welcome`, and `pu:invites:install`. Don't re-run those manually. See [Reference › Auth › Accounts › SaaS setup](/reference/auth/accounts#saas-setup-pu-saas-setup).
95
69
 
96
- ### Feature Options
70
+ ### API-only (JWT)
97
71
 
98
72
  ```bash
99
- # Enable all supported features
100
- rails g pu:rodauth:account user --kitchen_sink
101
-
102
- # Disable default features (explicit selection only)
103
- rails g pu:rodauth:account user --no-defaults
104
-
105
- # Enable specific features
106
- rails g pu:rodauth:account user --otp --recovery_codes --lockout
107
-
108
- # Skip email setup
109
- rails g pu:rodauth:account user --no-mails
110
-
111
- # API-only mode (JWT, no sessions)
112
- rails g pu:rodauth:account user --api_only --jwt --jwt_refresh
113
-
114
- # Use Argon2 instead of bcrypt
115
- rails g pu:rodauth:account user --argon2
116
-
117
- # Mark as primary account (no URL prefix)
118
- rails g pu:rodauth:account user --primary
73
+ rails generate pu:rodauth:account api_user --api_only --jwt --jwt_refresh
119
74
  ```
120
75
 
121
- ### Available Features
122
-
123
- | Feature | Description |
124
- |---------|-------------|
125
- | `login` | Basic login/logout |
126
- | `create_account` | User registration |
127
- | `verify_account` | Email verification |
128
- | `reset_password` | Password reset via email |
129
- | `change_password` | Change password when logged in |
130
- | `change_login` | Change email address |
131
- | `verify_login_change` | Verify email change |
132
- | `remember` | "Remember me" functionality |
133
- | `otp` | TOTP two-factor authentication |
134
- | `sms_codes` | SMS-based 2FA |
135
- | `recovery_codes` | Backup codes for 2FA |
136
- | `webauthn` | WebAuthn/passkey authentication |
137
- | `lockout` | Lock account after failed attempts |
138
- | `active_sessions` | Track/manage active sessions |
139
- | `audit_logging` | Log authentication events |
140
- | `email_auth` | Passwordless email login |
141
- | `jwt` | JWT token authentication |
142
- | `jwt_refresh` | JWT refresh tokens |
143
- | `close_account` | Allow account deletion |
144
-
145
- ## Generated Files
146
-
147
76
  ```
148
- app/
149
- ├── controllers/rodauth/
150
- │ └── user_controller.rb # Account-specific controller
151
- ├── mailers/rodauth/
152
- │ └── user_mailer.rb # Account-specific mailer
153
- ├── models/
154
- │ └── user.rb # Account model
155
- ├── rodauth/
156
- │ ├── rodauth_app.rb # Main Roda app
157
- │ ├── rodauth_plugin.rb # Base plugin
158
- │ └── user_rodauth_plugin.rb # Account-specific config
159
- ├── policies/
160
- │ └── user_policy.rb # Account policy
161
- ├── definitions/
162
- │ └── user_definition.rb # Account definition
163
- └── views/rodauth/
164
- └── user_mailer/ # Email templates
165
- db/migrate/
166
- └── xxx_create_users.rb # Account table migration
77
+ POST /api_users/login
78
+ {"login": "user@example.com", "password": "secret"}
79
+ # {"access_token": "...", "refresh_token": "..."}
167
80
  ```
168
81
 
169
- ## Connecting Auth to Controllers
82
+ ## Connecting a portal to an account type
170
83
 
171
- Include the auth module in your controller to require authentication:
84
+ If you create the portal with `--auth=`, it's wired automatically:
172
85
 
173
- ```ruby
174
- # app/controllers/resource_controller.rb
175
- class ResourceController < PlutoniumController
176
- include Plutonium::Resource::Controller
177
- include Plutonium::Auth::Rodauth(:user)
178
- end
86
+ ```bash
87
+ rails generate pu:pkg:portal customer --auth=user
179
88
  ```
180
89
 
181
- This provides:
182
-
183
- | Method | Description |
184
- |--------|-------------|
185
- | `current_user` | The authenticated account |
186
- | `logout_url` | URL to logout |
187
- | `rodauth` | Access to Rodauth instance |
188
-
189
- ### Portal Configuration
190
-
191
- For portals, include the auth module in the controller concern:
90
+ Manually, edit the portal's controller concern:
192
91
 
193
92
  ```ruby
194
- # packages/admin_portal/app/controllers/admin_portal/concerns/controller.rb
195
- module AdminPortal
196
- module Concerns
197
- module Controller
198
- extend ActiveSupport::Concern
199
- include Plutonium::Portal::Controller
200
- include Plutonium::Auth::Rodauth(:admin)
201
- end
202
- end
93
+ # packages/customer_portal/app/controllers/customer_portal/concerns/controller.rb
94
+ module CustomerPortal::Concerns::Controller
95
+ extend ActiveSupport::Concern
96
+ include Plutonium::Portal::Controller
97
+ include Plutonium::Auth::Rodauth(:user)
203
98
  end
204
99
  ```
205
100
 
206
- ## Accessing the Current User
101
+ Multiple account types different portals use different Rodauth instances:
207
102
 
208
103
  ```ruby
209
- # In controllers
210
- def index
211
- @user_posts = current_user.posts
212
- end
104
+ # Admin portal
105
+ include Plutonium::Auth::Rodauth(:admin)
213
106
 
214
- # In views (helper method)
215
- <% if current_user.present? %>
216
- Welcome, <%= current_user.email %>
217
- <% end %>
107
+ # Customer portal
108
+ include Plutonium::Auth::Rodauth(:user)
218
109
  ```
219
110
 
220
- ## Rodauth Plugin Configuration
111
+ See [Reference App › Portals](/reference/app/portals#controller-concern-auth).
221
112
 
222
- The generated plugin file contains configuration options:
223
-
224
- ```ruby
225
- # app/rodauth/user_rodauth_plugin.rb
226
- class UserRodauthPlugin < RodauthPlugin
227
- configure do
228
- # Features enabled for this account
229
- enable :login, :logout, :remember, :create_account, ...
113
+ ## Customizing the auth flow
230
114
 
231
- # URL prefix (non-primary accounts)
232
- prefix "/users"
115
+ All inside `app/rodauth/<name>_rodauth_plugin.rb`, in the `configure do` block:
233
116
 
234
- # Store password in column (not separate table)
235
- account_password_hash_column :password_hash
236
-
237
- # Controller for views
238
- rails_controller { Rodauth::UserController }
239
-
240
- # Model
241
- rails_account_model { User }
242
-
243
- # Redirects
244
- login_redirect "/"
245
- logout_redirect "/"
246
-
247
- # Session configuration
248
- session_key "_user_session"
249
- remember_cookie_key "_user_remember"
250
- end
251
- end
252
- ```
253
-
254
- ### Custom Login Redirect
117
+ ### Custom login redirect
255
118
 
256
119
  ```ruby
257
- configure do
258
- login_redirect { "/dashboard" }
259
-
260
- # Or dynamically
261
- login_redirect do
262
- if rails_account.admin?
263
- "/admin"
264
- else
265
- "/dashboard"
266
- end
267
- end
120
+ login_redirect do
121
+ rails_account.admin? ? "/admin" : "/dashboard"
268
122
  end
269
123
  ```
270
124
 
271
- ### Password Requirements
125
+ ### After-create hook (e.g. create a profile)
272
126
 
273
127
  ```ruby
274
- configure do
275
- # Minimum length (default: 8)
276
- password_minimum_length 12
277
-
278
- # Custom complexity
279
- password_meets_requirements? do |password|
280
- super(password) && password.match?(/\d/) && password.match?(/[^a-zA-Z\d]/)
281
- end
128
+ after_create_account do
129
+ Profile.create!(account_id: account_id, name: param("name"))
282
130
  end
283
131
  ```
284
132
 
285
- ### Multi-Phase Login
133
+ ### Password requirements
286
134
 
287
135
  ```ruby
288
- configure do
289
- # Ask for email first, then password
290
- use_multi_phase_login? true
136
+ password_minimum_length 12
137
+
138
+ password_meets_requirements? do |password|
139
+ super(password) && password.match?(/\d/) && password.match?(/[^a-zA-Z\d]/)
291
140
  end
292
141
  ```
293
142
 
294
- ### Prevent Public Signup
143
+ ### Prevent public signup
295
144
 
296
145
  ```ruby
297
- configure do
298
- before_create_account_route do
299
- request.halt unless internal_request?
300
- end
146
+ before_create_account_route do
147
+ request.halt unless internal_request?
301
148
  end
302
149
  ```
303
150
 
304
- ## Email Configuration
305
-
306
- Emails are sent via Action Mailer.
151
+ Full customization surface: [Reference › Auth › Accounts › Common customizations](/reference/auth/accounts#common-customizations).
307
152
 
308
- ### Development
309
-
310
- ```ruby
311
- # Gemfile
312
- gem "letter_opener", group: :development
313
-
314
- # config/environments/development.rb
315
- config.action_mailer.delivery_method = :letter_opener
316
- config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }
317
- ```
318
-
319
- ### Production
153
+ ## Email setup (production)
320
154
 
321
155
  ```ruby
322
156
  # config/environments/production.rb
323
157
  config.action_mailer.delivery_method = :smtp
324
158
  config.action_mailer.smtp_settings = {
325
- address: ENV['SMTP_HOST'],
326
- port: ENV['SMTP_PORT'],
327
- user_name: ENV['SMTP_USER'],
328
- password: ENV['SMTP_PASSWORD']
159
+ address: "smtp.example.com",
160
+ port: 587,
161
+ user_name: ENV["SMTP_USER"],
162
+ password: ENV["SMTP_PASSWORD"]
329
163
  }
330
164
  ```
331
165
 
332
- ### Custom Email Templates
333
-
334
- Override templates in `app/views/rodauth/user_mailer/`:
335
-
336
- ```erb
337
- <%# app/views/rodauth/user_mailer/reset_password.text.erb %>
338
- Hi <%= @account.email %>,
339
-
340
- Someone requested a password reset for your account.
341
-
342
- Reset your password: <%= @reset_password_url %>
343
-
344
- If you didn't request this, ignore this email.
345
- ```
346
-
347
- ## Customizing Views
348
-
349
- Generate views to customize:
350
-
351
- ```bash
352
- # Generate views for specific features
353
- rails g pu:rodauth:views user --features login create_account reset_password
354
-
355
- # Generate all views
356
- rails g pu:rodauth:views user --all
357
- ```
358
-
359
- Views are copied to `app/views/rodauth/user/` and can be customized as standard ERB templates.
360
-
361
- ## Multiple Account Types
362
-
363
- ### Different Portals, Different Accounts
364
-
365
- ```ruby
366
- # packages/admin_portal/app/controllers/admin_portal/concerns/controller.rb
367
- module AdminPortal
368
- module Concerns
369
- module Controller
370
- extend ActiveSupport::Concern
371
- include Plutonium::Portal::Controller
372
- include Plutonium::Auth::Rodauth(:admin)
373
- end
374
- end
375
- end
376
-
377
- # packages/customer_portal/app/controllers/customer_portal/concerns/controller.rb
378
- module CustomerPortal
379
- module Concerns
380
- module Controller
381
- extend ActiveSupport::Concern
382
- include Plutonium::Portal::Controller
383
- include Plutonium::Auth::Rodauth(:customer)
384
- end
385
- end
386
- end
387
- ```
388
-
389
- ### Shared Account Type
390
-
391
- Multiple portals can share an account type:
392
-
393
- ```ruby
394
- # Both portals include the same auth module
395
- include Plutonium::Auth::Rodauth(:user)
396
- ```
397
-
398
- ## Public Portals
399
-
400
- For portals that don't require authentication, use `Plutonium::Auth::Public`:
401
-
402
- ```ruby
403
- # packages/public_portal/app/controllers/public_portal/concerns/controller.rb
404
- module PublicPortal
405
- module Concerns
406
- module Controller
407
- extend ActiveSupport::Concern
408
- include Plutonium::Portal::Controller
409
- include Plutonium::Auth::Public
410
- end
411
- end
412
- end
413
- ```
414
-
415
- This provides a `current_user` method that returns `"Guest"`.
416
-
417
- ## Two-Factor Authentication
418
-
419
- ### Enable During Generation
420
-
421
- ```bash
422
- rails g pu:rodauth:account user --otp --recovery_codes
423
- ```
166
+ Override mailer templates in `app/views/rodauth/<account>_mailer/`.
424
167
 
425
- ### Add to Existing Account
168
+ ## Accessing the current user
426
169
 
427
170
  ```ruby
428
- # app/rodauth/user_rodauth_plugin.rb
429
- configure do
430
- enable :otp, :recovery_codes
171
+ # Controllers / views
172
+ current_user
431
173
 
432
- # Require 2FA
433
- two_factor_auth_required? true
434
- end
435
- ```
436
-
437
- Note: The `pu:rodauth:admin` generator automatically enables OTP and recovery codes.
438
-
439
- ## Creating Accounts
440
-
441
- ### Admin Accounts
442
-
443
- Admin accounts are created via rake task (web registration is disabled):
444
-
445
- ```bash
446
- # Interactive prompt for email
447
- rails rodauth:admin
448
-
449
- # With EMAIL environment variable
450
- EMAIL=admin@example.com rails rodauth:admin
451
- ```
452
-
453
- The task name matches the account name (e.g., `rails rodauth:admin` for an account named `admin`).
454
-
455
- ### Programmatic Account Creation
456
-
457
- For accounts with self-registration enabled, use internal requests:
458
-
459
- ```ruby
460
- # Create account via internal request
461
- RodauthApp.rodauth(:user).create_account(
462
- login: "user@example.com",
463
- password: "secure_password"
464
- )
465
- ```
466
-
467
- In seeds:
468
-
469
- ```ruby
470
- # db/seeds.rb
471
- RodauthApp.rodauth(:user).create_account(
472
- login: "user@example.com",
473
- password: "password123"
474
- )
174
+ # Policies
175
+ user
475
176
  ```
476
177
 
477
- ## API Authentication
178
+ ## Common issues
478
179
 
479
- For JSON API authentication:
480
-
481
- ```bash
482
- rails g pu:rodauth:account api_user --api_only --jwt --jwt_refresh
483
- ```
484
-
485
- This enables:
486
- - JWT token authentication
487
- - Refresh tokens
488
- - No session/cookie handling
489
-
490
- ### Using JWT
491
-
492
- ```bash
493
- # Login
494
- curl -X POST http://localhost:3000/api_users/login \
495
- -H "Content-Type: application/json" \
496
- -d '{"login": "user@example.com", "password": "secret"}'
497
-
498
- # Response includes tokens
499
- {"access_token": "...", "refresh_token": "..."}
500
-
501
- # Authenticated requests
502
- curl http://localhost:3000/api/posts \
503
- -H "Authorization: Bearer <access_token>"
504
- ```
505
-
506
- ## Troubleshooting
507
-
508
- ### Routes Not Working
509
-
510
- Restart the server after installing Rodauth:
511
-
512
- ```bash
513
- bin/rails restart
514
- ```
515
-
516
- ### Emails Not Sending
517
-
518
- Check Action Mailer configuration:
519
-
520
- ```ruby
521
- # Verify mailer config
522
- Rails.application.config.action_mailer.delivery_method
523
- Rails.application.config.action_mailer.default_url_options
524
- ```
525
-
526
- Use letter_opener in development to view emails in browser.
527
-
528
- ### Session Issues
529
-
530
- Clear session cookies in the browser, or for active_sessions feature:
531
-
532
- ```ruby
533
- # In rails runner
534
- User.find_by(email: "user@example.com").active_session_keys.delete_all
535
- ```
536
-
537
- ### Migration Issues
538
-
539
- Ensure all migrations have run:
540
-
541
- ```bash
542
- rails db:migrate:status
543
- rails db:migrate
544
- ```
545
-
546
- ### Account Not Verified
547
-
548
- For development, you can manually verify accounts:
549
-
550
- ```ruby
551
- # In rails runner
552
- user = User.find_by(email: "user@example.com")
553
- user.update!(status: 2) # 2 = verified
554
- ```
180
+ - **"You need to set up Rodauth"** — run `pu:rodauth:install` first.
181
+ - **Portal redirects to login even though you're authenticated** — the portal mount constraint references a different Rodauth account than the portal's controller concern uses. Match them up.
182
+ - **Email confirmation never arrives in development** — Plutonium sets ActionMailer to `:test` by default. Check `tmp/letter_opener/` or your mail interceptor. In production, configure SMTP (see above).
555
183
 
556
184
  ## Related
557
185
 
558
- - [Authorization](./authorization)
559
- - [Multi-tenancy](./multi-tenancy)
186
+ - [Reference › Auth](/reference/auth/) — full auth surface
187
+ - [Authorization](./authorization) — controlling who can do what AFTER login
188
+ - [Multi-tenancy](./multi-tenancy) — entity scoping for SaaS apps
189
+ - [User invites](./user-invites) — invitation-based onboarding
190
+ - [User profile](./user-profile) — account-settings page