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,479 @@
1
+ # Views Reference
2
+
3
+ Complete reference for UI customization with Phlex components.
4
+
5
+ ## Overview
6
+
7
+ Plutonium uses [Phlex](https://www.phlex.fun/) for all view components. Customization happens through:
8
+ - Definition nested classes (pages, forms, tables, displays)
9
+ - Page hooks for injecting content
10
+ - Custom Phlex components
11
+ - ERB view overrides
12
+
13
+ ## Architecture
14
+
15
+ ```
16
+ Definition
17
+ ├── IndexPage → renders Table
18
+ ├── ShowPage → renders Display
19
+ ├── NewPage → renders Form
20
+ ├── EditPage → renders Form
21
+ └── InteractiveActionPage → renders Interaction Form
22
+ ```
23
+
24
+ ## Page Configuration
25
+
26
+ Set titles and descriptions in definitions:
27
+
28
+ ```ruby
29
+ class PostDefinition < ResourceDefinition
30
+ # Page titles
31
+ index_page_title "Blog Posts"
32
+ index_page_description "Manage all published articles"
33
+
34
+ show_page_title "Article Details"
35
+ new_page_title "Write New Article"
36
+ edit_page_title "Edit Article"
37
+
38
+ # Breadcrumbs
39
+ breadcrumbs true # Global default
40
+ index_page_breadcrumbs false # Per-page override
41
+ show_page_breadcrumbs true
42
+ end
43
+ ```
44
+
45
+ ## Custom Page Classes
46
+
47
+ Override page rendering by defining nested classes in your definition:
48
+
49
+ ```ruby
50
+ class PostDefinition < ResourceDefinition
51
+ class ShowPage < ShowPage
52
+ private
53
+
54
+ # Custom title logic
55
+ def page_title
56
+ "#{object.title} - #{object.author.name}"
57
+ end
58
+
59
+ # Add content before the main area
60
+ def render_before_content
61
+ div(class: "alert alert-info") {
62
+ "This post has #{object.comments.count} comments"
63
+ }
64
+ end
65
+
66
+ # Add content after
67
+ def render_after_content
68
+ render RelatedPostsComponent.new(post: object)
69
+ end
70
+
71
+ # Override the toolbar
72
+ def render_toolbar
73
+ div(class: "flex gap-2") {
74
+ button(class: "btn") { "Preview" }
75
+ button(class: "btn btn-primary") { "Publish" }
76
+ }
77
+ end
78
+ end
79
+ end
80
+ ```
81
+
82
+ ## Page Hooks
83
+
84
+ All pages inherit these customization hooks:
85
+
86
+ | Hook | Purpose |
87
+ |------|---------|
88
+ | `render_before_header` | Before entire header section |
89
+ | `render_after_header` | After entire header section |
90
+ | `render_before_breadcrumbs` | Before breadcrumbs |
91
+ | `render_after_breadcrumbs` | After breadcrumbs |
92
+ | `render_before_page_header` | Before title/actions |
93
+ | `render_after_page_header` | After title/actions |
94
+ | `render_before_toolbar` | Before toolbar |
95
+ | `render_after_toolbar` | After toolbar |
96
+ | `render_before_content` | Before main content |
97
+ | `render_after_content` | After main content |
98
+ | `render_before_footer` | Before footer |
99
+ | `render_after_footer` | After footer |
100
+
101
+ ## Form Customization
102
+
103
+ Override form rendering in your definition:
104
+
105
+ ```ruby
106
+ class PostDefinition < ResourceDefinition
107
+ class Form < Form
108
+ def form_template
109
+ # Custom layout with sections
110
+ div(class: "grid grid-cols-2 gap-6") {
111
+ div {
112
+ h3(class: "text-lg font-medium") { "Basic Info" }
113
+ render_resource_field :title
114
+ render_resource_field :slug
115
+ }
116
+
117
+ div {
118
+ h3(class: "text-lg font-medium") { "Content" }
119
+ render_resource_field :content
120
+ }
121
+ }
122
+
123
+ div(class: "mt-6") {
124
+ h3(class: "text-lg font-medium") { "Publishing" }
125
+ render_resource_field :published_at
126
+ render_resource_field :category
127
+ }
128
+
129
+ render_actions
130
+ end
131
+ end
132
+ end
133
+ ```
134
+
135
+ ### Form Methods
136
+
137
+ | Method | Purpose |
138
+ |--------|---------|
139
+ | `render_fields` | Render all permitted fields |
140
+ | `render_resource_field(name)` | Render a single field |
141
+ | `render_actions` | Render submit buttons |
142
+ | `record` / `object` | The form object |
143
+ | `resource_fields` | List of permitted field names |
144
+ | `resource_definition` | The definition instance |
145
+
146
+ ## Display Customization
147
+
148
+ Override show page detail rendering:
149
+
150
+ ```ruby
151
+ class PostDefinition < ResourceDefinition
152
+ class Display < Display
153
+ def display_template
154
+ # Hero section
155
+ div(class: "bg-gradient-to-r from-blue-500 to-purple-600 p-8 rounded-lg text-white mb-6") {
156
+ h1(class: "text-3xl font-bold") { object.title }
157
+ p(class: "mt-2 opacity-90") { object.excerpt }
158
+ }
159
+
160
+ # Main content
161
+ Block do
162
+ fields_wrapper do
163
+ render_resource_field :author
164
+ render_resource_field :published_at
165
+ render_resource_field :category
166
+ end
167
+ end
168
+
169
+ # Full-width content
170
+ Block do
171
+ div(class: "prose max-w-none") {
172
+ raw object.content
173
+ }
174
+ end
175
+
176
+ # Associations (tabs)
177
+ render_associations if present_associations?
178
+ end
179
+ end
180
+ end
181
+ ```
182
+
183
+ ### Display Methods
184
+
185
+ | Method | Purpose |
186
+ |--------|---------|
187
+ | `render_fields` | Render all permitted fields in a block |
188
+ | `render_resource_field(name)` | Render single field |
189
+ | `render_associations` | Render association tabs |
190
+ | `object` | The record being displayed |
191
+ | `resource_fields` | List of permitted field names |
192
+ | `resource_associations` | List of permitted associations |
193
+
194
+ ## Table Customization
195
+
196
+ Override index page table:
197
+
198
+ ```ruby
199
+ class PostDefinition < ResourceDefinition
200
+ class Table < Table
201
+ def view_template
202
+ render_search_bar
203
+ render_scopes_bar
204
+
205
+ if collection.empty?
206
+ render_empty_card
207
+ else
208
+ # Custom card grid instead of table
209
+ div(class: "grid grid-cols-3 gap-4") {
210
+ collection.each do |post|
211
+ render PostCardComponent.new(post:)
212
+ end
213
+ }
214
+ end
215
+
216
+ render_footer
217
+ end
218
+ end
219
+ end
220
+ ```
221
+
222
+ ### Table Methods
223
+
224
+ | Method | Purpose |
225
+ |--------|---------|
226
+ | `render_search_bar` | Search input |
227
+ | `render_scopes_bar` | Scope tabs |
228
+ | `render_table` | Default table |
229
+ | `render_empty_card` | Empty state |
230
+ | `render_footer` | Pagination |
231
+ | `collection` | The paginated records |
232
+ | `resource_fields` | Column field names |
233
+
234
+ ## Component Kit
235
+
236
+ Plutonium provides shorthand methods for common components:
237
+
238
+ ```ruby
239
+ class MyPage < Plutonium::UI::Page::Base
240
+ def view_template
241
+ # These are automatically rendered
242
+ PageHeader(title: "Dashboard")
243
+
244
+ Panel(class: "mt-4") {
245
+ p { "Content here" }
246
+ }
247
+
248
+ Block {
249
+ TabList(items: tabs)
250
+ }
251
+
252
+ EmptyCard("No items found")
253
+
254
+ ActionButton(action, url: "/posts/new")
255
+ end
256
+ end
257
+ ```
258
+
259
+ Available kit methods:
260
+
261
+ | Method | Purpose |
262
+ |--------|---------|
263
+ | `Breadcrumbs()` | Navigation breadcrumbs |
264
+ | `PageHeader(title:, description:, actions:)` | Page header with actions |
265
+ | `Panel(**attrs)` | Content panel |
266
+ | `Block(**attrs)` | Content block |
267
+ | `TabList(items:)` | Tab navigation |
268
+ | `EmptyCard(message)` | Empty state card |
269
+ | `ActionButton(action, url:)` | Action button |
270
+ | `DynaFrameHost()` / `DynaFrameContent()` | Turbo frame helpers |
271
+ | `TableSearchBar()` | Search bar for tables |
272
+ | `TableScopesBar()` | Scope tabs for tables |
273
+ | `TableInfo(pagy)` | Pagination info |
274
+ | `TablePagination(pagy)` | Pagination links |
275
+ | `FrameNavigatorPanel(title:, src:, panel_id:)` | Frame navigation panel |
276
+
277
+ ## Custom Components
278
+
279
+ ### Creating a Phlex Component
280
+
281
+ ```ruby
282
+ # app/components/post_card_component.rb
283
+ class PostCardComponent < Plutonium::UI::Component::Base
284
+ def initialize(post:)
285
+ @post = post
286
+ end
287
+
288
+ def view_template
289
+ div(class: "bg-white rounded-lg shadow p-4") {
290
+ h3(class: "font-bold") { @post.title }
291
+ p(class: "text-gray-600 mt-2") { @post.excerpt }
292
+
293
+ div(class: "mt-4 flex justify-between items-center") {
294
+ span(class: "text-sm text-gray-500") { @post.published_at&.strftime("%B %d, %Y") }
295
+ a(href: resource_url_for(@post), class: "text-blue-600") { "Read more" }
296
+ }
297
+ }
298
+ end
299
+ end
300
+ ```
301
+
302
+ ### Using Components in Definitions
303
+
304
+ ```ruby
305
+ class PostDefinition < ResourceDefinition
306
+ # Custom display component
307
+ display :status, as: StatusBadgeComponent
308
+
309
+ # Custom input component
310
+ input :color, as: ColorPickerComponent
311
+
312
+ # Block with component
313
+ display :metrics do |field|
314
+ MetricsChartComponent.new(data: field.value)
315
+ end
316
+ end
317
+ ```
318
+
319
+ ## Layout Customization
320
+
321
+ ### Custom Layout Class
322
+
323
+ ```ruby
324
+ # packages/admin_portal/app/views/layouts/admin_portal/resource_layout.rb
325
+ module AdminPortal
326
+ class ResourceLayout < Plutonium::UI::Layout::ResourceLayout
327
+ private
328
+
329
+ # Custom main content area classes
330
+ def main_attributes
331
+ mix(super, { class: "pt-20 lg:ml-64" })
332
+ end
333
+
334
+ # Add custom header content
335
+ def render_before_main
336
+ super
337
+ render AnnouncementBanner.new if Announcement.active.any?
338
+ end
339
+
340
+ # Custom scripts
341
+ def render_body_scripts
342
+ super
343
+ script(src: "/custom-analytics.js")
344
+ end
345
+ end
346
+ end
347
+ ```
348
+
349
+ ### Layout Hooks
350
+
351
+ | Hook | Purpose |
352
+ |------|---------|
353
+ | `render_before_main` | Before main content area |
354
+ | `render_after_main` | After main (modals, etc.) |
355
+ | `render_head` | HTML head section |
356
+ | `render_title` | Page title tag |
357
+ | `render_assets` | CSS/JS assets |
358
+ | `render_body_scripts` | Scripts at end of body |
359
+
360
+ ## Custom ERB Views
361
+
362
+ For complete control, create custom ERB view files:
363
+
364
+ ```
365
+ # Main app (for a PostsController)
366
+ app/views/posts/index.html.erb
367
+ app/views/posts/show.html.erb
368
+
369
+ # Portal-specific
370
+ packages/admin_portal/app/views/admin_portal/posts/show.html.erb
371
+ ```
372
+
373
+ The default views render the page class:
374
+
375
+ ```erb
376
+ <%# app/views/resource/show.html.erb %>
377
+ <%= render current_definition.show_page_class.new %>
378
+ ```
379
+
380
+ Custom view example:
381
+
382
+ ```erb
383
+ <%# app/views/posts/show.html.erb %>
384
+ <div class="max-w-4xl mx-auto">
385
+ <article class="prose lg:prose-xl">
386
+ <h1><%= resource_record!.title %></h1>
387
+ <%= raw resource_record!.content %>
388
+ </article>
389
+
390
+ <div class="mt-8">
391
+ <%= link_to "Edit", resource_url_for(resource_record!, action: :edit), class: "btn" %>
392
+ <%= link_to "Back", resource_url_for(Post), class: "btn" %>
393
+ </div>
394
+ </div>
395
+ ```
396
+
397
+ ## Available Context
398
+
399
+ ### Resource Methods
400
+
401
+ | Method | Description |
402
+ |--------|-------------|
403
+ | `resource_class` | The model class (e.g., `Post`) |
404
+ | `resource_record!` | Current record (raises if not found) |
405
+ | `resource_record?` | Current record (nil if not found) |
406
+ | `current_parent` | Parent record for nested routes |
407
+ | `current_scoped_entity` | Entity for multi-tenant portals |
408
+
409
+ ### Definition & Policy
410
+
411
+ | Method | Description |
412
+ |--------|-------------|
413
+ | `current_definition` | Definition instance for current resource |
414
+ | `current_policy` | Policy instance for current record |
415
+ | `current_authorized_scope` | Scoped collection user can access |
416
+
417
+ ### URL Helpers
418
+
419
+ | Method | Description |
420
+ |--------|-------------|
421
+ | `resource_url_for(record)` | URL for a record |
422
+ | `resource_url_for(record, action: :edit)` | Action URL for record |
423
+ | `resource_url_for(Model)` | Index URL for model |
424
+ | `resource_url_for(Model, action: :new)` | New URL for model |
425
+ | `resource_url_for(record, parent: parent)` | Nested resource URL |
426
+
427
+ ### Display Helpers
428
+
429
+ | Method | Description |
430
+ |--------|-------------|
431
+ | `display_name_of(record)` | Human-readable name for record |
432
+ | `resource_name(klass)` | Singular model name |
433
+ | `resource_name_plural(klass)` | Plural model name |
434
+
435
+ ### In Phlex Components
436
+
437
+ ```ruby
438
+ class MyComponent < Plutonium::UI::Component::Base
439
+ def view_template
440
+ # Plutonium methods work directly
441
+ current_user
442
+ resource_record!
443
+ resource_url_for(@post)
444
+
445
+ # Rails helpers via helpers proxy
446
+ helpers.link_to(...)
447
+ helpers.image_tag(...)
448
+ end
449
+ end
450
+ ```
451
+
452
+ ## Portal-Specific Views
453
+
454
+ Each portal can override views:
455
+
456
+ ```ruby
457
+ # Base definition
458
+ class PostDefinition < ResourceDefinition
459
+ class ShowPage < ShowPage
460
+ # Default behavior
461
+ end
462
+ end
463
+
464
+ # Admin portal override
465
+ class AdminPortal::PostDefinition < ::PostDefinition
466
+ class ShowPage < ShowPage # Inherits from ::PostDefinition::ShowPage
467
+ def render_after_content
468
+ super
469
+ render AdminOnlySection.new(post: object)
470
+ end
471
+ end
472
+ end
473
+ ```
474
+
475
+ ## Related
476
+
477
+ - [Forms Reference](./forms) - Custom form templates and field builders
478
+ - [Theming Guide](/guides/theming) - TailwindCSS and styling
479
+ - [Fields Reference](/reference/definition/fields) - Field configuration
@@ -2,12 +2,19 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
- gem "rails", "~> 7.1.3", ">= 7.1.3.4"
6
- gem "sqlite3", "~> 1.4"
5
+ gem "rails", "~> 7.2"
6
+ gem "sqlite3"
7
7
  gem "puma", ">= 5.0"
8
8
  gem "importmap-rails"
9
9
  gem "turbo-rails"
10
10
  gem "stimulus-rails"
11
+ gem "propshaft"
12
+ gem "rodauth-rails"
13
+ gem "sequel-activerecord_connection"
14
+ gem "tilt"
15
+ gem "bcrypt"
16
+ gem "rotp"
17
+ gem "rqrcode"
11
18
  gem "tzinfo-data", platforms: [:windows, :jruby]
12
19
 
13
20
  gemspec path: "../"