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
@@ -1,443 +0,0 @@
1
- ---
2
- title: Controller Module
3
- ---
4
-
5
- # Controller Module
6
-
7
- The Controller module is your gateway to handling HTTP requests in Plutonium applications. It combines Rails' ActionController with Plutonium-specific enhancements to create a powerful, convention-over-configuration approach that eliminates boilerplate while providing enterprise-grade features like authorization and multi-tenancy.
8
-
9
- ::: tip Module Organization
10
- Controller functionality is distributed across multiple focused modules:
11
- - `lib/plutonium/core/controller.rb` - Foundation and core utilities
12
- - `lib/plutonium/resource/controller.rb` - Complete CRUD operations
13
- - `lib/plutonium/portal/controller.rb` - Portal-specific features and multi-tenancy
14
- :::
15
-
16
- ## Core Philosophy
17
-
18
- Plutonium's controller system is built on three fundamental principles:
19
-
20
- - **Convention over Configuration**: Intelligent defaults that work out of the box with minimal setup
21
- - **Modular Architecture**: Mix and match functionality based on your needs
22
- - **Enterprise Readiness**: Built-in authentication, authorization and multi-tenancy
23
-
24
- ## Understanding Resource Registration
25
-
26
- Before diving into controllers, it's crucial to understand how Plutonium connects your resources to the web through registration and routing.
27
-
28
- ### Registering Resources
29
-
30
- Resources must be registered with each portal to become accessible through the web interface:
31
-
32
- ```ruby
33
- # packages/admin_portal/config/routes.rb
34
- AdminPortal::Engine.routes.draw do
35
- root to: "dashboard#index"
36
-
37
- # Basic resource registration
38
- register_resource User
39
- register_resource Post
40
- register_resource Comment
41
-
42
- # Advanced registration with options
43
- register_resource Profile, singular: true # Creates singular routes
44
- register_resource Report do
45
- # Add custom routes alongside the standard ones
46
- member do
47
- get :download
48
- post :regenerate
49
- end
50
- end
51
- end
52
- ```
53
-
54
- ### What Registration Gives You
55
-
56
- When you register a resource, Plutonium automatically creates:
57
-
58
- 1. **Complete CRUD routes**: All standard RESTful endpoints
59
- 2. **Nested association routes**: Based on your model's `has_many` relationships
60
- 3. **Interactive action routes**: For custom business operations
61
- 4. **Entity-scoped routes**: If your portal uses multi-tenancy
62
-
63
- ```ruby
64
- # This simple registration:
65
- register_resource Post
66
-
67
- # Automatically generates:
68
- # GET /posts # index - list all posts
69
- # GET /posts/new # new - form for creating posts
70
- # POST /posts # create - handle post creation
71
- # GET /posts/:id # show - display a specific post
72
- # GET /posts/:id/edit # edit - form for editing posts
73
- # PATCH /posts/:id # update - handle post updates
74
- # DELETE /posts/:id # destroy - delete posts
75
-
76
- # Plus interactive action routes:
77
- # GET /posts/resource_actions/:interactive_action # Resource-level actions
78
- # POST /posts/resource_actions/:interactive_action
79
- # GET /posts/:id/record_actions/:interactive_action # Individual record actions
80
- # POST /posts/:id/record_actions/:interactive_action
81
-
82
- # Plus nested routes for associations (if Post has_many :comments):
83
- # GET /posts/:post_id/nested_comments
84
- ```
85
-
86
- ### Entity Scoping in Routes
87
-
88
- If your portal is scoped to an entity (like Organization), all routes are automatically nested:
89
-
90
- ```ruby
91
- # Engine configuration
92
- class AdminPortal::Engine < Rails::Engine
93
- include Plutonium::Portal::Engine
94
- scope_to_entity Organization, strategy: :path
95
- end
96
-
97
- # Your routes become:
98
- # GET /:organization_id/posts
99
- # GET /:organization_id/posts/:id
100
- # All data is automatically scoped to the organization
101
- ```
102
-
103
- ## Controller Components
104
-
105
- ### Base Controller: The Foundation
106
-
107
- Every Plutonium controller starts with `Plutonium::Core::Controller`, which provides essential framework integration:
108
-
109
- ```ruby
110
- # app/controllers/application_controller.rb
111
- class ApplicationController < ActionController::Base
112
- include Plutonium::Core::Controller
113
-
114
- # You now have access to all Plutonium controller features
115
- end
116
- ```
117
-
118
- **Key Capabilities:**
119
- - **Smart URL Generation**: Automatic resource URL creation with proper routing
120
- - **Enhanced Flash Messages**: Extended message types (`:success`, `:warning`, `:error`)
121
- - **View Integration**: Automatic view path resolution and layout management
122
- - **Resource Management**: Access to registered resources and metadata
123
- - **CSRF Protection**: Automatic CSRF protection with smart handling for API requests
124
-
125
- **Essential Methods:**
126
- ```ruby
127
- # URL generation that understands your resource structure
128
- resource_url_for(@user) # => "/users/1"
129
- resource_url_for(@user, action: :edit) # => "/users/1/edit"
130
- resource_url_for(User) # => "/users"
131
-
132
- # Build complex URL arguments for nested resources
133
- resource_url_args_for(@user, Post) # => {controller: "/users/posts", user_id: 1}
134
-
135
- # Access application metadata
136
- registered_resources # => [User, Post, Comment, ...]
137
-
138
- # Page title management
139
- set_page_title("User Profile")
140
- make_page_title("Dashboard") # => "Dashboard | MyApp"
141
- ```
142
-
143
- ### Resource Controller: Complete CRUD Operations
144
-
145
- The Resource Controller provides full CRUD functionality with zero configuration:
146
-
147
- ```ruby
148
- class PostsController < ApplicationController
149
- include Plutonium::Resource::Controller
150
-
151
- # That's it! All CRUD actions are automatically available:
152
- # index, show, new, create, edit, update, destroy
153
- end
154
- ```
155
-
156
- **What You Get Automatically:**
157
- - **Complete CRUD Operations**: All RESTful actions implemented
158
- - **Smart Parameter Handling**: Automatic parameter processing and validation
159
- - **Authorization Integration**: Policy checks on every action
160
- - **Query Integration**: Automatic filtering, searching, and sorting
161
- - **Interaction Support**: Business logic through interaction classes
162
- - **Nested Resource Support**: Handles parent-child relationships automatically
163
- - **Pagination**: Built-in pagination with sensible defaults
164
-
165
- **Key Methods Available:**
166
- ```ruby
167
- # Resource management
168
- resource_class # => Post
169
- resource_record! # => @post (raises if not found)
170
- resource_record? # => @post or nil
171
- current_parent # => parent record for nested routes
172
-
173
- # Parameter handling with automatic authorization
174
- resource_params # => processed params with proper scoping
175
- submitted_resource_params # => raw submitted parameters
176
-
177
- # View builders for consistent UI
178
- build_form # => form builder for the resource
179
- build_detail # => detail view builder
180
- build_collection # => collection view builder
181
-
182
- # Query objects for data access
183
- current_query_object # => handles filtering, searching, sorting
184
- ```
185
-
186
- ### Portal Controller: Multi-Tenancy and Segmentation
187
-
188
- Portal Controllers provide specialized functionality for multi-tenant applications and user segmentation:
189
-
190
- ```ruby
191
- module AdminPortal
192
- class PostsController < ResourceController
193
- include AdminPortal::Concerns::Controller
194
-
195
- # Automatically inherits from ::PostsController
196
- # Includes portal-specific concerns and scoping
197
- end
198
- end
199
- ```
200
-
201
- ## Controller Concerns: Modular Functionality
202
-
203
- Plutonium's controller system uses several modular concerns that provide specific capabilities:
204
-
205
- ### Bootable: Initialization and Setup
206
-
207
- Handles the foundational setup that makes everything work smoothly:
208
-
209
- ```ruby
210
- # Automatically included - provides:
211
- # ✓ Package detection and engine resolution
212
- # ✓ View path configuration for proper template loading
213
- # ✓ Flash message type registration
214
-
215
- # Available methods:
216
- current_package # => current package module (e.g., AdminPortal)
217
- current_engine # => current Rails engine instance
218
- ```
219
-
220
- ### Entity Scoping: Multi-Tenancy Made Simple
221
-
222
- Provides powerful multi-tenancy capabilities with automatic data scoping:
223
-
224
- ```ruby
225
- # Check if the controller is scoped to an entity
226
- scoped_to_entity? # => true/false
227
-
228
- # Get the current scoped entity
229
- current_scoped_entity # => current organization/tenant
230
-
231
- # Access scoping configuration
232
- scoped_entity_strategy # => :path, :subdomain, :custom_method
233
- scoped_entity_param_key # => :organization_id
234
- scoped_entity_class # => Organization
235
- ```
236
-
237
- #### Setting Up Entity Scoping
238
-
239
- Configure scoping at the engine level and implement custom strategies as needed:
240
-
241
- ```ruby
242
- # 1. Configure in your engine
243
- class AdminPortal::Engine < Rails::Engine
244
- include Plutonium::Portal::Engine
245
-
246
- # Path-based scoping (URLs like /organizations/123/posts)
247
- scope_to_entity Organization, strategy: :path
248
-
249
- # Or custom strategy for more control
250
- scope_to_entity Organization, strategy: :current_organization
251
- end
252
-
253
- # 2. For custom strategies, implement the method in your controller concern
254
- module AdminPortal::Concerns::Controller
255
- private
256
-
257
- # Method name MUST match the strategy name exactly
258
- def current_organization
259
- # Custom logic - could be subdomain, session, JWT, etc.
260
- @current_organization ||= begin
261
- # Primary: subdomain lookup
262
- Organization.find_by(subdomain: request.subdomain) ||
263
- # Fallback: session-based lookup
264
- current_user.organizations.find(session[:org_id])
265
- end
266
- end
267
- end
268
- ```
269
-
270
- ### Authorizable: Comprehensive Security
271
-
272
- Integrates with ActionPolicy to provide robust authorization throughout your application:
273
-
274
- ```ruby
275
- # Authorization methods that work automatically
276
- authorize_current!(resource_record!) # Check permissions for current resource
277
- authorize_current!(resource_class) # Check permissions for resource class
278
- authorize_current!(record, to: :interactive_action?) # Check specific action permission
279
-
280
- # Policy access and queries
281
- current_policy # Get policy for current resource
282
- current_policy.allowed_to?(:show?) # Check if action is allowed
283
- policy_for(@user) # Get policy for specific resource
284
- authorized_resource_scope(User) # Get authorized scope for resource class
285
-
286
- # Permission helpers
287
- permitted_attributes # Get allowed attributes for current action
288
- permitted_associations # Get allowed associations
289
- ```
290
-
291
- **Authorization Examples:**
292
- ```ruby
293
- class PostsController < ApplicationController
294
- include Plutonium::Resource::Controller
295
-
296
- def index
297
- # Authorization is automatically checked against PostPolicy#index?
298
- # No additional code needed
299
- end
300
-
301
- def custom_publish
302
- # Check custom permissions
303
- authorize_current!(resource_record!, to: :publish?)
304
-
305
- # Your business logic here
306
- PublishPostInteraction.call(post: resource_record!)
307
-
308
- redirect_to resource_url_for(resource_record!), success: "Post published!"
309
- end
310
-
311
- def conditional_action
312
- # Check permissions before taking action
313
- if current_policy.allowed_to?(:edit?)
314
- redirect_to resource_url_for(resource_record!, action: :edit)
315
- else
316
- redirect_to resource_url_for(resource_record!),
317
- warning: "You don't have permission to edit this post"
318
- end
319
- end
320
-
321
- private
322
-
323
- def resource_params
324
- # Only permit attributes that the policy allows
325
- params.require(:post).permit(*permitted_attributes)
326
- end
327
- end
328
- ```
329
-
330
- ## Advanced Usage Patterns
331
-
332
-
333
- ### Nested Resources: Automatic Relationship Handling
334
-
335
- Plutonium automatically handles nested resources based on your ActiveRecord associations:
336
-
337
- ```ruby
338
- # Your models define the relationships
339
- class User < ResourceRecord
340
- has_many :posts
341
- has_many :comments
342
- end
343
-
344
- class Post < ResourceRecord
345
- belongs_to :user
346
- has_many :comments
347
- end
348
-
349
- # Register resources normally
350
- AdminPortal::Engine.routes.draw do
351
- register_resource User
352
- register_resource Post
353
- register_resource Comment
354
- end
355
-
356
- # Plutonium automatically creates nested routes:
357
- # /users/:user_id/nested_posts
358
- # /users/:user_id/nested_comments
359
- # /posts/:post_id/nested_comments
360
- ```
361
-
362
- **Automatic Parent Resolution:**
363
- ```ruby
364
- # In a nested route like /users/123/nested_posts/456
365
- current_parent # => User.find(123) - automatically resolved
366
- parent_route_param # => :user_id
367
- parent_input_param # => :user (the belongs_to association name)
368
-
369
- # Parameters are automatically merged
370
- resource_params # => includes user: current_parent
371
- ```
372
-
373
- **Smart URL Generation:**
374
- ```ruby
375
- # From within a nested controller context
376
- resource_url_for(Post) # => "/users/123/nested_posts"
377
- resource_url_for(@post) # => "/users/123/nested_posts/456"
378
- resource_url_for(@post, action: :edit) # => "/users/123/nested_posts/456/edit"
379
-
380
- # Explicit parent specification
381
- resource_url_for(Post, parent: @user) # => "/users/123/nested_posts"
382
- ```
383
-
384
- ### Multi-Format Response Handling
385
-
386
- Plutonium automatically handles different response formats for you.
387
- It currently supports HTML, JSON, and Turbo Streams.
388
-
389
- ### CSRF Protection
390
-
391
- Plutonium provides intelligent CSRF (Cross-Site Request Forgery) protection that automatically adapts to different request types:
392
-
393
- ```ruby
394
- # Automatically configured in Plutonium::Core::Controller
395
- protect_from_forgery with: :null_session, if: -> { request.headers['Authorization'].present? }
396
- ```
397
-
398
- **How It Works:**
399
- - **Session-based requests** (typical web forms, SPA AJAX calls): Full CSRF protection is enforced
400
- - **Token-based requests** (API calls with Authorization headers): CSRF protection is skipped using `:null_session`
401
-
402
- **Security Benefits:**
403
- - SPAs using session cookies remain protected against CSRF attacks
404
- - API clients using Bearer tokens, Basic auth, or other Authorization headers bypass CSRF (as intended)
405
- - No configuration needed - works automatically based on request characteristics
406
-
407
- **Authorization Header Examples:**
408
- ```http
409
- # These requests will skip CSRF protection:
410
- Authorization: Bearer eyJhbGciOiJIUzI1NiJ9...
411
- Authorization: Basic dXNlcjpwYXNzd29yZA==
412
- Authorization: ApiKey abc123
413
- ```
414
-
415
- **For SPA Development:**
416
- If your SPA uses session-based authentication, include CSRF tokens in your AJAX requests:
417
-
418
- ```javascript
419
- // Include CSRF token in meta tags
420
- <%= csrf_meta_tags %>
421
-
422
- // Send token in AJAX requests
423
- fetch('/api/posts', {
424
- method: 'POST',
425
- headers: {
426
- 'Content-Type': 'application/json',
427
- 'X-CSRF-Token': document.querySelector('[name="csrf-token"]').content
428
- },
429
- body: JSON.stringify(data)
430
- })
431
- ```
432
-
433
- ## Related Modules
434
-
435
- The Controller module works seamlessly with other Plutonium components:
436
-
437
- - **[Core](./core.md)**: Foundation and essential utilities
438
- - **[Resource Record](./resource_record.md)**: CRUD operations and resource management
439
- - **[Portal](./portal.md)**: Multi-tenant portal functionality
440
- - **[Authentication](./authentication.md)**: User authentication and session management
441
- - **[Policy](./policy.md)**: Authorization and access control
442
- - **[Interaction](./interaction.md)**: Business logic encapsulation
443
- - **[Routing](./routing.md)**: Resource registration and route generation