lcp 0.1.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 (1676) hide show
  1. checksums.yaml +7 -0
  2. data/.claude/skills/lcp-custom-field/SKILL.md +205 -0
  3. data/.claude/skills/lcp-getting-started/SKILL.md +332 -0
  4. data/.claude/skills/lcp-host-binding/SKILL.md +287 -0
  5. data/.claude/skills/lcp-model/SKILL.md +185 -0
  6. data/.claude/skills/lcp-permissions/SKILL.md +176 -0
  7. data/.claude/skills/lcp-presenter/SKILL.md +194 -0
  8. data/.claude/skills/lcp-workflow/SKILL.md +281 -0
  9. data/CHANGELOG.md +69 -0
  10. data/MIT-LICENSE +20 -0
  11. data/README.md +28 -0
  12. data/Rakefile +17 -0
  13. data/app/assets/javascripts/lcp_ruby/application.js +58 -0
  14. data/app/assets/javascripts/lcp_ruby/controllers/advanced_filter_controller.js +1521 -0
  15. data/app/assets/javascripts/lcp_ruby/controllers/approval_actions_controller.js +24 -0
  16. data/app/assets/javascripts/lcp_ruby/controllers/array_input_controller.js +156 -0
  17. data/app/assets/javascripts/lcp_ruby/controllers/batch_select_controller.js +405 -0
  18. data/app/assets/javascripts/lcp_ruby/controllers/cascading_selects_controller.js +436 -0
  19. data/app/assets/javascripts/lcp_ruby/controllers/char_counter_controller.js +28 -0
  20. data/app/assets/javascripts/lcp_ruby/controllers/clipboard_controller.js +62 -0
  21. data/app/assets/javascripts/lcp_ruby/controllers/conditional_rendering_controller.js +178 -0
  22. data/app/assets/javascripts/lcp_ruby/controllers/confirm_dialog_controller.js +131 -0
  23. data/app/assets/javascripts/lcp_ruby/controllers/custom_fields_manage_controller.js +80 -0
  24. data/app/assets/javascripts/lcp_ruby/controllers/dialog_controller.js +421 -0
  25. data/app/assets/javascripts/lcp_ruby/controllers/dialog_nested_controller.js +182 -0
  26. data/app/assets/javascripts/lcp_ruby/controllers/direct_upload_controller.js +100 -0
  27. data/app/assets/javascripts/lcp_ruby/controllers/drawer_controller.js +205 -0
  28. data/app/assets/javascripts/lcp_ruby/controllers/dropdown_controller.js +160 -0
  29. data/app/assets/javascripts/lcp_ruby/controllers/export_dialog_controller.js +15 -0
  30. data/app/assets/javascripts/lcp_ruby/controllers/field_picker_controller.js +290 -0
  31. data/app/assets/javascripts/lcp_ruby/controllers/file_upload_controller.js +135 -0
  32. data/app/assets/javascripts/lcp_ruby/controllers/filter_auto_submit_controller.js +46 -0
  33. data/app/assets/javascripts/lcp_ruby/controllers/filter_dirty_controller.js +94 -0
  34. data/app/assets/javascripts/lcp_ruby/controllers/form_actions_controller.js +68 -0
  35. data/app/assets/javascripts/lcp_ruby/controllers/form_handling_controller.js +67 -0
  36. data/app/assets/javascripts/lcp_ruby/controllers/import_dialog_controller.js +142 -0
  37. data/app/assets/javascripts/lcp_ruby/controllers/import_mapper_controller.js +322 -0
  38. data/app/assets/javascripts/lcp_ruby/controllers/index_sortable_controller.js +388 -0
  39. data/app/assets/javascripts/lcp_ruby/controllers/inline_create_controller.js +137 -0
  40. data/app/assets/javascripts/lcp_ruby/controllers/kanban_board_controller.js +290 -0
  41. data/app/assets/javascripts/lcp_ruby/controllers/menu_controller.js +19 -0
  42. data/app/assets/javascripts/lcp_ruby/controllers/nested_forms_controller.js +261 -0
  43. data/app/assets/javascripts/lcp_ruby/controllers/responsive_sidebar_controller.js +161 -0
  44. data/app/assets/javascripts/lcp_ruby/controllers/responsive_top_nav_controller.js +394 -0
  45. data/app/assets/javascripts/lcp_ruby/controllers/saved_filters_controller.js +129 -0
  46. data/app/assets/javascripts/lcp_ruby/controllers/search_controller.js +82 -0
  47. data/app/assets/javascripts/lcp_ruby/controllers/selection_controller.js +33 -0
  48. data/app/assets/javascripts/lcp_ruby/controllers/sidebar_controller.js +83 -0
  49. data/app/assets/javascripts/lcp_ruby/controllers/sidebar_toggle_controller.js +66 -0
  50. data/app/assets/javascripts/lcp_ruby/controllers/slider_controller.js +26 -0
  51. data/app/assets/javascripts/lcp_ruby/controllers/submenu_controller.js +55 -0
  52. data/app/assets/javascripts/lcp_ruby/controllers/tom_select_controller.js +168 -0
  53. data/app/assets/javascripts/lcp_ruby/controllers/tree_index_controller.js +106 -0
  54. data/app/assets/javascripts/lcp_ruby/controllers/tree_reparent_controller.js +182 -0
  55. data/app/assets/javascripts/lcp_ruby/controllers/tree_select_controller.js +119 -0
  56. data/app/assets/javascripts/lcp_ruby/controllers/ui_components_controller.js +135 -0
  57. data/app/assets/javascripts/lcp_ruby/controllers/zone_tabs_controller.js +66 -0
  58. data/app/assets/javascripts/lcp_ruby/dev_toolbar.js +494 -0
  59. data/app/assets/javascripts/lcp_ruby/i18n.js.erb +29 -0
  60. data/app/assets/javascripts/lcp_ruby/lucide_init.js +24 -0
  61. data/app/assets/javascripts/lcp_ruby/stimulus_bootstrap.js +7 -0
  62. data/app/assets/javascripts/lcp_ruby/utils.js +119 -0
  63. data/app/assets/javascripts/lcp_ruby/xhr_fetch.js +411 -0
  64. data/app/assets/stylesheets/lcp_ruby/application.css +1940 -0
  65. data/app/assets/stylesheets/lcp_ruby/dev_toolbar.css +355 -0
  66. data/app/controllers/concerns/lcp_ruby/dialog_rendering.rb +167 -0
  67. data/app/controllers/concerns/lcp_ruby/form_action_execution.rb +249 -0
  68. data/app/controllers/concerns/lcp_ruby/page_authorization.rb +105 -0
  69. data/app/controllers/concerns/lcp_ruby/zone_resolution.rb +199 -0
  70. data/app/controllers/lcp_ruby/actions_controller.rb +481 -0
  71. data/app/controllers/lcp_ruby/application_controller.rb +59 -0
  72. data/app/controllers/lcp_ruby/approval_tasks_controller.rb +98 -0
  73. data/app/controllers/lcp_ruby/auth/base_controller.rb +58 -0
  74. data/app/controllers/lcp_ruby/auth/callbacks_controller.rb +103 -0
  75. data/app/controllers/lcp_ruby/auth/passwords_controller.rb +15 -0
  76. data/app/controllers/lcp_ruby/auth/registrations_controller.rb +37 -0
  77. data/app/controllers/lcp_ruby/auth/sessions_controller.rb +112 -0
  78. data/app/controllers/lcp_ruby/custom_fields_controller.rb +370 -0
  79. data/app/controllers/lcp_ruby/dev_toolbar_controller.rb +197 -0
  80. data/app/controllers/lcp_ruby/dialogs_controller.rb +199 -0
  81. data/app/controllers/lcp_ruby/health_controller.rb +23 -0
  82. data/app/controllers/lcp_ruby/impersonation_controller.rb +32 -0
  83. data/app/controllers/lcp_ruby/landing_controller.rb +49 -0
  84. data/app/controllers/lcp_ruby/metrics_controller.rb +17 -0
  85. data/app/controllers/lcp_ruby/resources_controller.rb +2218 -0
  86. data/app/controllers/lcp_ruby/saved_filters_controller.rb +221 -0
  87. data/app/helpers/lcp_ruby/condition_helper.rb +87 -0
  88. data/app/helpers/lcp_ruby/dashboard_helper.rb +45 -0
  89. data/app/helpers/lcp_ruby/dev_toolbar_helper.rb +17 -0
  90. data/app/helpers/lcp_ruby/dialog_helper.rb +27 -0
  91. data/app/helpers/lcp_ruby/display/card_helper.rb +317 -0
  92. data/app/helpers/lcp_ruby/display_helper.rb +63 -0
  93. data/app/helpers/lcp_ruby/display_template_helper.rb +100 -0
  94. data/app/helpers/lcp_ruby/form_helper.rb +1020 -0
  95. data/app/helpers/lcp_ruby/grouped_query_helper.rb +107 -0
  96. data/app/helpers/lcp_ruby/i18n_payload_helper.rb +197 -0
  97. data/app/helpers/lcp_ruby/layout_helper.rb +832 -0
  98. data/app/helpers/lcp_ruby/link_through_helper.rb +29 -0
  99. data/app/helpers/lcp_ruby/oidc_button_helper.rb +59 -0
  100. data/app/helpers/lcp_ruby/search_helper.rb +31 -0
  101. data/app/helpers/lcp_ruby/tree_helper.rb +140 -0
  102. data/app/helpers/lcp_ruby/view_slot_helper.rb +33 -0
  103. data/app/models/lcp_ruby/user.rb +61 -0
  104. data/app/views/layouts/lcp_ruby/application.html.erb +168 -0
  105. data/app/views/layouts/lcp_ruby/auth.html.erb +170 -0
  106. data/app/views/lcp_ruby/auth/callbacks/failure.html.erb +18 -0
  107. data/app/views/lcp_ruby/auth/mailer/reset_password_instructions.html.erb +9 -0
  108. data/app/views/lcp_ruby/auth/passwords/edit.html.erb +34 -0
  109. data/app/views/lcp_ruby/auth/passwords/new.html.erb +24 -0
  110. data/app/views/lcp_ruby/auth/registrations/edit.html.erb +48 -0
  111. data/app/views/lcp_ruby/auth/registrations/new.html.erb +46 -0
  112. data/app/views/lcp_ruby/auth/sessions/new.html.erb +55 -0
  113. data/app/views/lcp_ruby/auth/shared/_links.html.erb +13 -0
  114. data/app/views/lcp_ruby/custom_fields/_manage_row.html.erb +82 -0
  115. data/app/views/lcp_ruby/custom_fields/manage.html.erb +47 -0
  116. data/app/views/lcp_ruby/dialogs/_dialog_composite_frame.html.erb +87 -0
  117. data/app/views/lcp_ruby/dialogs/_dialog_frame.html.erb +60 -0
  118. data/app/views/lcp_ruby/dialogs/_dialog_show_frame.html.erb +14 -0
  119. data/app/views/lcp_ruby/dialogs/_show_secret.html.erb +10 -0
  120. data/app/views/lcp_ruby/dialogs/_success.html.erb +1 -0
  121. data/app/views/lcp_ruby/errors/not_found.html.erb +5 -0
  122. data/app/views/lcp_ruby/menu_renderers/_user_menu.html.erb +51 -0
  123. data/app/views/lcp_ruby/menu_renderers/_user_menu_panel.html.erb +32 -0
  124. data/app/views/lcp_ruby/navigation/_auto_top.html.erb +16 -0
  125. data/app/views/lcp_ruby/navigation/_both_sidebar.html.erb +1 -0
  126. data/app/views/lcp_ruby/navigation/_both_top.html.erb +1 -0
  127. data/app/views/lcp_ruby/navigation/_impersonation_banner.html.erb +14 -0
  128. data/app/views/lcp_ruby/navigation/_item_content.html.erb +23 -0
  129. data/app/views/lcp_ruby/navigation/_link_or_button.html.erb +51 -0
  130. data/app/views/lcp_ruby/navigation/_mobile_header.html.erb +23 -0
  131. data/app/views/lcp_ruby/navigation/_panel_item.html.erb +32 -0
  132. data/app/views/lcp_ruby/navigation/_sidebar.html.erb +38 -0
  133. data/app/views/lcp_ruby/navigation/_sidebar_item.html.erb +38 -0
  134. data/app/views/lcp_ruby/navigation/_sidebar_toggle.html.erb +32 -0
  135. data/app/views/lcp_ruby/navigation/_top.html.erb +26 -0
  136. data/app/views/lcp_ruby/navigation/_top_item.html.erb +112 -0
  137. data/app/views/lcp_ruby/navigation/_widget_item.html.erb +14 -0
  138. data/app/views/lcp_ruby/resources/_action_button.html.erb +138 -0
  139. data/app/views/lcp_ruby/resources/_advanced_filter.html.erb +55 -0
  140. data/app/views/lcp_ruby/resources/_api_status_banner.html.erb +11 -0
  141. data/app/views/lcp_ruby/resources/_association_list.html.erb +132 -0
  142. data/app/views/lcp_ruby/resources/_audit_history.html.erb +66 -0
  143. data/app/views/lcp_ruby/resources/_batch_toolbar.html.erb +54 -0
  144. data/app/views/lcp_ruby/resources/_filter_form.html.erb +57 -0
  145. data/app/views/lcp_ruby/resources/_form.html.erb +73 -0
  146. data/app/views/lcp_ruby/resources/_form_action_button.html.erb +20 -0
  147. data/app/views/lcp_ruby/resources/_form_action_dropdown_item.html.erb +17 -0
  148. data/app/views/lcp_ruby/resources/_form_actions.html.erb +38 -0
  149. data/app/views/lcp_ruby/resources/_form_section.html.erb +235 -0
  150. data/app/views/lcp_ruby/resources/_grid_page.html.erb +17 -0
  151. data/app/views/lcp_ruby/resources/_grouped_index.html.erb +61 -0
  152. data/app/views/lcp_ruby/resources/_inline_create_form.html.erb +50 -0
  153. data/app/views/lcp_ruby/resources/_json_items_list.html.erb +77 -0
  154. data/app/views/lcp_ruby/resources/_json_nested_fields.html.erb +30 -0
  155. data/app/views/lcp_ruby/resources/_kanban_card.html.erb +31 -0
  156. data/app/views/lcp_ruby/resources/_kanban_card_body.html.erb +17 -0
  157. data/app/views/lcp_ruby/resources/_kanban_column.html.erb +33 -0
  158. data/app/views/lcp_ruby/resources/_kanban_column_header.html.erb +10 -0
  159. data/app/views/lcp_ruby/resources/_kanban_index.html.erb +17 -0
  160. data/app/views/lcp_ruby/resources/_nested_field_cell.html.erb +33 -0
  161. data/app/views/lcp_ruby/resources/_nested_fields.html.erb +26 -0
  162. data/app/views/lcp_ruby/resources/_nested_row_content.html.erb +65 -0
  163. data/app/views/lcp_ruby/resources/_scope_filters.html.erb +71 -0
  164. data/app/views/lcp_ruby/resources/_semantic_index_page.html.erb +162 -0
  165. data/app/views/lcp_ruby/resources/_semantic_page.html.erb +121 -0
  166. data/app/views/lcp_ruby/resources/_show_sections.html.erb +128 -0
  167. data/app/views/lcp_ruby/resources/_table_index.html.erb +169 -0
  168. data/app/views/lcp_ruby/resources/_tile_card.html.erb +26 -0
  169. data/app/views/lcp_ruby/resources/_tile_card_body.html.erb +19 -0
  170. data/app/views/lcp_ruby/resources/_tiles_index.html.erb +15 -0
  171. data/app/views/lcp_ruby/resources/_transition_button.html.erb +33 -0
  172. data/app/views/lcp_ruby/resources/_tree_index.html.erb +61 -0
  173. data/app/views/lcp_ruby/resources/_view_switcher.html.erb +24 -0
  174. data/app/views/lcp_ruby/resources/edit.html.erb +9 -0
  175. data/app/views/lcp_ruby/resources/index.html.erb +80 -0
  176. data/app/views/lcp_ruby/resources/new.html.erb +9 -0
  177. data/app/views/lcp_ruby/resources/show.html.erb +37 -0
  178. data/app/views/lcp_ruby/shared/_breadcrumbs.html.erb +15 -0
  179. data/app/views/lcp_ruby/shared/_custom_partial_error.html.erb +3 -0
  180. data/app/views/lcp_ruby/shared/_flash_messages.html.erb +19 -0
  181. data/app/views/lcp_ruby/slots/index/_advanced_filter.html.erb +3 -0
  182. data/app/views/lcp_ruby/slots/index/_collection_actions.html.erb +50 -0
  183. data/app/views/lcp_ruby/slots/index/_manage_all.html.erb +4 -0
  184. data/app/views/lcp_ruby/slots/index/_pagination_footer.html.erb +71 -0
  185. data/app/views/lcp_ruby/slots/index/_predefined_filters.html.erb +8 -0
  186. data/app/views/lcp_ruby/slots/index/_saved_filters.html.erb +87 -0
  187. data/app/views/lcp_ruby/slots/index/_search.html.erb +52 -0
  188. data/app/views/lcp_ruby/slots/index/_search_parameter.html.erb +72 -0
  189. data/app/views/lcp_ruby/slots/index/_sort_dropdown.html.erb +21 -0
  190. data/app/views/lcp_ruby/slots/index/_summary_bar.html.erb +22 -0
  191. data/app/views/lcp_ruby/slots/index/_view_switcher.html.erb +1 -0
  192. data/app/views/lcp_ruby/slots/show/_approval_status.html.erb +8 -0
  193. data/app/views/lcp_ruby/slots/show/_back_to_list.html.erb +1 -0
  194. data/app/views/lcp_ruby/slots/show/_copy_url.html.erb +5 -0
  195. data/app/views/lcp_ruby/slots/show/_single_actions.html.erb +4 -0
  196. data/app/views/lcp_ruby/slots/show/_view_switcher.html.erb +1 -0
  197. data/app/views/lcp_ruby/widgets/_approval_status.html.erb +150 -0
  198. data/app/views/lcp_ruby/widgets/_chart.html.erb +36 -0
  199. data/app/views/lcp_ruby/widgets/_embed.html.erb +13 -0
  200. data/app/views/lcp_ruby/widgets/_kpi_card.html.erb +29 -0
  201. data/app/views/lcp_ruby/widgets/_list.html.erb +17 -0
  202. data/app/views/lcp_ruby/widgets/_presenter_zone.html.erb +84 -0
  203. data/app/views/lcp_ruby/widgets/_record_show_zone.html.erb +11 -0
  204. data/app/views/lcp_ruby/widgets/_text.html.erb +3 -0
  205. data/app/views/lcp_ruby/widgets/_workflow_graph.html.erb +32 -0
  206. data/app/views/lcp_ruby/zones/_custom_zone.html.erb +16 -0
  207. data/app/views/lcp_ruby/zones/_error.html.erb +5 -0
  208. data/app/views/lcp_ruby/zones/_zone_frame.html.erb +25 -0
  209. data/app/views/lcp_ruby/zones/_zone_search.html.erb +20 -0
  210. data/config/locales/cs.yml +859 -0
  211. data/config/locales/en.yml +731 -0
  212. data/config/routes.rb +119 -0
  213. data/docs/README.md +225 -0
  214. data/docs/architecture.md +212 -0
  215. data/docs/feature-catalog.md +763 -0
  216. data/docs/feature-catalog.yml +20911 -0
  217. data/docs/getting-started.md +1187 -0
  218. data/docs/guides/action-buttons.md +537 -0
  219. data/docs/guides/adding-locale.md +353 -0
  220. data/docs/guides/api-backed-models.md +478 -0
  221. data/docs/guides/attachments.md +399 -0
  222. data/docs/guides/auditing.md +333 -0
  223. data/docs/guides/batch-actions.md +342 -0
  224. data/docs/guides/composite-pages.md +1290 -0
  225. data/docs/guides/computed-fields.md +350 -0
  226. data/docs/guides/conditional-rendering.md +832 -0
  227. data/docs/guides/custom-actions.md +238 -0
  228. data/docs/guides/custom-fields.md +439 -0
  229. data/docs/guides/custom-renderers.md +234 -0
  230. data/docs/guides/custom-types.md +274 -0
  231. data/docs/guides/dashboards.md +504 -0
  232. data/docs/guides/debugging/README.md +38 -0
  233. data/docs/guides/debugging/controllers.md +147 -0
  234. data/docs/guides/debugging/data.md +165 -0
  235. data/docs/guides/debugging/metadata.md +143 -0
  236. data/docs/guides/debugging/models.md +126 -0
  237. data/docs/guides/debugging/permissions.md +147 -0
  238. data/docs/guides/debugging/presenters.md +151 -0
  239. data/docs/guides/developer-tools.md +418 -0
  240. data/docs/guides/dialogs.md +392 -0
  241. data/docs/guides/display-types.md +1430 -0
  242. data/docs/guides/eager-loading.md +230 -0
  243. data/docs/guides/event-handlers.md +135 -0
  244. data/docs/guides/export.md +305 -0
  245. data/docs/guides/extensibility.md +761 -0
  246. data/docs/guides/groups.md +220 -0
  247. data/docs/guides/hierarchical-authorization.md +427 -0
  248. data/docs/guides/host-application.md +556 -0
  249. data/docs/guides/host-controller-integration.md +473 -0
  250. data/docs/guides/impersonation.md +83 -0
  251. data/docs/guides/import.md +165 -0
  252. data/docs/guides/inherited-permissions.md +459 -0
  253. data/docs/guides/menu.md +373 -0
  254. data/docs/guides/monitoring.md +254 -0
  255. data/docs/guides/oidc-setup.md +399 -0
  256. data/docs/guides/permission-source.md +205 -0
  257. data/docs/guides/permissions.md +364 -0
  258. data/docs/guides/presenters.md +2324 -0
  259. data/docs/guides/record-aliases.md +303 -0
  260. data/docs/guides/rendering-extension-points.md +280 -0
  261. data/docs/guides/role-source.md +288 -0
  262. data/docs/guides/selectbox.md +516 -0
  263. data/docs/guides/sequences.md +291 -0
  264. data/docs/guides/soft-delete.md +460 -0
  265. data/docs/guides/theming.md +129 -0
  266. data/docs/guides/tiles.md +383 -0
  267. data/docs/guides/tree-structures.md +297 -0
  268. data/docs/guides/userstamps.md +288 -0
  269. data/docs/guides/view-groups.md +259 -0
  270. data/docs/guides/view-slots.md +352 -0
  271. data/docs/guides/virtual-columns.md +810 -0
  272. data/docs/guides/workflow.md +692 -0
  273. data/docs/reference/api-backed-models.md +404 -0
  274. data/docs/reference/api-tokens.md +128 -0
  275. data/docs/reference/auditing.md +277 -0
  276. data/docs/reference/boot_lifecycle.md +188 -0
  277. data/docs/reference/cascading_selects.md +189 -0
  278. data/docs/reference/condition-operators.md +445 -0
  279. data/docs/reference/custom-fields.md +483 -0
  280. data/docs/reference/dialogs.md +286 -0
  281. data/docs/reference/doctor.md +168 -0
  282. data/docs/reference/dynamic-references.md +95 -0
  283. data/docs/reference/eager-loading.md +192 -0
  284. data/docs/reference/engine-configuration.md +989 -0
  285. data/docs/reference/export.md +309 -0
  286. data/docs/reference/forms.md +68 -0
  287. data/docs/reference/groups.md +176 -0
  288. data/docs/reference/host-controller-integration.md +342 -0
  289. data/docs/reference/i18n.md +497 -0
  290. data/docs/reference/i18n_check.md +351 -0
  291. data/docs/reference/import.md +260 -0
  292. data/docs/reference/invariant_check.md +216 -0
  293. data/docs/reference/menu.md +985 -0
  294. data/docs/reference/model-dsl.md +1157 -0
  295. data/docs/reference/models.md +2972 -0
  296. data/docs/reference/monitoring.md +222 -0
  297. data/docs/reference/oidc-bearer.md +269 -0
  298. data/docs/reference/oidc.md +407 -0
  299. data/docs/reference/page_filters.md +328 -0
  300. data/docs/reference/pages.md +1375 -0
  301. data/docs/reference/permission-source.md +185 -0
  302. data/docs/reference/permissions.md +715 -0
  303. data/docs/reference/presenter-dsl.md +1719 -0
  304. data/docs/reference/presenters.md +3627 -0
  305. data/docs/reference/role-source.md +227 -0
  306. data/docs/reference/theme-variables.md +139 -0
  307. data/docs/reference/tree-structures.md +374 -0
  308. data/docs/reference/types.md +470 -0
  309. data/docs/reference/view-groups.md +347 -0
  310. data/docs/reference/view-slots.md +228 -0
  311. data/docs/reference/virtual_forms.md +196 -0
  312. data/docs/reference/workflow-approvals.md +387 -0
  313. data/docs/reference/workflow.md +651 -0
  314. data/examples/crm/Gemfile +9 -0
  315. data/examples/crm/Gemfile.lock +417 -0
  316. data/examples/crm/Rakefile +2 -0
  317. data/examples/crm/app/actions/activity/complete.rb +20 -0
  318. data/examples/crm/app/actions/deal/close_won.rb +20 -0
  319. data/examples/crm/app/assets/config/manifest.js +3 -0
  320. data/examples/crm/app/controllers/application_controller.rb +9 -0
  321. data/examples/crm/app/event_handlers/deal/on_stage_change.rb +17 -0
  322. data/examples/crm/app/lcp_services/computed/weighted_deal_value.rb +13 -0
  323. data/examples/crm/app/lcp_services/data_providers/active_contacts_count.rb +14 -0
  324. data/examples/crm/app/lcp_services/data_providers/open_deals_count.rb +14 -0
  325. data/examples/crm/app/lcp_services/data_providers/pending_activities_count.rb +15 -0
  326. data/examples/crm/app/lcp_services/data_providers/pipeline_value.rb +27 -0
  327. data/examples/crm/app/lcp_services/data_providers/won_deals_count.rb +14 -0
  328. data/examples/crm/app/lcp_services/defaults/thirty_days_out.rb +11 -0
  329. data/examples/crm/app/lcp_services/transforms/titlecase.rb +11 -0
  330. data/examples/crm/app/lcp_services/validators/deal_credit_limit.rb +19 -0
  331. data/examples/crm/app/lcp_services/validators/deal_documents_required.rb +17 -0
  332. data/examples/crm/app/renderers/conditional_badge.rb +39 -0
  333. data/examples/crm/bin/rails +4 -0
  334. data/examples/crm/bin/rake +4 -0
  335. data/examples/crm/config/application.rb +31 -0
  336. data/examples/crm/config/boot.rb +2 -0
  337. data/examples/crm/config/database.yml +12 -0
  338. data/examples/crm/config/environment.rb +2 -0
  339. data/examples/crm/config/initializers/lcp_ruby.rb +45 -0
  340. data/examples/crm/config/lcp_ruby/menu.yml +53 -0
  341. data/examples/crm/config/lcp_ruby/models/activity.rb +43 -0
  342. data/examples/crm/config/lcp_ruby/models/city.rb +19 -0
  343. data/examples/crm/config/lcp_ruby/models/company.rb +65 -0
  344. data/examples/crm/config/lcp_ruby/models/contact.rb +62 -0
  345. data/examples/crm/config/lcp_ruby/models/country.rb +22 -0
  346. data/examples/crm/config/lcp_ruby/models/custom_field_definition.rb +60 -0
  347. data/examples/crm/config/lcp_ruby/models/deal.rb +85 -0
  348. data/examples/crm/config/lcp_ruby/models/deal_category.rb +15 -0
  349. data/examples/crm/config/lcp_ruby/models/gapfree_sequence.rb +17 -0
  350. data/examples/crm/config/lcp_ruby/models/region.rb +15 -0
  351. data/examples/crm/config/lcp_ruby/models/saved_filter.rb +50 -0
  352. data/examples/crm/config/lcp_ruby/pages/activity_quick_log.yml +19 -0
  353. data/examples/crm/config/lcp_ruby/pages/company_detail.yml +127 -0
  354. data/examples/crm/config/lcp_ruby/pages/deals_overview.yml +65 -0
  355. data/examples/crm/config/lcp_ruby/permissions/activity.yml +40 -0
  356. data/examples/crm/config/lcp_ruby/permissions/custom_field_definition.yml +16 -0
  357. data/examples/crm/config/lcp_ruby/permissions/deal.yml +54 -0
  358. data/examples/crm/config/lcp_ruby/permissions/default.yml +16 -0
  359. data/examples/crm/config/lcp_ruby/permissions/gapfree_sequence.yml +6 -0
  360. data/examples/crm/config/lcp_ruby/permissions/saved_filter.yml +27 -0
  361. data/examples/crm/config/lcp_ruby/presenters/activity.rb +140 -0
  362. data/examples/crm/config/lcp_ruby/presenters/activity_quick_form.rb +36 -0
  363. data/examples/crm/config/lcp_ruby/presenters/activity_short.rb +16 -0
  364. data/examples/crm/config/lcp_ruby/presenters/activity_tiles.rb +35 -0
  365. data/examples/crm/config/lcp_ruby/presenters/city.rb +53 -0
  366. data/examples/crm/config/lcp_ruby/presenters/company.rb +147 -0
  367. data/examples/crm/config/lcp_ruby/presenters/company_activities_zone.rb +26 -0
  368. data/examples/crm/config/lcp_ruby/presenters/company_archive.rb +37 -0
  369. data/examples/crm/config/lcp_ruby/presenters/company_contacts_zone.rb +22 -0
  370. data/examples/crm/config/lcp_ruby/presenters/company_deals_zone.rb +36 -0
  371. data/examples/crm/config/lcp_ruby/presenters/company_short.rb +21 -0
  372. data/examples/crm/config/lcp_ruby/presenters/company_show_zone.rb +38 -0
  373. data/examples/crm/config/lcp_ruby/presenters/company_sidebar.rb +15 -0
  374. data/examples/crm/config/lcp_ruby/presenters/company_tiles.rb +35 -0
  375. data/examples/crm/config/lcp_ruby/presenters/contact.rb +120 -0
  376. data/examples/crm/config/lcp_ruby/presenters/contact_quick_form.rb +17 -0
  377. data/examples/crm/config/lcp_ruby/presenters/contact_short.rb +20 -0
  378. data/examples/crm/config/lcp_ruby/presenters/contact_tiles.rb +34 -0
  379. data/examples/crm/config/lcp_ruby/presenters/country.rb +44 -0
  380. data/examples/crm/config/lcp_ruby/presenters/custom_fields.rb +124 -0
  381. data/examples/crm/config/lcp_ruby/presenters/deal.rb +181 -0
  382. data/examples/crm/config/lcp_ruby/presenters/deal_category.rb +46 -0
  383. data/examples/crm/config/lcp_ruby/presenters/deal_overview.rb +6 -0
  384. data/examples/crm/config/lcp_ruby/presenters/deal_pipeline.rb +18 -0
  385. data/examples/crm/config/lcp_ruby/presenters/deal_short.rb +25 -0
  386. data/examples/crm/config/lcp_ruby/presenters/deal_tiles.rb +48 -0
  387. data/examples/crm/config/lcp_ruby/presenters/region.rb +42 -0
  388. data/examples/crm/config/lcp_ruby/presenters/save_filter_dialog.rb +17 -0
  389. data/examples/crm/config/lcp_ruby/presenters/saved_filters.rb +93 -0
  390. data/examples/crm/config/lcp_ruby/views/activities.yml +16 -0
  391. data/examples/crm/config/lcp_ruby/views/cities.yml +10 -0
  392. data/examples/crm/config/lcp_ruby/views/companies.yml +14 -0
  393. data/examples/crm/config/lcp_ruby/views/contacts.yml +16 -0
  394. data/examples/crm/config/lcp_ruby/views/countries.yml +8 -0
  395. data/examples/crm/config/lcp_ruby/views/custom_fields.rb +9 -0
  396. data/examples/crm/config/lcp_ruby/views/deal_categories.yml +8 -0
  397. data/examples/crm/config/lcp_ruby/views/deals.yml +19 -0
  398. data/examples/crm/config/lcp_ruby/views/pipeline.yml +10 -0
  399. data/examples/crm/config/lcp_ruby/views/regions.yml +10 -0
  400. data/examples/crm/config/lcp_ruby/views/saved_filters.yml +7 -0
  401. data/examples/crm/config/locales/cs.yml +338 -0
  402. data/examples/crm/config/locales/en.yml +353 -0
  403. data/examples/crm/config/routes.rb +4 -0
  404. data/examples/crm/config/storage.yml +3 -0
  405. data/examples/crm/config.ru +2 -0
  406. data/examples/crm/db/migrate/20260219104942_create_active_storage_tables.active_storage.rb +57 -0
  407. data/examples/crm/db/schema.rb +245 -0
  408. data/examples/crm/db/seeds.rb +1111 -0
  409. data/examples/crm/erd.md +163 -0
  410. data/examples/hr/Gemfile +9 -0
  411. data/examples/hr/Gemfile.lock +419 -0
  412. data/examples/hr/Rakefile +6 -0
  413. data/examples/hr/app/actions/asset/assign_asset.rb +20 -0
  414. data/examples/hr/app/actions/asset/return_asset.rb +20 -0
  415. data/examples/hr/app/actions/candidate/advance.rb +32 -0
  416. data/examples/hr/app/actions/candidate/hire.rb +20 -0
  417. data/examples/hr/app/actions/candidate/reject_candidate.rb +20 -0
  418. data/examples/hr/app/actions/expense_claim/approve.rb +21 -0
  419. data/examples/hr/app/actions/expense_claim/reject.rb +21 -0
  420. data/examples/hr/app/actions/expense_claim/submit.rb +20 -0
  421. data/examples/hr/app/actions/interview/complete_interview.rb +20 -0
  422. data/examples/hr/app/actions/leave_request/approve.rb +21 -0
  423. data/examples/hr/app/actions/leave_request/cancel.rb +20 -0
  424. data/examples/hr/app/actions/leave_request/reject.rb +21 -0
  425. data/examples/hr/app/assets/config/manifest.js +1 -0
  426. data/examples/hr/app/assets/stylesheets/application.css +10 -0
  427. data/examples/hr/app/condition_services/is_own_org_unit.rb +14 -0
  428. data/examples/hr/app/condition_services/is_own_record.rb +20 -0
  429. data/examples/hr/app/controllers/application_controller.rb +15 -0
  430. data/examples/hr/app/event_handlers/asset_assignment/on_create.rb +24 -0
  431. data/examples/hr/app/event_handlers/candidate/on_status_change.rb +18 -0
  432. data/examples/hr/app/event_handlers/leave_request/on_status_change.rb +45 -0
  433. data/examples/hr/app/helpers/application_helper.rb +2 -0
  434. data/examples/hr/app/javascript/application.js +1 -0
  435. data/examples/hr/app/jobs/application_job.rb +7 -0
  436. data/examples/hr/app/lcp_services/computed/employee_tenure.rb +28 -0
  437. data/examples/hr/app/lcp_services/computed/leave_remaining.rb +13 -0
  438. data/examples/hr/app/lcp_services/data_providers/headcount_text.rb +14 -0
  439. data/examples/hr/app/lcp_services/data_providers/open_positions_count.rb +14 -0
  440. data/examples/hr/app/lcp_services/data_providers/pending_expenses_count.rb +14 -0
  441. data/examples/hr/app/lcp_services/data_providers/pending_leaves_count.rb +14 -0
  442. data/examples/hr/app/lcp_services/defaults/current_year.rb +11 -0
  443. data/examples/hr/app/lcp_services/transforms/titlecase.rb +11 -0
  444. data/examples/hr/app/lcp_services/validators/expense_receipt_required.rb +17 -0
  445. data/examples/hr/app/lcp_services/validators/leave_balance_check.rb +37 -0
  446. data/examples/hr/app/models/application_record.rb +3 -0
  447. data/examples/hr/app/views/layouts/application.html.erb +29 -0
  448. data/examples/hr/app/views/pwa/manifest.json.erb +22 -0
  449. data/examples/hr/app/views/pwa/service-worker.js +26 -0
  450. data/examples/hr/bin/brakeman +7 -0
  451. data/examples/hr/bin/bundler-audit +6 -0
  452. data/examples/hr/bin/ci +6 -0
  453. data/examples/hr/bin/dev +2 -0
  454. data/examples/hr/bin/docker-entrypoint +8 -0
  455. data/examples/hr/bin/importmap +4 -0
  456. data/examples/hr/bin/jobs +6 -0
  457. data/examples/hr/bin/kamal +27 -0
  458. data/examples/hr/bin/rails +4 -0
  459. data/examples/hr/bin/rake +4 -0
  460. data/examples/hr/bin/rubocop +8 -0
  461. data/examples/hr/bin/setup +35 -0
  462. data/examples/hr/bin/thrust +5 -0
  463. data/examples/hr/config/application.rb +31 -0
  464. data/examples/hr/config/boot.rb +2 -0
  465. data/examples/hr/config/bundler-audit.yml +5 -0
  466. data/examples/hr/config/cache.yml +16 -0
  467. data/examples/hr/config/ci.rb +20 -0
  468. data/examples/hr/config/credentials.yml.enc +1 -0
  469. data/examples/hr/config/database.yml +36 -0
  470. data/examples/hr/config/deploy.yml +119 -0
  471. data/examples/hr/config/environment.rb +5 -0
  472. data/examples/hr/config/environments/development.rb +66 -0
  473. data/examples/hr/config/environments/production.rb +74 -0
  474. data/examples/hr/config/environments/test.rb +45 -0
  475. data/examples/hr/config/importmap.rb +3 -0
  476. data/examples/hr/config/initializers/assets.rb +7 -0
  477. data/examples/hr/config/initializers/content_security_policy.rb +29 -0
  478. data/examples/hr/config/initializers/filter_parameter_logging.rb +8 -0
  479. data/examples/hr/config/initializers/inflections.rb +16 -0
  480. data/examples/hr/config/initializers/lcp_ruby.rb +18 -0
  481. data/examples/hr/config/lcp_ruby/menu.yml +86 -0
  482. data/examples/hr/config/lcp_ruby/models/announcement.rb +33 -0
  483. data/examples/hr/config/lcp_ruby/models/asset.rb +73 -0
  484. data/examples/hr/config/lcp_ruby/models/asset_assignment.rb +39 -0
  485. data/examples/hr/config/lcp_ruby/models/audit_log.yml +57 -0
  486. data/examples/hr/config/lcp_ruby/models/candidate.rb +68 -0
  487. data/examples/hr/config/lcp_ruby/models/custom_field_definition.rb +60 -0
  488. data/examples/hr/config/lcp_ruby/models/dashboard.rb +17 -0
  489. data/examples/hr/config/lcp_ruby/models/document.rb +38 -0
  490. data/examples/hr/config/lcp_ruby/models/employee.rb +128 -0
  491. data/examples/hr/config/lcp_ruby/models/employee_skill.rb +29 -0
  492. data/examples/hr/config/lcp_ruby/models/expense_claim.rb +70 -0
  493. data/examples/hr/config/lcp_ruby/models/goal.rb +48 -0
  494. data/examples/hr/config/lcp_ruby/models/group.rb +37 -0
  495. data/examples/hr/config/lcp_ruby/models/group_membership.rb +26 -0
  496. data/examples/hr/config/lcp_ruby/models/interview.rb +54 -0
  497. data/examples/hr/config/lcp_ruby/models/job_posting.rb +67 -0
  498. data/examples/hr/config/lcp_ruby/models/leave_balance.rb +31 -0
  499. data/examples/hr/config/lcp_ruby/models/leave_request.rb +52 -0
  500. data/examples/hr/config/lcp_ruby/models/leave_type.rb +35 -0
  501. data/examples/hr/config/lcp_ruby/models/organization_unit.rb +42 -0
  502. data/examples/hr/config/lcp_ruby/models/performance_review.rb +59 -0
  503. data/examples/hr/config/lcp_ruby/models/position.rb +43 -0
  504. data/examples/hr/config/lcp_ruby/models/skill.rb +27 -0
  505. data/examples/hr/config/lcp_ruby/models/training_course.rb +53 -0
  506. data/examples/hr/config/lcp_ruby/models/training_enrollment.rb +35 -0
  507. data/examples/hr/config/lcp_ruby/pages/dashboard.yml +101 -0
  508. data/examples/hr/config/lcp_ruby/permissions/announcement.yml +25 -0
  509. data/examples/hr/config/lcp_ruby/permissions/asset.yml +35 -0
  510. data/examples/hr/config/lcp_ruby/permissions/audit_log.yml +28 -0
  511. data/examples/hr/config/lcp_ruby/permissions/candidate.yml +25 -0
  512. data/examples/hr/config/lcp_ruby/permissions/custom_field_definition.yml +28 -0
  513. data/examples/hr/config/lcp_ruby/permissions/dashboard.yml +25 -0
  514. data/examples/hr/config/lcp_ruby/permissions/default.yml +25 -0
  515. data/examples/hr/config/lcp_ruby/permissions/document.yml +37 -0
  516. data/examples/hr/config/lcp_ruby/permissions/employee.yml +55 -0
  517. data/examples/hr/config/lcp_ruby/permissions/expense_claim.yml +45 -0
  518. data/examples/hr/config/lcp_ruby/permissions/group.yml +27 -0
  519. data/examples/hr/config/lcp_ruby/permissions/job_posting.yml +34 -0
  520. data/examples/hr/config/lcp_ruby/permissions/leave_request.yml +45 -0
  521. data/examples/hr/config/lcp_ruby/permissions/performance_review.yml +42 -0
  522. data/examples/hr/config/lcp_ruby/presenters/announcement.rb +47 -0
  523. data/examples/hr/config/lcp_ruby/presenters/asset.rb +69 -0
  524. data/examples/hr/config/lcp_ruby/presenters/asset_assignment.rb +47 -0
  525. data/examples/hr/config/lcp_ruby/presenters/audit_logs.yml +43 -0
  526. data/examples/hr/config/lcp_ruby/presenters/candidate.rb +71 -0
  527. data/examples/hr/config/lcp_ruby/presenters/custom_fields.rb +124 -0
  528. data/examples/hr/config/lcp_ruby/presenters/dashboard.rb +37 -0
  529. data/examples/hr/config/lcp_ruby/presenters/document.rb +46 -0
  530. data/examples/hr/config/lcp_ruby/presenters/employee.rb +167 -0
  531. data/examples/hr/config/lcp_ruby/presenters/employee_archive.rb +38 -0
  532. data/examples/hr/config/lcp_ruby/presenters/employee_directory.rb +27 -0
  533. data/examples/hr/config/lcp_ruby/presenters/employee_skill.rb +57 -0
  534. data/examples/hr/config/lcp_ruby/presenters/expense_claim.rb +76 -0
  535. data/examples/hr/config/lcp_ruby/presenters/goal.rb +60 -0
  536. data/examples/hr/config/lcp_ruby/presenters/group.rb +48 -0
  537. data/examples/hr/config/lcp_ruby/presenters/interview.rb +59 -0
  538. data/examples/hr/config/lcp_ruby/presenters/job_posting.rb +73 -0
  539. data/examples/hr/config/lcp_ruby/presenters/leave_balance.rb +50 -0
  540. data/examples/hr/config/lcp_ruby/presenters/leave_request.rb +89 -0
  541. data/examples/hr/config/lcp_ruby/presenters/leave_type.rb +52 -0
  542. data/examples/hr/config/lcp_ruby/presenters/organization_unit.rb +56 -0
  543. data/examples/hr/config/lcp_ruby/presenters/performance_review.rb +87 -0
  544. data/examples/hr/config/lcp_ruby/presenters/position.rb +54 -0
  545. data/examples/hr/config/lcp_ruby/presenters/skill.rb +45 -0
  546. data/examples/hr/config/lcp_ruby/presenters/training_course.rb +61 -0
  547. data/examples/hr/config/lcp_ruby/presenters/training_enrollment.rb +49 -0
  548. data/examples/hr/config/lcp_ruby/views/announcements.yml +8 -0
  549. data/examples/hr/config/lcp_ruby/views/asset_assignments.yml +10 -0
  550. data/examples/hr/config/lcp_ruby/views/assets.yml +8 -0
  551. data/examples/hr/config/lcp_ruby/views/audit_logs.yml +8 -0
  552. data/examples/hr/config/lcp_ruby/views/candidates.yml +8 -0
  553. data/examples/hr/config/lcp_ruby/views/custom_fields.yml +8 -0
  554. data/examples/hr/config/lcp_ruby/views/dashboard.yml +6 -0
  555. data/examples/hr/config/lcp_ruby/views/documents.yml +10 -0
  556. data/examples/hr/config/lcp_ruby/views/employee_skills.yml +10 -0
  557. data/examples/hr/config/lcp_ruby/views/employees.yml +14 -0
  558. data/examples/hr/config/lcp_ruby/views/expense_claims.yml +10 -0
  559. data/examples/hr/config/lcp_ruby/views/goals.yml +10 -0
  560. data/examples/hr/config/lcp_ruby/views/groups.yml +8 -0
  561. data/examples/hr/config/lcp_ruby/views/interviews.yml +8 -0
  562. data/examples/hr/config/lcp_ruby/views/job_postings.yml +6 -0
  563. data/examples/hr/config/lcp_ruby/views/leave_balances.yml +10 -0
  564. data/examples/hr/config/lcp_ruby/views/leave_requests.yml +10 -0
  565. data/examples/hr/config/lcp_ruby/views/leave_types.yml +8 -0
  566. data/examples/hr/config/lcp_ruby/views/organization_units.yml +8 -0
  567. data/examples/hr/config/lcp_ruby/views/performance_reviews.yml +10 -0
  568. data/examples/hr/config/lcp_ruby/views/positions.yml +8 -0
  569. data/examples/hr/config/lcp_ruby/views/skills.yml +8 -0
  570. data/examples/hr/config/lcp_ruby/views/training_courses.yml +8 -0
  571. data/examples/hr/config/lcp_ruby/views/training_enrollments.yml +10 -0
  572. data/examples/hr/config/locales/cs.yml +496 -0
  573. data/examples/hr/config/locales/en.yml +740 -0
  574. data/examples/hr/config/locales/sk.yml +496 -0
  575. data/examples/hr/config/puma.rb +42 -0
  576. data/examples/hr/config/queue.yml +18 -0
  577. data/examples/hr/config/recurring.yml +15 -0
  578. data/examples/hr/config/routes.rb +4 -0
  579. data/examples/hr/config/storage.yml +27 -0
  580. data/examples/hr/config.ru +6 -0
  581. data/examples/hr/db/cache_schema.rb +12 -0
  582. data/examples/hr/db/migrate/20260303202825_create_active_storage_tables.active_storage.rb +57 -0
  583. data/examples/hr/db/queue_schema.rb +129 -0
  584. data/examples/hr/db/schema.rb +588 -0
  585. data/examples/hr/db/seeds.rb +932 -0
  586. data/examples/hr/erd.md +396 -0
  587. data/examples/hr/public/400.html +135 -0
  588. data/examples/hr/public/404.html +135 -0
  589. data/examples/hr/public/406-unsupported-browser.html +135 -0
  590. data/examples/hr/public/422.html +135 -0
  591. data/examples/hr/public/500.html +135 -0
  592. data/examples/hr/public/icon.svg +3 -0
  593. data/examples/hr/public/robots.txt +1 -0
  594. data/examples/showcase/Gemfile +15 -0
  595. data/examples/showcase/Gemfile.lock +425 -0
  596. data/examples/showcase/Rakefile +2 -0
  597. data/examples/showcase/app/actions/showcase_batch_task/assign_batch.rb +20 -0
  598. data/examples/showcase/app/actions/showcase_batch_task/close_task.rb +21 -0
  599. data/examples/showcase/app/actions/showcase_condition/approve.rb +20 -0
  600. data/examples/showcase/app/actions/showcase_permission/lock.rb +20 -0
  601. data/examples/showcase/app/assets/config/manifest.js +3 -0
  602. data/examples/showcase/app/assets/stylesheets/application.css +27 -0
  603. data/examples/showcase/app/condition_services/budget_threshold.rb +16 -0
  604. data/examples/showcase/app/condition_services/overdue_check.rb +11 -0
  605. data/examples/showcase/app/controllers/application_controller.rb +2 -0
  606. data/examples/showcase/app/controllers/docs_controller.rb +48 -0
  607. data/examples/showcase/app/controllers/host_inventory_items_managed_controller.rb +90 -0
  608. data/examples/showcase/app/controllers/host_inventory_items_report_controller.rb +39 -0
  609. data/examples/showcase/app/controllers/host_inventory_items_wizard_controller.rb +50 -0
  610. data/examples/showcase/app/data_providers/showcase_amount_provider.rb +52 -0
  611. data/examples/showcase/app/data_providers/weather_station_provider.rb +140 -0
  612. data/examples/showcase/app/event_handlers/showcase_model/on_status_change.rb +17 -0
  613. data/examples/showcase/app/event_handlers/showcase_permission/on_status_change.rb +17 -0
  614. data/examples/showcase/app/event_handlers/showcase_workflow/log_review_exit.rb +16 -0
  615. data/examples/showcase/app/event_handlers/showcase_workflow/notify_reviewers.rb +15 -0
  616. data/examples/showcase/app/event_handlers/showcase_workflow/request_submitted.rb +15 -0
  617. data/examples/showcase/app/lcp_metrics/showcase_metrics.rb +31 -0
  618. data/examples/showcase/app/lcp_services/computed/showcase_score.rb +18 -0
  619. data/examples/showcase/app/lcp_services/computed/showcase_total.rb +13 -0
  620. data/examples/showcase/app/lcp_services/defaults/one_week_from_now.rb +11 -0
  621. data/examples/showcase/app/lcp_services/menu_items/recent_announcements.rb +36 -0
  622. data/examples/showcase/app/lcp_services/virtual_columns/project_health.rb +26 -0
  623. data/examples/showcase/app/model_extensions/lcp_error_log_extension.rb +12 -0
  624. data/examples/showcase/app/models/host_inventory_item.rb +20 -0
  625. data/examples/showcase/app/models/platform_profile.rb +27 -0
  626. data/examples/showcase/app/models/platform_user.rb +5 -0
  627. data/examples/showcase/app/views/docs/show.html.erb +19 -0
  628. data/examples/showcase/app/views/host_inventory_items_report/index.html.erb +61 -0
  629. data/examples/showcase/app/views/host_inventory_items_report/show.html.erb +39 -0
  630. data/examples/showcase/app/views/layouts/docs.html.erb +46 -0
  631. data/examples/showcase/app/views/showcase/menu_renderers/_status_pill.html.erb +17 -0
  632. data/examples/showcase/app/views/showcase_custom/_activity_timeline.html.erb +37 -0
  633. data/examples/showcase/app/views/showcase_custom/_card_index.html.erb +74 -0
  634. data/examples/showcase/app/views/showcase_custom/_detail_show.html.erb +115 -0
  635. data/examples/showcase/app/views/showcase_custom/_location_map.html.erb +29 -0
  636. data/examples/showcase/app/views/showcase_custom/_location_view.html.erb +34 -0
  637. data/examples/showcase/app/views/showcase_custom/_quick_stats.html.erb +50 -0
  638. data/examples/showcase/app/views/showcase_custom/_stats_sidebar.html.erb +42 -0
  639. data/examples/showcase/app/views/showcase_custom/_tags_editor.html.erb +48 -0
  640. data/examples/showcase/bin/rails +4 -0
  641. data/examples/showcase/bin/rake +4 -0
  642. data/examples/showcase/config/application.rb +37 -0
  643. data/examples/showcase/config/boot.rb +2 -0
  644. data/examples/showcase/config/database.yml +12 -0
  645. data/examples/showcase/config/environment.rb +2 -0
  646. data/examples/showcase/config/initializers/devise.rb +5 -0
  647. data/examples/showcase/config/initializers/lcp_ruby.rb +175 -0
  648. data/examples/showcase/config/lcp_ruby/auth.yml +60 -0
  649. data/examples/showcase/config/lcp_ruby/jobs/data_import.yml +7 -0
  650. data/examples/showcase/config/lcp_ruby/jobs/showcase_cleanup.yml +11 -0
  651. data/examples/showcase/config/lcp_ruby/jobs/showcase_event_triggered.yml +11 -0
  652. data/examples/showcase/config/lcp_ruby/jobs/showcase_multi_step.yml +9 -0
  653. data/examples/showcase/config/lcp_ruby/jobs/showcase_webhook.yml +13 -0
  654. data/examples/showcase/config/lcp_ruby/menu.yml +249 -0
  655. data/examples/showcase/config/lcp_ruby/models/_base_document.rb +26 -0
  656. data/examples/showcase/config/lcp_ruby/models/_categorized_document.rb +19 -0
  657. data/examples/showcase/config/lcp_ruby/models/_contactable.rb +20 -0
  658. data/examples/showcase/config/lcp_ruby/models/api_token.rb +23 -0
  659. data/examples/showcase/config/lcp_ruby/models/article.rb +49 -0
  660. data/examples/showcase/config/lcp_ruby/models/article_tag.rb +10 -0
  661. data/examples/showcase/config/lcp_ruby/models/author.rb +16 -0
  662. data/examples/showcase/config/lcp_ruby/models/batch_operation.yml +79 -0
  663. data/examples/showcase/config/lcp_ruby/models/batch_operation_item.yml +45 -0
  664. data/examples/showcase/config/lcp_ruby/models/category.rb +23 -0
  665. data/examples/showcase/config/lcp_ruby/models/comment.rb +21 -0
  666. data/examples/showcase/config/lcp_ruby/models/custom_field_definition.rb +59 -0
  667. data/examples/showcase/config/lcp_ruby/models/department.rb +32 -0
  668. data/examples/showcase/config/lcp_ruby/models/employee.rb +52 -0
  669. data/examples/showcase/config/lcp_ruby/models/employee_emergency_contact.rb +24 -0
  670. data/examples/showcase/config/lcp_ruby/models/employee_profile.rb +18 -0
  671. data/examples/showcase/config/lcp_ruby/models/employee_skill.rb +10 -0
  672. data/examples/showcase/config/lcp_ruby/models/export_log.yml +27 -0
  673. data/examples/showcase/config/lcp_ruby/models/export_profile.yml +37 -0
  674. data/examples/showcase/config/lcp_ruby/models/feature.rb +76 -0
  675. data/examples/showcase/config/lcp_ruby/models/gapfree_sequence.rb +17 -0
  676. data/examples/showcase/config/lcp_ruby/models/group.rb +26 -0
  677. data/examples/showcase/config/lcp_ruby/models/group_membership.rb +21 -0
  678. data/examples/showcase/config/lcp_ruby/models/group_role_mapping.rb +14 -0
  679. data/examples/showcase/config/lcp_ruby/models/host_inventory_item.yml +111 -0
  680. data/examples/showcase/config/lcp_ruby/models/import_profile.rb +30 -0
  681. data/examples/showcase/config/lcp_ruby/models/import_row.rb +32 -0
  682. data/examples/showcase/config/lcp_ruby/models/ingredient_def.rb +11 -0
  683. data/examples/showcase/config/lcp_ruby/models/lcp_error_log.yml +61 -0
  684. data/examples/showcase/config/lcp_ruby/models/page_config.rb +19 -0
  685. data/examples/showcase/config/lcp_ruby/models/permission_config.rb +21 -0
  686. data/examples/showcase/config/lcp_ruby/models/pipeline.rb +15 -0
  687. data/examples/showcase/config/lcp_ruby/models/pipeline_stage.rb +17 -0
  688. data/examples/showcase/config/lcp_ruby/models/platform_profile.rb +104 -0
  689. data/examples/showcase/config/lcp_ruby/models/profile_setting.rb +17 -0
  690. data/examples/showcase/config/lcp_ruby/models/profile_tag.rb +19 -0
  691. data/examples/showcase/config/lcp_ruby/models/project.rb +23 -0
  692. data/examples/showcase/config/lcp_ruby/models/role.rb +24 -0
  693. data/examples/showcase/config/lcp_ruby/models/saved_filter.rb +50 -0
  694. data/examples/showcase/config/lcp_ruby/models/showcase_aggregate.rb +93 -0
  695. data/examples/showcase/config/lcp_ruby/models/showcase_aggregate_company.rb +14 -0
  696. data/examples/showcase/config/lcp_ruby/models/showcase_aggregate_item.rb +25 -0
  697. data/examples/showcase/config/lcp_ruby/models/showcase_announcement.rb +20 -0
  698. data/examples/showcase/config/lcp_ruby/models/showcase_array.rb +45 -0
  699. data/examples/showcase/config/lcp_ruby/models/showcase_attachment.rb +49 -0
  700. data/examples/showcase/config/lcp_ruby/models/showcase_audit_log.yml +44 -0
  701. data/examples/showcase/config/lcp_ruby/models/showcase_audited_record.rb +20 -0
  702. data/examples/showcase/config/lcp_ruby/models/showcase_batch_task.rb +27 -0
  703. data/examples/showcase/config/lcp_ruby/models/showcase_business_unit.rb +26 -0
  704. data/examples/showcase/config/lcp_ruby/models/showcase_condition.rb +24 -0
  705. data/examples/showcase/config/lcp_ruby/models/showcase_condition_category.rb +16 -0
  706. data/examples/showcase/config/lcp_ruby/models/showcase_condition_task.rb +16 -0
  707. data/examples/showcase/config/lcp_ruby/models/showcase_condition_threshold.rb +13 -0
  708. data/examples/showcase/config/lcp_ruby/models/showcase_contact.rb +22 -0
  709. data/examples/showcase/config/lcp_ruby/models/showcase_custom_render.rb +38 -0
  710. data/examples/showcase/config/lcp_ruby/models/showcase_delete_reason.rb +11 -0
  711. data/examples/showcase/config/lcp_ruby/models/showcase_division.rb +31 -0
  712. data/examples/showcase/config/lcp_ruby/models/showcase_extensibility.rb +25 -0
  713. data/examples/showcase/config/lcp_ruby/models/showcase_field.rb +53 -0
  714. data/examples/showcase/config/lcp_ruby/models/showcase_form.rb +23 -0
  715. data/examples/showcase/config/lcp_ruby/models/showcase_form_action.rb +38 -0
  716. data/examples/showcase/config/lcp_ruby/models/showcase_grade.rb +18 -0
  717. data/examples/showcase/config/lcp_ruby/models/showcase_hr_employee.rb +90 -0
  718. data/examples/showcase/config/lcp_ruby/models/showcase_item_class.rb +31 -0
  719. data/examples/showcase/config/lcp_ruby/models/showcase_job_execution.rb +49 -0
  720. data/examples/showcase/config/lcp_ruby/models/showcase_memo.rb +23 -0
  721. data/examples/showcase/config/lcp_ruby/models/showcase_model.rb +74 -0
  722. data/examples/showcase/config/lcp_ruby/models/showcase_organization.rb +31 -0
  723. data/examples/showcase/config/lcp_ruby/models/showcase_permission.rb +30 -0
  724. data/examples/showcase/config/lcp_ruby/models/showcase_person.rb +23 -0
  725. data/examples/showcase/config/lcp_ruby/models/showcase_positioning.rb +19 -0
  726. data/examples/showcase/config/lcp_ruby/models/showcase_quick_note.rb +13 -0
  727. data/examples/showcase/config/lcp_ruby/models/showcase_recipe.rb +17 -0
  728. data/examples/showcase/config/lcp_ruby/models/showcase_report.rb +32 -0
  729. data/examples/showcase/config/lcp_ruby/models/showcase_school_class.rb +17 -0
  730. data/examples/showcase/config/lcp_ruby/models/showcase_search.rb +84 -0
  731. data/examples/showcase/config/lcp_ruby/models/showcase_sequence.rb +46 -0
  732. data/examples/showcase/config/lcp_ruby/models/showcase_soft_delete.rb +30 -0
  733. data/examples/showcase/config/lcp_ruby/models/showcase_soft_delete_item.rb +21 -0
  734. data/examples/showcase/config/lcp_ruby/models/showcase_student.rb +17 -0
  735. data/examples/showcase/config/lcp_ruby/models/showcase_type_default.rb +49 -0
  736. data/examples/showcase/config/lcp_ruby/models/showcase_userstamps.rb +26 -0
  737. data/examples/showcase/config/lcp_ruby/models/showcase_virtual_field.rb +68 -0
  738. data/examples/showcase/config/lcp_ruby/models/showcase_workflow.rb +54 -0
  739. data/examples/showcase/config/lcp_ruby/models/skill.rb +22 -0
  740. data/examples/showcase/config/lcp_ruby/models/tag.rb +16 -0
  741. data/examples/showcase/config/lcp_ruby/models/user.rb +54 -0
  742. data/examples/showcase/config/lcp_ruby/models/weather_station.rb +20 -0
  743. data/examples/showcase/config/lcp_ruby/models/workflow_approval_request.yml +77 -0
  744. data/examples/showcase/config/lcp_ruby/models/workflow_approval_step.yml +56 -0
  745. data/examples/showcase/config/lcp_ruby/models/workflow_approval_task.yml +51 -0
  746. data/examples/showcase/config/lcp_ruby/models/workflow_audit_log.yml +74 -0
  747. data/examples/showcase/config/lcp_ruby/pages/article_detail.yml +32 -0
  748. data/examples/showcase/config/lcp_ruby/pages/author_detail.yml +27 -0
  749. data/examples/showcase/config/lcp_ruby/pages/category_detail.yml +24 -0
  750. data/examples/showcase/config/lcp_ruby/pages/chart_showcase.yml +151 -0
  751. data/examples/showcase/config/lcp_ruby/pages/department_detail.yml +55 -0
  752. data/examples/showcase/config/lcp_ruby/pages/department_explorer.yml +60 -0
  753. data/examples/showcase/config/lcp_ruby/pages/employee_overview.yml +106 -0
  754. data/examples/showcase/config/lcp_ruby/pages/employee_transfer_dialog.yml +24 -0
  755. data/examples/showcase/config/lcp_ruby/pages/hr_turnover_dashboard.yml +288 -0
  756. data/examples/showcase/config/lcp_ruby/pages/main_dashboard.yml +142 -0
  757. data/examples/showcase/config/lcp_ruby/pages/monitoring_dashboard.yml +58 -0
  758. data/examples/showcase/config/lcp_ruby/pages/pipeline_detail.yml +16 -0
  759. data/examples/showcase/config/lcp_ruby/pages/showcase_custom_zones.yml +39 -0
  760. data/examples/showcase/config/lcp_ruby/pages/showcase_form_action_dialog.yml +11 -0
  761. data/examples/showcase/config/lcp_ruby/pages/workflow_request_detail.yml +34 -0
  762. data/examples/showcase/config/lcp_ruby/permissions/api_token.yml +26 -0
  763. data/examples/showcase/config/lcp_ruby/permissions/batch_operation.yml +36 -0
  764. data/examples/showcase/config/lcp_ruby/permissions/custom_field_definition.yml +15 -0
  765. data/examples/showcase/config/lcp_ruby/permissions/default.yml +28 -0
  766. data/examples/showcase/config/lcp_ruby/permissions/export_log.yml +23 -0
  767. data/examples/showcase/config/lcp_ruby/permissions/export_profile.yml +25 -0
  768. data/examples/showcase/config/lcp_ruby/permissions/gapfree_sequence.yml +6 -0
  769. data/examples/showcase/config/lcp_ruby/permissions/group.yml +20 -0
  770. data/examples/showcase/config/lcp_ruby/permissions/group_membership.yml +20 -0
  771. data/examples/showcase/config/lcp_ruby/permissions/group_role_mapping.yml +20 -0
  772. data/examples/showcase/config/lcp_ruby/permissions/host_inventory_item.yml +34 -0
  773. data/examples/showcase/config/lcp_ruby/permissions/import_profile.yml +29 -0
  774. data/examples/showcase/config/lcp_ruby/permissions/import_row.yml +17 -0
  775. data/examples/showcase/config/lcp_ruby/permissions/lcp_error_log.yml +8 -0
  776. data/examples/showcase/config/lcp_ruby/permissions/page_config.yml +15 -0
  777. data/examples/showcase/config/lcp_ruby/permissions/permission_config.yml +15 -0
  778. data/examples/showcase/config/lcp_ruby/permissions/platform_profile.yml +23 -0
  779. data/examples/showcase/config/lcp_ruby/permissions/profile_setting.yml +23 -0
  780. data/examples/showcase/config/lcp_ruby/permissions/profile_tag.yml +23 -0
  781. data/examples/showcase/config/lcp_ruby/permissions/role.yml +20 -0
  782. data/examples/showcase/config/lcp_ruby/permissions/saved_filter.yml +39 -0
  783. data/examples/showcase/config/lcp_ruby/permissions/showcase_announcement.yml +22 -0
  784. data/examples/showcase/config/lcp_ruby/permissions/showcase_audit_log.yml +15 -0
  785. data/examples/showcase/config/lcp_ruby/permissions/showcase_audited_record.yml +15 -0
  786. data/examples/showcase/config/lcp_ruby/permissions/showcase_batch_task.yml +31 -0
  787. data/examples/showcase/config/lcp_ruby/permissions/showcase_condition.yml +54 -0
  788. data/examples/showcase/config/lcp_ruby/permissions/showcase_contact.yml +21 -0
  789. data/examples/showcase/config/lcp_ruby/permissions/showcase_custom_render.yml +21 -0
  790. data/examples/showcase/config/lcp_ruby/permissions/showcase_delete_reason.yml +12 -0
  791. data/examples/showcase/config/lcp_ruby/permissions/showcase_form_action.yml +26 -0
  792. data/examples/showcase/config/lcp_ruby/permissions/showcase_grade.yml +33 -0
  793. data/examples/showcase/config/lcp_ruby/permissions/showcase_job_execution.yml +23 -0
  794. data/examples/showcase/config/lcp_ruby/permissions/showcase_permission.yml +47 -0
  795. data/examples/showcase/config/lcp_ruby/permissions/showcase_quick_note.yml +12 -0
  796. data/examples/showcase/config/lcp_ruby/permissions/showcase_school_class.yml +37 -0
  797. data/examples/showcase/config/lcp_ruby/permissions/showcase_student.yml +43 -0
  798. data/examples/showcase/config/lcp_ruby/permissions/showcase_workflow.yml +34 -0
  799. data/examples/showcase/config/lcp_ruby/permissions/workflow_approval_request.yml +18 -0
  800. data/examples/showcase/config/lcp_ruby/permissions/workflow_approval_step.yml +18 -0
  801. data/examples/showcase/config/lcp_ruby/permissions/workflow_approval_task.yml +18 -0
  802. data/examples/showcase/config/lcp_ruby/permissions/workflow_audit_log.yml +19 -0
  803. data/examples/showcase/config/lcp_ruby/presenters/announcements.rb +59 -0
  804. data/examples/showcase/config/lcp_ruby/presenters/approval_requests.rb +69 -0
  805. data/examples/showcase/config/lcp_ruby/presenters/approval_steps.rb +59 -0
  806. data/examples/showcase/config/lcp_ruby/presenters/approval_tasks.rb +65 -0
  807. data/examples/showcase/config/lcp_ruby/presenters/article_comments_zone.rb +12 -0
  808. data/examples/showcase/config/lcp_ruby/presenters/article_related_zone.rb +15 -0
  809. data/examples/showcase/config/lcp_ruby/presenters/articles.rb +149 -0
  810. data/examples/showcase/config/lcp_ruby/presenters/articles_tiles.rb +30 -0
  811. data/examples/showcase/config/lcp_ruby/presenters/author_articles_zone.rb +12 -0
  812. data/examples/showcase/config/lcp_ruby/presenters/author_show_zone.rb +12 -0
  813. data/examples/showcase/config/lcp_ruby/presenters/authors.rb +39 -0
  814. data/examples/showcase/config/lcp_ruby/presenters/batch_operation_items.yml +45 -0
  815. data/examples/showcase/config/lcp_ruby/presenters/batch_operations.yml +66 -0
  816. data/examples/showcase/config/lcp_ruby/presenters/categories.rb +50 -0
  817. data/examples/showcase/config/lcp_ruby/presenters/category_articles_zone.rb +20 -0
  818. data/examples/showcase/config/lcp_ruby/presenters/category_children_zone.rb +10 -0
  819. data/examples/showcase/config/lcp_ruby/presenters/comment_quick_add_dialog.rb +15 -0
  820. data/examples/showcase/config/lcp_ruby/presenters/custom_fields.rb +124 -0
  821. data/examples/showcase/config/lcp_ruby/presenters/dashboard_employees.rb +16 -0
  822. data/examples/showcase/config/lcp_ruby/presenters/delete_reason_dialog.rb +13 -0
  823. data/examples/showcase/config/lcp_ruby/presenters/departments.rb +55 -0
  824. data/examples/showcase/config/lcp_ruby/presenters/dept_add_employee_dialog.rb +19 -0
  825. data/examples/showcase/config/lcp_ruby/presenters/dept_children_zone.rb +10 -0
  826. data/examples/showcase/config/lcp_ruby/presenters/dept_detail_zone.rb +14 -0
  827. data/examples/showcase/config/lcp_ruby/presenters/dept_employees_zone.rb +16 -0
  828. data/examples/showcase/config/lcp_ruby/presenters/dept_list_selection_zone.rb +19 -0
  829. data/examples/showcase/config/lcp_ruby/presenters/employee_overview_index_zone.rb +36 -0
  830. data/examples/showcase/config/lcp_ruby/presenters/employee_quick_add_dialog.rb +14 -0
  831. data/examples/showcase/config/lcp_ruby/presenters/employee_show_zone.rb +20 -0
  832. data/examples/showcase/config/lcp_ruby/presenters/employee_transfer_form_zone.rb +19 -0
  833. data/examples/showcase/config/lcp_ruby/presenters/employees.rb +165 -0
  834. data/examples/showcase/config/lcp_ruby/presenters/employees_tiles.rb +33 -0
  835. data/examples/showcase/config/lcp_ruby/presenters/export_logs.yml +58 -0
  836. data/examples/showcase/config/lcp_ruby/presenters/export_profiles.yml +70 -0
  837. data/examples/showcase/config/lcp_ruby/presenters/extensibility_quick_edit_dialog.rb +13 -0
  838. data/examples/showcase/config/lcp_ruby/presenters/feature_kanban.rb +30 -0
  839. data/examples/showcase/config/lcp_ruby/presenters/features_card.rb +179 -0
  840. data/examples/showcase/config/lcp_ruby/presenters/features_hub.rb +44 -0
  841. data/examples/showcase/config/lcp_ruby/presenters/features_table.rb +37 -0
  842. data/examples/showcase/config/lcp_ruby/presenters/features_tiles.rb +48 -0
  843. data/examples/showcase/config/lcp_ruby/presenters/group_memberships.rb +54 -0
  844. data/examples/showcase/config/lcp_ruby/presenters/group_role_mappings.rb +48 -0
  845. data/examples/showcase/config/lcp_ruby/presenters/groups.rb +74 -0
  846. data/examples/showcase/config/lcp_ruby/presenters/host_inventory_items.rb +99 -0
  847. data/examples/showcase/config/lcp_ruby/presenters/host_inventory_items_managed.rb +84 -0
  848. data/examples/showcase/config/lcp_ruby/presenters/host_inventory_items_report.rb +40 -0
  849. data/examples/showcase/config/lcp_ruby/presenters/host_inventory_items_wizard.rb +76 -0
  850. data/examples/showcase/config/lcp_ruby/presenters/import_profiles.rb +61 -0
  851. data/examples/showcase/config/lcp_ruby/presenters/import_rows.rb +39 -0
  852. data/examples/showcase/config/lcp_ruby/presenters/lcp_error_logs.yml +46 -0
  853. data/examples/showcase/config/lcp_ruby/presenters/my_api_tokens.rb +35 -0
  854. data/examples/showcase/config/lcp_ruby/presenters/my_api_tokens_create_dialog.rb +27 -0
  855. data/examples/showcase/config/lcp_ruby/presenters/my_employee_profile.rb +24 -0
  856. data/examples/showcase/config/lcp_ruby/presenters/my_settings.rb +50 -0
  857. data/examples/showcase/config/lcp_ruby/presenters/page_configs.rb +56 -0
  858. data/examples/showcase/config/lcp_ruby/presenters/permission_configs.rb +58 -0
  859. data/examples/showcase/config/lcp_ruby/presenters/pipeline_edit_zone.rb +11 -0
  860. data/examples/showcase/config/lcp_ruby/presenters/pipeline_stages.rb +51 -0
  861. data/examples/showcase/config/lcp_ruby/presenters/pipeline_stages_zone.rb +11 -0
  862. data/examples/showcase/config/lcp_ruby/presenters/pipelines.rb +40 -0
  863. data/examples/showcase/config/lcp_ruby/presenters/platform_profiles.rb +90 -0
  864. data/examples/showcase/config/lcp_ruby/presenters/projects.rb +58 -0
  865. data/examples/showcase/config/lcp_ruby/presenters/quick_note_dialog.rb +14 -0
  866. data/examples/showcase/config/lcp_ruby/presenters/roles.rb +60 -0
  867. data/examples/showcase/config/lcp_ruby/presenters/save_filter_dialog.rb +17 -0
  868. data/examples/showcase/config/lcp_ruby/presenters/saved_filters.rb +94 -0
  869. data/examples/showcase/config/lcp_ruby/presenters/showcase_aggregate_items.rb +61 -0
  870. data/examples/showcase/config/lcp_ruby/presenters/showcase_aggregates.rb +115 -0
  871. data/examples/showcase/config/lcp_ruby/presenters/showcase_aggregates_tiles.rb +44 -0
  872. data/examples/showcase/config/lcp_ruby/presenters/showcase_amount_kanban.rb +31 -0
  873. data/examples/showcase/config/lcp_ruby/presenters/showcase_arrays.rb +140 -0
  874. data/examples/showcase/config/lcp_ruby/presenters/showcase_attachments.rb +66 -0
  875. data/examples/showcase/config/lcp_ruby/presenters/showcase_audit_logs.rb +46 -0
  876. data/examples/showcase/config/lcp_ruby/presenters/showcase_audited_records.rb +58 -0
  877. data/examples/showcase/config/lcp_ruby/presenters/showcase_batch_tasks.rb +97 -0
  878. data/examples/showcase/config/lcp_ruby/presenters/showcase_batch_tasks_archive.rb +52 -0
  879. data/examples/showcase/config/lcp_ruby/presenters/showcase_business_units.rb +43 -0
  880. data/examples/showcase/config/lcp_ruby/presenters/showcase_conditions.rb +195 -0
  881. data/examples/showcase/config/lcp_ruby/presenters/showcase_contacts.rb +82 -0
  882. data/examples/showcase/config/lcp_ruby/presenters/showcase_custom_render_with.rb +50 -0
  883. data/examples/showcase/config/lcp_ruby/presenters/showcase_custom_sections.rb +88 -0
  884. data/examples/showcase/config/lcp_ruby/presenters/showcase_custom_zones_main.rb +75 -0
  885. data/examples/showcase/config/lcp_ruby/presenters/showcase_divisions.rb +53 -0
  886. data/examples/showcase/config/lcp_ruby/presenters/showcase_extensibility.rb +48 -0
  887. data/examples/showcase/config/lcp_ruby/presenters/showcase_fields_card.rb +34 -0
  888. data/examples/showcase/config/lcp_ruby/presenters/showcase_fields_table.rb +128 -0
  889. data/examples/showcase/config/lcp_ruby/presenters/showcase_fields_tiles.rb +42 -0
  890. data/examples/showcase/config/lcp_ruby/presenters/showcase_form_action_dialog.rb +27 -0
  891. data/examples/showcase/config/lcp_ruby/presenters/showcase_form_actions.rb +132 -0
  892. data/examples/showcase/config/lcp_ruby/presenters/showcase_form_actions_overflow.rb +76 -0
  893. data/examples/showcase/config/lcp_ruby/presenters/showcase_forms.rb +110 -0
  894. data/examples/showcase/config/lcp_ruby/presenters/showcase_grades.rb +38 -0
  895. data/examples/showcase/config/lcp_ruby/presenters/showcase_hr_employees.rb +84 -0
  896. data/examples/showcase/config/lcp_ruby/presenters/showcase_item_classes.rb +120 -0
  897. data/examples/showcase/config/lcp_ruby/presenters/showcase_job_executions.rb +150 -0
  898. data/examples/showcase/config/lcp_ruby/presenters/showcase_memos.rb +96 -0
  899. data/examples/showcase/config/lcp_ruby/presenters/showcase_models.rb +112 -0
  900. data/examples/showcase/config/lcp_ruby/presenters/showcase_organizations.rb +106 -0
  901. data/examples/showcase/config/lcp_ruby/presenters/showcase_people.rb +97 -0
  902. data/examples/showcase/config/lcp_ruby/presenters/showcase_permissions.rb +84 -0
  903. data/examples/showcase/config/lcp_ruby/presenters/showcase_positioning.rb +61 -0
  904. data/examples/showcase/config/lcp_ruby/presenters/showcase_recipes.rb +105 -0
  905. data/examples/showcase/config/lcp_ruby/presenters/showcase_recipes_raw.rb +32 -0
  906. data/examples/showcase/config/lcp_ruby/presenters/showcase_reports.rb +109 -0
  907. data/examples/showcase/config/lcp_ruby/presenters/showcase_school_classes.rb +34 -0
  908. data/examples/showcase/config/lcp_ruby/presenters/showcase_searches.rb +226 -0
  909. data/examples/showcase/config/lcp_ruby/presenters/showcase_sequences.rb +67 -0
  910. data/examples/showcase/config/lcp_ruby/presenters/showcase_soft_delete.rb +88 -0
  911. data/examples/showcase/config/lcp_ruby/presenters/showcase_soft_delete_archive.rb +52 -0
  912. data/examples/showcase/config/lcp_ruby/presenters/showcase_soft_delete_items.rb +47 -0
  913. data/examples/showcase/config/lcp_ruby/presenters/showcase_students.rb +33 -0
  914. data/examples/showcase/config/lcp_ruby/presenters/showcase_type_defaults.rb +92 -0
  915. data/examples/showcase/config/lcp_ruby/presenters/showcase_userstamps.rb +76 -0
  916. data/examples/showcase/config/lcp_ruby/presenters/showcase_virtual_fields.rb +104 -0
  917. data/examples/showcase/config/lcp_ruby/presenters/showcase_workflow_admin.rb +24 -0
  918. data/examples/showcase/config/lcp_ruby/presenters/showcase_workflow_kanban.rb +36 -0
  919. data/examples/showcase/config/lcp_ruby/presenters/showcase_workflows.rb +103 -0
  920. data/examples/showcase/config/lcp_ruby/presenters/tags.rb +35 -0
  921. data/examples/showcase/config/lcp_ruby/presenters/users.rb +61 -0
  922. data/examples/showcase/config/lcp_ruby/presenters/weather_stations.rb +60 -0
  923. data/examples/showcase/config/lcp_ruby/presenters/workflow_audit_logs.rb +76 -0
  924. data/examples/showcase/config/lcp_ruby/presenters/workflow_request_audit_zone.rb +28 -0
  925. data/examples/showcase/config/lcp_ruby/theme.yml +2 -0
  926. data/examples/showcase/config/lcp_ruby/types/currency.yml +15 -0
  927. data/examples/showcase/config/lcp_ruby/types/percentage.yml +16 -0
  928. data/examples/showcase/config/lcp_ruby/types/rating.yml +20 -0
  929. data/examples/showcase/config/lcp_ruby/views/announcements.yml +7 -0
  930. data/examples/showcase/config/lcp_ruby/views/approval_requests.yml +7 -0
  931. data/examples/showcase/config/lcp_ruby/views/approval_steps.yml +7 -0
  932. data/examples/showcase/config/lcp_ruby/views/approval_tasks.yml +7 -0
  933. data/examples/showcase/config/lcp_ruby/views/articles.yml +12 -0
  934. data/examples/showcase/config/lcp_ruby/views/authors.yml +7 -0
  935. data/examples/showcase/config/lcp_ruby/views/batch_operation_items.yml +6 -0
  936. data/examples/showcase/config/lcp_ruby/views/batch_operations.yml +10 -0
  937. data/examples/showcase/config/lcp_ruby/views/categories.yml +9 -0
  938. data/examples/showcase/config/lcp_ruby/views/custom_fields.rb +8 -0
  939. data/examples/showcase/config/lcp_ruby/views/dashboard.yml +10 -0
  940. data/examples/showcase/config/lcp_ruby/views/department_explorer.yml +7 -0
  941. data/examples/showcase/config/lcp_ruby/views/departments.yml +9 -0
  942. data/examples/showcase/config/lcp_ruby/views/employee_overview.yml +7 -0
  943. data/examples/showcase/config/lcp_ruby/views/employees.yml +12 -0
  944. data/examples/showcase/config/lcp_ruby/views/export_logs.yml +7 -0
  945. data/examples/showcase/config/lcp_ruby/views/export_profiles.yml +7 -0
  946. data/examples/showcase/config/lcp_ruby/views/features.yml +19 -0
  947. data/examples/showcase/config/lcp_ruby/views/group_memberships.yml +7 -0
  948. data/examples/showcase/config/lcp_ruby/views/group_role_mappings.yml +7 -0
  949. data/examples/showcase/config/lcp_ruby/views/groups.yml +7 -0
  950. data/examples/showcase/config/lcp_ruby/views/host_inventory_items.yml +16 -0
  951. data/examples/showcase/config/lcp_ruby/views/hr_turnover_dashboard.yml +7 -0
  952. data/examples/showcase/config/lcp_ruby/views/import_profiles.yml +7 -0
  953. data/examples/showcase/config/lcp_ruby/views/import_rows.yml +7 -0
  954. data/examples/showcase/config/lcp_ruby/views/lcp_error_logs.yml +10 -0
  955. data/examples/showcase/config/lcp_ruby/views/monitoring.yml +7 -0
  956. data/examples/showcase/config/lcp_ruby/views/my_api_tokens.rb +9 -0
  957. data/examples/showcase/config/lcp_ruby/views/page_configs.yml +11 -0
  958. data/examples/showcase/config/lcp_ruby/views/permission_configs.yml +11 -0
  959. data/examples/showcase/config/lcp_ruby/views/pipeline_stages.yml +7 -0
  960. data/examples/showcase/config/lcp_ruby/views/pipelines.yml +7 -0
  961. data/examples/showcase/config/lcp_ruby/views/platform_profiles.yml +7 -0
  962. data/examples/showcase/config/lcp_ruby/views/projects.yml +9 -0
  963. data/examples/showcase/config/lcp_ruby/views/roles.yml +7 -0
  964. data/examples/showcase/config/lcp_ruby/views/saved_filters.yml +7 -0
  965. data/examples/showcase/config/lcp_ruby/views/showcase_aggregate_items.yml +7 -0
  966. data/examples/showcase/config/lcp_ruby/views/showcase_aggregates.yml +10 -0
  967. data/examples/showcase/config/lcp_ruby/views/showcase_arrays.yml +7 -0
  968. data/examples/showcase/config/lcp_ruby/views/showcase_attachments.yml +7 -0
  969. data/examples/showcase/config/lcp_ruby/views/showcase_audit_logs.yml +11 -0
  970. data/examples/showcase/config/lcp_ruby/views/showcase_audited_records.yml +10 -0
  971. data/examples/showcase/config/lcp_ruby/views/showcase_batch_tasks.yml +10 -0
  972. data/examples/showcase/config/lcp_ruby/views/showcase_business_units.yml +7 -0
  973. data/examples/showcase/config/lcp_ruby/views/showcase_conditions.yml +7 -0
  974. data/examples/showcase/config/lcp_ruby/views/showcase_contacts.yml +7 -0
  975. data/examples/showcase/config/lcp_ruby/views/showcase_custom_render_with.yml +7 -0
  976. data/examples/showcase/config/lcp_ruby/views/showcase_custom_sections.yml +7 -0
  977. data/examples/showcase/config/lcp_ruby/views/showcase_custom_zones.yml +7 -0
  978. data/examples/showcase/config/lcp_ruby/views/showcase_divisions.yml +9 -0
  979. data/examples/showcase/config/lcp_ruby/views/showcase_extensibility.yml +7 -0
  980. data/examples/showcase/config/lcp_ruby/views/showcase_fields.yml +13 -0
  981. data/examples/showcase/config/lcp_ruby/views/showcase_form_actions.yml +10 -0
  982. data/examples/showcase/config/lcp_ruby/views/showcase_forms.yml +7 -0
  983. data/examples/showcase/config/lcp_ruby/views/showcase_grades.yml +9 -0
  984. data/examples/showcase/config/lcp_ruby/views/showcase_hr_employees.yml +9 -0
  985. data/examples/showcase/config/lcp_ruby/views/showcase_item_classes.yml +7 -0
  986. data/examples/showcase/config/lcp_ruby/views/showcase_job_executions.yml +9 -0
  987. data/examples/showcase/config/lcp_ruby/views/showcase_memos.yml +7 -0
  988. data/examples/showcase/config/lcp_ruby/views/showcase_models.yml +7 -0
  989. data/examples/showcase/config/lcp_ruby/views/showcase_organizations.yml +7 -0
  990. data/examples/showcase/config/lcp_ruby/views/showcase_people.yml +7 -0
  991. data/examples/showcase/config/lcp_ruby/views/showcase_permissions.yml +7 -0
  992. data/examples/showcase/config/lcp_ruby/views/showcase_positioning.yml +7 -0
  993. data/examples/showcase/config/lcp_ruby/views/showcase_recipes.yml +10 -0
  994. data/examples/showcase/config/lcp_ruby/views/showcase_reports.yml +7 -0
  995. data/examples/showcase/config/lcp_ruby/views/showcase_school_classes.yml +7 -0
  996. data/examples/showcase/config/lcp_ruby/views/showcase_searches.yml +7 -0
  997. data/examples/showcase/config/lcp_ruby/views/showcase_sequences.yml +7 -0
  998. data/examples/showcase/config/lcp_ruby/views/showcase_soft_delete.yml +10 -0
  999. data/examples/showcase/config/lcp_ruby/views/showcase_soft_delete_items.yml +8 -0
  1000. data/examples/showcase/config/lcp_ruby/views/showcase_students.yml +9 -0
  1001. data/examples/showcase/config/lcp_ruby/views/showcase_userstamps.yml +7 -0
  1002. data/examples/showcase/config/lcp_ruby/views/showcase_virtual_fields.yml +7 -0
  1003. data/examples/showcase/config/lcp_ruby/views/showcase_workflows.yml +16 -0
  1004. data/examples/showcase/config/lcp_ruby/views/tags.yml +7 -0
  1005. data/examples/showcase/config/lcp_ruby/views/users.yml +7 -0
  1006. data/examples/showcase/config/lcp_ruby/views/weather_stations.yml +7 -0
  1007. data/examples/showcase/config/lcp_ruby/views/workflow_audit_logs.yml +9 -0
  1008. data/examples/showcase/config/lcp_ruby/workflows/showcase_form_action.rb +48 -0
  1009. data/examples/showcase/config/lcp_ruby/workflows/showcase_workflow.rb +199 -0
  1010. data/examples/showcase/config/locales/cs.yml +2818 -0
  1011. data/examples/showcase/config/locales/en.yml +67 -0
  1012. data/examples/showcase/config/locales/lcp_ruby/api_tokens.cs.yml +46 -0
  1013. data/examples/showcase/config/locales/lcp_ruby/api_tokens.en.yml +49 -0
  1014. data/examples/showcase/config/routes.rb +21 -0
  1015. data/examples/showcase/config/storage.yml +3 -0
  1016. data/examples/showcase/config.ru +2 -0
  1017. data/examples/showcase/db/migrate/20260219124321_create_active_storage_tables.active_storage.rb +57 -0
  1018. data/examples/showcase/db/migrate/20260220072723_create_lcp_ruby_users.rb +42 -0
  1019. data/examples/showcase/db/migrate/20260406120000_create_host_inventory_items.rb +32 -0
  1020. data/examples/showcase/db/migrate/20260428134542_add_oidc_columns_to_lcp_ruby_users.rb +13 -0
  1021. data/examples/showcase/db/migrate/20260502120000_create_platform_profiles.rb +19 -0
  1022. data/examples/showcase/db/schema.rb +1222 -0
  1023. data/examples/showcase/db/seeds.rb +3085 -0
  1024. data/examples/showcase/erd.md +567 -0
  1025. data/examples/showcase/test/fixtures/import_articles.csv +4 -0
  1026. data/examples/showcase/test/fixtures/import_employees.csv +4 -0
  1027. data/examples/todo/Gemfile +8 -0
  1028. data/examples/todo/Gemfile.lock +415 -0
  1029. data/examples/todo/Rakefile +2 -0
  1030. data/examples/todo/app/assets/config/manifest.js +1 -0
  1031. data/examples/todo/app/controllers/application_controller.rb +6 -0
  1032. data/examples/todo/app/lcp_services/defaults/one_week_from_now.rb +11 -0
  1033. data/examples/todo/bin/rails +4 -0
  1034. data/examples/todo/bin/rake +4 -0
  1035. data/examples/todo/config/application.rb +31 -0
  1036. data/examples/todo/config/boot.rb +2 -0
  1037. data/examples/todo/config/database.yml +12 -0
  1038. data/examples/todo/config/environment.rb +2 -0
  1039. data/examples/todo/config/lcp_ruby/models/todo_item.yml +67 -0
  1040. data/examples/todo/config/lcp_ruby/models/todo_list.yml +49 -0
  1041. data/examples/todo/config/lcp_ruby/permissions/default.yml +10 -0
  1042. data/examples/todo/config/lcp_ruby/permissions/todo_item.yml +21 -0
  1043. data/examples/todo/config/lcp_ruby/presenters/todo_item.yml +75 -0
  1044. data/examples/todo/config/lcp_ruby/presenters/todo_list.yml +68 -0
  1045. data/examples/todo/config/lcp_ruby/views/todo_items.yml +11 -0
  1046. data/examples/todo/config/lcp_ruby/views/todo_lists.yml +9 -0
  1047. data/examples/todo/config/routes.rb +4 -0
  1048. data/examples/todo/config/storage.yml +3 -0
  1049. data/examples/todo/config.ru +2 -0
  1050. data/examples/todo/db/migrate/20260219103416_create_active_storage_tables.active_storage.rb +57 -0
  1051. data/examples/todo/db/schema.rb +63 -0
  1052. data/examples/todo/db/seeds.rb +24 -0
  1053. data/examples/todo/erd.md +21 -0
  1054. data/exe/lcp +33 -0
  1055. data/lib/generators/lcp_ruby/agent_setup_generator.rb +102 -0
  1056. data/lib/generators/lcp_ruby/api_tokens_generator.rb +102 -0
  1057. data/lib/generators/lcp_ruby/auditing_generator.rb +54 -0
  1058. data/lib/generators/lcp_ruby/background_jobs_generator.rb +61 -0
  1059. data/lib/generators/lcp_ruby/batch_operations_generator.rb +62 -0
  1060. data/lib/generators/lcp_ruby/claude_skills_generator.rb +47 -0
  1061. data/lib/generators/lcp_ruby/custom_fields_generator.rb +54 -0
  1062. data/lib/generators/lcp_ruby/dsl_to_yaml.rb +72 -0
  1063. data/lib/generators/lcp_ruby/entity/color_palette.rb +22 -0
  1064. data/lib/generators/lcp_ruby/entity/field_descriptor.rb +24 -0
  1065. data/lib/generators/lcp_ruby/entity/field_token_parser.rb +101 -0
  1066. data/lib/generators/lcp_ruby/entity/role_discovery.rb +45 -0
  1067. data/lib/generators/lcp_ruby/entity_generator.rb +1104 -0
  1068. data/lib/generators/lcp_ruby/export_generator.rb +71 -0
  1069. data/lib/generators/lcp_ruby/format_support.rb +56 -0
  1070. data/lib/generators/lcp_ruby/gapfree_sequences_generator.rb +64 -0
  1071. data/lib/generators/lcp_ruby/groups_generator.rb +94 -0
  1072. data/lib/generators/lcp_ruby/host_controller_generator.rb +202 -0
  1073. data/lib/generators/lcp_ruby/import_generator.rb +96 -0
  1074. data/lib/generators/lcp_ruby/install_auth_generator.rb +432 -0
  1075. data/lib/generators/lcp_ruby/install_generator.rb +319 -0
  1076. data/lib/generators/lcp_ruby/monitoring_generator.rb +58 -0
  1077. data/lib/generators/lcp_ruby/oidc_role_mappings_generator.rb +60 -0
  1078. data/lib/generators/lcp_ruby/pages_generator.rb +66 -0
  1079. data/lib/generators/lcp_ruby/permission_source_generator.rb +66 -0
  1080. data/lib/generators/lcp_ruby/role_model_generator.rb +73 -0
  1081. data/lib/generators/lcp_ruby/saved_filters_generator.rb +62 -0
  1082. data/lib/generators/lcp_ruby/templates/add_oidc_columns_to_lcp_ruby_users.rb.erb +13 -0
  1083. data/lib/generators/lcp_ruby/templates/agent_setup/agents_md.md +3 -0
  1084. data/lib/generators/lcp_ruby/templates/agent_setup/claude_md.md +12 -0
  1085. data/lib/generators/lcp_ruby/templates/api_tokens/create_dialog.rb +31 -0
  1086. data/lib/generators/lcp_ruby/templates/api_tokens/locales.en.yml +43 -0
  1087. data/lib/generators/lcp_ruby/templates/api_tokens/model.rb +23 -0
  1088. data/lib/generators/lcp_ruby/templates/api_tokens/permissions.yml +30 -0
  1089. data/lib/generators/lcp_ruby/templates/api_tokens/presenter.rb +38 -0
  1090. data/lib/generators/lcp_ruby/templates/api_tokens/view_group.rb +13 -0
  1091. data/lib/generators/lcp_ruby/templates/auditing/model.rb +34 -0
  1092. data/lib/generators/lcp_ruby/templates/auditing/permissions.yml +19 -0
  1093. data/lib/generators/lcp_ruby/templates/auditing/presenter.rb +41 -0
  1094. data/lib/generators/lcp_ruby/templates/auditing/view_group.rb +10 -0
  1095. data/lib/generators/lcp_ruby/templates/background_jobs/model.rb +59 -0
  1096. data/lib/generators/lcp_ruby/templates/background_jobs/permissions.yml +22 -0
  1097. data/lib/generators/lcp_ruby/templates/background_jobs/presenter.rb +82 -0
  1098. data/lib/generators/lcp_ruby/templates/background_jobs/view_group.rb +9 -0
  1099. data/lib/generators/lcp_ruby/templates/batch_operations/item_model.rb +28 -0
  1100. data/lib/generators/lcp_ruby/templates/batch_operations/item_presenter.rb +43 -0
  1101. data/lib/generators/lcp_ruby/templates/batch_operations/model.rb +42 -0
  1102. data/lib/generators/lcp_ruby/templates/batch_operations/permissions.yml +44 -0
  1103. data/lib/generators/lcp_ruby/templates/batch_operations/presenter.rb +61 -0
  1104. data/lib/generators/lcp_ruby/templates/batch_operations/view_group.rb +9 -0
  1105. data/lib/generators/lcp_ruby/templates/create_lcp_ruby_users.rb.erb +50 -0
  1106. data/lib/generators/lcp_ruby/templates/custom_fields/model.rb +60 -0
  1107. data/lib/generators/lcp_ruby/templates/custom_fields/permissions.yml +19 -0
  1108. data/lib/generators/lcp_ruby/templates/custom_fields/presenter.rb +128 -0
  1109. data/lib/generators/lcp_ruby/templates/custom_fields/view_group.rb +9 -0
  1110. data/lib/generators/lcp_ruby/templates/entity/model.rb +42 -0
  1111. data/lib/generators/lcp_ruby/templates/entity/permissions.yml +20 -0
  1112. data/lib/generators/lcp_ruby/templates/entity/presenter.rb +55 -0
  1113. data/lib/generators/lcp_ruby/templates/entity/view_group.rb +8 -0
  1114. data/lib/generators/lcp_ruby/templates/export/export_log_model.rb +30 -0
  1115. data/lib/generators/lcp_ruby/templates/export/export_log_permissions.yml +24 -0
  1116. data/lib/generators/lcp_ruby/templates/export/export_logs_presenter.rb +51 -0
  1117. data/lib/generators/lcp_ruby/templates/export/export_profile_model.rb +28 -0
  1118. data/lib/generators/lcp_ruby/templates/export/export_profile_permissions.yml +26 -0
  1119. data/lib/generators/lcp_ruby/templates/export/export_profiles_presenter.rb +59 -0
  1120. data/lib/generators/lcp_ruby/templates/gapfree_sequences/model.rb +18 -0
  1121. data/lib/generators/lcp_ruby/templates/gapfree_sequences/permissions.yml +19 -0
  1122. data/lib/generators/lcp_ruby/templates/gapfree_sequences/presenter.rb +51 -0
  1123. data/lib/generators/lcp_ruby/templates/gapfree_sequences/view_group.rb +9 -0
  1124. data/lib/generators/lcp_ruby/templates/groups/group_membership_model.rb +17 -0
  1125. data/lib/generators/lcp_ruby/templates/groups/group_model.rb +28 -0
  1126. data/lib/generators/lcp_ruby/templates/groups/group_permissions.yml +19 -0
  1127. data/lib/generators/lcp_ruby/templates/groups/group_presenter.rb +53 -0
  1128. data/lib/generators/lcp_ruby/templates/groups/group_role_mapping_model.rb +15 -0
  1129. data/lib/generators/lcp_ruby/templates/groups/group_view_group.rb +9 -0
  1130. data/lib/generators/lcp_ruby/templates/host_controller/controller.rb.erb +131 -0
  1131. data/lib/generators/lcp_ruby/templates/import/data_import_job.yml +7 -0
  1132. data/lib/generators/lcp_ruby/templates/import/import_profile_model.rb +30 -0
  1133. data/lib/generators/lcp_ruby/templates/import/import_profile_permissions.yml +29 -0
  1134. data/lib/generators/lcp_ruby/templates/import/import_profiles_presenter.rb +57 -0
  1135. data/lib/generators/lcp_ruby/templates/import/import_row_model.rb +32 -0
  1136. data/lib/generators/lcp_ruby/templates/import/import_row_permissions.yml +11 -0
  1137. data/lib/generators/lcp_ruby/templates/import/import_rows_presenter.rb +35 -0
  1138. data/lib/generators/lcp_ruby/templates/install/default_permissions.yml +26 -0
  1139. data/lib/generators/lcp_ruby/templates/install/menu.yml.tt +71 -0
  1140. data/lib/generators/lcp_ruby/templates/install/model.rb +20 -0
  1141. data/lib/generators/lcp_ruby/templates/install/permissions.yml +25 -0
  1142. data/lib/generators/lcp_ruby/templates/install/presenter.rb +44 -0
  1143. data/lib/generators/lcp_ruby/templates/install/view_group.rb +10 -0
  1144. data/lib/generators/lcp_ruby/templates/install_auth/oidc/entra.yml.erb +46 -0
  1145. data/lib/generators/lcp_ruby/templates/install_auth/oidc/generic.yml.erb +55 -0
  1146. data/lib/generators/lcp_ruby/templates/install_auth/oidc/google.yml.erb +42 -0
  1147. data/lib/generators/lcp_ruby/templates/install_auth/oidc/keycloak.yml.erb +45 -0
  1148. data/lib/generators/lcp_ruby/templates/install_auth/oidc/okta.yml.erb +45 -0
  1149. data/lib/generators/lcp_ruby/templates/install_auth/user.rb +36 -0
  1150. data/lib/generators/lcp_ruby/templates/monitoring/model.rb +34 -0
  1151. data/lib/generators/lcp_ruby/templates/monitoring/model_extension.rb +12 -0
  1152. data/lib/generators/lcp_ruby/templates/monitoring/page.yml +49 -0
  1153. data/lib/generators/lcp_ruby/templates/monitoring/permissions.yml +8 -0
  1154. data/lib/generators/lcp_ruby/templates/monitoring/presenter.rb +44 -0
  1155. data/lib/generators/lcp_ruby/templates/oidc_role_mappings/locales.en.yml +15 -0
  1156. data/lib/generators/lcp_ruby/templates/oidc_role_mappings/model.rb +32 -0
  1157. data/lib/generators/lcp_ruby/templates/oidc_role_mappings/permissions.yml +21 -0
  1158. data/lib/generators/lcp_ruby/templates/oidc_role_mappings/presenter.rb +41 -0
  1159. data/lib/generators/lcp_ruby/templates/pages/model.rb +19 -0
  1160. data/lib/generators/lcp_ruby/templates/pages/permissions.yml +19 -0
  1161. data/lib/generators/lcp_ruby/templates/pages/presenter.rb +51 -0
  1162. data/lib/generators/lcp_ruby/templates/pages/view_group.rb +10 -0
  1163. data/lib/generators/lcp_ruby/templates/permission_source/model.rb +21 -0
  1164. data/lib/generators/lcp_ruby/templates/permission_source/permissions.yml +19 -0
  1165. data/lib/generators/lcp_ruby/templates/permission_source/presenter.rb +51 -0
  1166. data/lib/generators/lcp_ruby/templates/permission_source/view_group.rb +10 -0
  1167. data/lib/generators/lcp_ruby/templates/role_model/model.rb +24 -0
  1168. data/lib/generators/lcp_ruby/templates/role_model/permissions.yml +19 -0
  1169. data/lib/generators/lcp_ruby/templates/role_model/presenter.rb +62 -0
  1170. data/lib/generators/lcp_ruby/templates/role_model/view_group.rb +10 -0
  1171. data/lib/generators/lcp_ruby/templates/saved_filters/model.rb +51 -0
  1172. data/lib/generators/lcp_ruby/templates/saved_filters/permissions.yml +44 -0
  1173. data/lib/generators/lcp_ruby/templates/saved_filters/presenter.rb +96 -0
  1174. data/lib/generators/lcp_ruby/templates/saved_filters/save_dialog_presenter.rb +19 -0
  1175. data/lib/generators/lcp_ruby/templates/workflow_approvals/request_model.rb +50 -0
  1176. data/lib/generators/lcp_ruby/templates/workflow_approvals/request_permissions.yml +10 -0
  1177. data/lib/generators/lcp_ruby/templates/workflow_approvals/request_presenter.rb +44 -0
  1178. data/lib/generators/lcp_ruby/templates/workflow_approvals/request_view_group.rb +10 -0
  1179. data/lib/generators/lcp_ruby/templates/workflow_approvals/step_model.rb +36 -0
  1180. data/lib/generators/lcp_ruby/templates/workflow_approvals/step_permissions.yml +10 -0
  1181. data/lib/generators/lcp_ruby/templates/workflow_approvals/task_model.rb +34 -0
  1182. data/lib/generators/lcp_ruby/templates/workflow_approvals/task_permissions.yml +10 -0
  1183. data/lib/generators/lcp_ruby/templates/workflow_approvals/task_presenter.rb +39 -0
  1184. data/lib/generators/lcp_ruby/templates/workflow_approvals/task_view_group.rb +10 -0
  1185. data/lib/generators/lcp_ruby/templates/workflow_audit_log/model.rb +48 -0
  1186. data/lib/generators/lcp_ruby/templates/workflow_audit_log/permissions.yml +10 -0
  1187. data/lib/generators/lcp_ruby/templates/workflow_audit_log/presenter.rb +44 -0
  1188. data/lib/generators/lcp_ruby/templates/workflow_audit_log/view_group.rb +10 -0
  1189. data/lib/generators/lcp_ruby/templates/workflow_definition/model.rb +43 -0
  1190. data/lib/generators/lcp_ruby/templates/workflow_definition/permissions.yml +19 -0
  1191. data/lib/generators/lcp_ruby/templates/workflow_definition/presenter.rb +70 -0
  1192. data/lib/generators/lcp_ruby/templates/workflow_definition/view_group.rb +10 -0
  1193. data/lib/generators/lcp_ruby/workflow_approvals_generator.rb +93 -0
  1194. data/lib/generators/lcp_ruby/workflow_audit_log_generator.rb +54 -0
  1195. data/lib/generators/lcp_ruby/workflow_definition_generator.rb +77 -0
  1196. data/lib/lcp.rb +6 -0
  1197. data/lib/lcp_ruby/actions/action_executor.rb +66 -0
  1198. data/lib/lcp_ruby/actions/action_registry.rb +48 -0
  1199. data/lib/lcp_ruby/actions/api_tokens/revoke.rb +13 -0
  1200. data/lib/lcp_ruby/actions/base_action.rb +79 -0
  1201. data/lib/lcp_ruby/actions/form_action_pipeline.rb +138 -0
  1202. data/lib/lcp_ruby/aggregates/query_builder.rb +6 -0
  1203. data/lib/lcp_ruby/api_tokens/model_extension.rb +41 -0
  1204. data/lib/lcp_ruby/api_tokens/resolver_registry.rb +53 -0
  1205. data/lib/lcp_ruby/api_tokens/token_generator.rb +27 -0
  1206. data/lib/lcp_ruby/api_tokens/verifier.rb +38 -0
  1207. data/lib/lcp_ruby/app_template.rb +181 -0
  1208. data/lib/lcp_ruby/array_query.rb +120 -0
  1209. data/lib/lcp_ruby/asset_copier.rb +62 -0
  1210. data/lib/lcp_ruby/association_fk_type.rb +191 -0
  1211. data/lib/lcp_ruby/association_join_column.rb +28 -0
  1212. data/lib/lcp_ruby/association_options_builder.rb +231 -0
  1213. data/lib/lcp_ruby/auditing/audit_writer.rb +258 -0
  1214. data/lib/lcp_ruby/auditing/contract_validator.rb +95 -0
  1215. data/lib/lcp_ruby/auditing/registry.rb +29 -0
  1216. data/lib/lcp_ruby/auditing/setup.rb +49 -0
  1217. data/lib/lcp_ruby/authentication/audit_subscriber.rb +51 -0
  1218. data/lib/lcp_ruby/authentication/bearer_jwt_verifier.rb +139 -0
  1219. data/lib/lcp_ruby/authentication/devise_setup.rb +47 -0
  1220. data/lib/lcp_ruby/authentication/errors.rb +27 -0
  1221. data/lib/lcp_ruby/authentication/http_fetcher.rb +36 -0
  1222. data/lib/lcp_ruby/authentication/jwks_cache.rb +91 -0
  1223. data/lib/lcp_ruby/authentication/oidc_bearer_resolver.rb +84 -0
  1224. data/lib/lcp_ruby/authentication/omniauth_builder.rb +147 -0
  1225. data/lib/lcp_ruby/authentication/provider.rb +108 -0
  1226. data/lib/lcp_ruby/authentication/provider_registry.rb +227 -0
  1227. data/lib/lcp_ruby/authentication/role_mapper.rb +94 -0
  1228. data/lib/lcp_ruby/authentication/test_support.rb +257 -0
  1229. data/lib/lcp_ruby/authentication/user_resolver.rb +169 -0
  1230. data/lib/lcp_ruby/authentication.rb +40 -0
  1231. data/lib/lcp_ruby/authorization/association_lookup.rb +56 -0
  1232. data/lib/lcp_ruby/authorization/authorization_error.rb +12 -0
  1233. data/lib/lcp_ruby/authorization/cache.rb +89 -0
  1234. data/lib/lcp_ruby/authorization/codes.rb +17 -0
  1235. data/lib/lcp_ruby/authorization/impersonated_user.rb +29 -0
  1236. data/lib/lcp_ruby/authorization/includes_hint.rb +110 -0
  1237. data/lib/lcp_ruby/authorization/inherited_parent_validator.rb +142 -0
  1238. data/lib/lcp_ruby/authorization/invariant_check/configuration.rb +132 -0
  1239. data/lib/lcp_ruby/authorization/invariant_error.rb +15 -0
  1240. data/lib/lcp_ruby/authorization/misconfigured_page_error.rb +30 -0
  1241. data/lib/lcp_ruby/authorization/page_gate.rb +57 -0
  1242. data/lib/lcp_ruby/authorization/permission_evaluator.rb +343 -0
  1243. data/lib/lcp_ruby/authorization/policy_factory.rb +91 -0
  1244. data/lib/lcp_ruby/authorization/runtime_invariant_validator.rb +421 -0
  1245. data/lib/lcp_ruby/authorization/scope_builder.rb +227 -0
  1246. data/lib/lcp_ruby/authorization/scope_resolver.rb +28 -0
  1247. data/lib/lcp_ruby/authorized_controller.rb +44 -0
  1248. data/lib/lcp_ruby/background_jobs/base_handler.rb +113 -0
  1249. data/lib/lcp_ruby/background_jobs/change_handler.rb +17 -0
  1250. data/lib/lcp_ruby/background_jobs/contract.rb +16 -0
  1251. data/lib/lcp_ruby/background_jobs/contract_validator.rb +112 -0
  1252. data/lib/lcp_ruby/background_jobs/declarative/base_action.rb +11 -0
  1253. data/lib/lcp_ruby/background_jobs/declarative/call_webhook_action.rb +174 -0
  1254. data/lib/lcp_ruby/background_jobs/declarative/fire_event_action.rb +24 -0
  1255. data/lib/lcp_ruby/background_jobs/declarative/registry.rb +34 -0
  1256. data/lib/lcp_ruby/background_jobs/declarative/run_scope_action.rb +98 -0
  1257. data/lib/lcp_ruby/background_jobs/declarative/send_notification_action.rb +13 -0
  1258. data/lib/lcp_ruby/background_jobs/definition.rb +134 -0
  1259. data/lib/lcp_ruby/background_jobs/enqueue.rb +83 -0
  1260. data/lib/lcp_ruby/background_jobs/errors.rb +9 -0
  1261. data/lib/lcp_ruby/background_jobs/executor_job.rb +111 -0
  1262. data/lib/lcp_ruby/background_jobs/handler_factory.rb +46 -0
  1263. data/lib/lcp_ruby/background_jobs/host_source.rb +33 -0
  1264. data/lib/lcp_ruby/background_jobs/model_source.rb +93 -0
  1265. data/lib/lcp_ruby/background_jobs/registry.rb +81 -0
  1266. data/lib/lcp_ruby/background_jobs/resolver.rb +29 -0
  1267. data/lib/lcp_ruby/background_jobs/schedule_adapter.rb +14 -0
  1268. data/lib/lcp_ruby/background_jobs/setup.rb +145 -0
  1269. data/lib/lcp_ruby/background_jobs/static_source.rb +19 -0
  1270. data/lib/lcp_ruby/background_jobs/steps_executor.rb +52 -0
  1271. data/lib/lcp_ruby/background_jobs/triggers/event_trigger.rb +97 -0
  1272. data/lib/lcp_ruby/background_jobs/triggers/trigger_installer.rb +20 -0
  1273. data/lib/lcp_ruby/background_jobs/unique_key_builder.rb +31 -0
  1274. data/lib/lcp_ruby/batch_actions/base_service.rb +70 -0
  1275. data/lib/lcp_ruby/batch_actions/batch_action_handler.rb +200 -0
  1276. data/lib/lcp_ruby/batch_actions/custom_action_dispatcher.rb +133 -0
  1277. data/lib/lcp_ruby/batch_actions/destroy_service.rb +37 -0
  1278. data/lib/lcp_ruby/batch_actions/permanently_destroy_service.rb +33 -0
  1279. data/lib/lcp_ruby/batch_actions/restore_service.rb +33 -0
  1280. data/lib/lcp_ruby/batch_actions.rb +5 -0
  1281. data/lib/lcp_ruby/bulk_updater.rb +25 -0
  1282. data/lib/lcp_ruby/cli/docs_command.rb +29 -0
  1283. data/lib/lcp_ruby/cli/examples_command.rb +29 -0
  1284. data/lib/lcp_ruby/cli/new_command.rb +509 -0
  1285. data/lib/lcp_ruby/cli/run_command.rb +155 -0
  1286. data/lib/lcp_ruby/cli/skills_command.rb +54 -0
  1287. data/lib/lcp_ruby/cli.rb +74 -0
  1288. data/lib/lcp_ruby/condition_evaluator.rb +366 -0
  1289. data/lib/lcp_ruby/condition_service_registry.rb +58 -0
  1290. data/lib/lcp_ruby/condition_services/current_user_role.rb +28 -0
  1291. data/lib/lcp_ruby/condition_services/feature_flag.rb +63 -0
  1292. data/lib/lcp_ruby/condition_services/impersonating.rb +24 -0
  1293. data/lib/lcp_ruby/conditions/validator.rb +35 -0
  1294. data/lib/lcp_ruby/configuration.rb +431 -0
  1295. data/lib/lcp_ruby/controller/authentication.rb +118 -0
  1296. data/lib/lcp_ruby/controller/authorization.rb +198 -0
  1297. data/lib/lcp_ruby/controller/bearer_authentication.rb +76 -0
  1298. data/lib/lcp_ruby/controller/crud_helpers.rb +233 -0
  1299. data/lib/lcp_ruby/controller/error_handling.rb +94 -0
  1300. data/lib/lcp_ruby/controller/impersonation.rb +70 -0
  1301. data/lib/lcp_ruby/controller/locale_binding.rb +62 -0
  1302. data/lib/lcp_ruby/controller/path_helpers.rb +125 -0
  1303. data/lib/lcp_ruby/controller/presenter_setup.rb +89 -0
  1304. data/lib/lcp_ruby/controller/search.rb +321 -0
  1305. data/lib/lcp_ruby/controller/view_helpers.rb +105 -0
  1306. data/lib/lcp_ruby/current.rb +13 -0
  1307. data/lib/lcp_ruby/custom_fields/applicator.rb +194 -0
  1308. data/lib/lcp_ruby/custom_fields/contract_validator.rb +77 -0
  1309. data/lib/lcp_ruby/custom_fields/definition_change_handler.rb +21 -0
  1310. data/lib/lcp_ruby/custom_fields/query.rb +112 -0
  1311. data/lib/lcp_ruby/custom_fields/registry.rb +70 -0
  1312. data/lib/lcp_ruby/custom_fields/setup.rb +58 -0
  1313. data/lib/lcp_ruby/custom_fields/utils.rb +40 -0
  1314. data/lib/lcp_ruby/custom_fields.rb +9 -0
  1315. data/lib/lcp_ruby/data_source/api_error_placeholder.rb +47 -0
  1316. data/lib/lcp_ruby/data_source/api_filter_translator.rb +72 -0
  1317. data/lib/lcp_ruby/data_source/api_model_concern.rb +131 -0
  1318. data/lib/lcp_ruby/data_source/api_preloader.rb +44 -0
  1319. data/lib/lcp_ruby/data_source/base.rb +85 -0
  1320. data/lib/lcp_ruby/data_source/cached_wrapper.rb +107 -0
  1321. data/lib/lcp_ruby/data_source/host.rb +71 -0
  1322. data/lib/lcp_ruby/data_source/registry.rb +39 -0
  1323. data/lib/lcp_ruby/data_source/resilient_wrapper.rb +67 -0
  1324. data/lib/lcp_ruby/data_source/rest_json.rb +247 -0
  1325. data/lib/lcp_ruby/data_source/setup.rb +57 -0
  1326. data/lib/lcp_ruby/dev_toolbar.rb +8 -0
  1327. data/lib/lcp_ruby/display/base_renderer.rb +21 -0
  1328. data/lib/lcp_ruby/display/count_badge.rb +11 -0
  1329. data/lib/lcp_ruby/display/icon_badge.rb +17 -0
  1330. data/lib/lcp_ruby/display/renderer_registry.rb +138 -0
  1331. data/lib/lcp_ruby/display/renderers/attachment_link.rb +26 -0
  1332. data/lib/lcp_ruby/display/renderers/attachment_list.rb +32 -0
  1333. data/lib/lcp_ruby/display/renderers/attachment_preview.rb +26 -0
  1334. data/lib/lcp_ruby/display/renderers/avatar.rb +14 -0
  1335. data/lib/lcp_ruby/display/renderers/badge.rb +43 -0
  1336. data/lib/lcp_ruby/display/renderers/boolean_icon.rb +54 -0
  1337. data/lib/lcp_ruby/display/renderers/code.rb +39 -0
  1338. data/lib/lcp_ruby/display/renderers/collection.rb +34 -0
  1339. data/lib/lcp_ruby/display/renderers/color_swatch.rb +25 -0
  1340. data/lib/lcp_ruby/display/renderers/concerns/attachment_helpers.rb +73 -0
  1341. data/lib/lcp_ruby/display/renderers/concerns/workflow_helpers.rb +35 -0
  1342. data/lib/lcp_ruby/display/renderers/copy_code.rb +33 -0
  1343. data/lib/lcp_ruby/display/renderers/currency.rb +14 -0
  1344. data/lib/lcp_ruby/display/renderers/date.rb +17 -0
  1345. data/lib/lcp_ruby/display/renderers/datetime.rb +17 -0
  1346. data/lib/lcp_ruby/display/renderers/email_link.rb +15 -0
  1347. data/lib/lcp_ruby/display/renderers/file_size.rb +11 -0
  1348. data/lib/lcp_ruby/display/renderers/heading.rb +11 -0
  1349. data/lib/lcp_ruby/display/renderers/image.rb +17 -0
  1350. data/lib/lcp_ruby/display/renderers/internal_link.rb +23 -0
  1351. data/lib/lcp_ruby/display/renderers/link.rb +15 -0
  1352. data/lib/lcp_ruby/display/renderers/link_list.rb +90 -0
  1353. data/lib/lcp_ruby/display/renderers/markdown.rb +33 -0
  1354. data/lib/lcp_ruby/display/renderers/number.rb +14 -0
  1355. data/lib/lcp_ruby/display/renderers/percentage.rb +12 -0
  1356. data/lib/lcp_ruby/display/renderers/phone_link.rb +15 -0
  1357. data/lib/lcp_ruby/display/renderers/progress_bar.rb +15 -0
  1358. data/lib/lcp_ruby/display/renderers/rating.rb +15 -0
  1359. data/lib/lcp_ruby/display/renderers/record_link.rb +101 -0
  1360. data/lib/lcp_ruby/display/renderers/relative_date.rb +15 -0
  1361. data/lib/lcp_ruby/display/renderers/rich_text.rb +15 -0
  1362. data/lib/lcp_ruby/display/renderers/text.rb +12 -0
  1363. data/lib/lcp_ruby/display/renderers/truncate.rb +17 -0
  1364. data/lib/lcp_ruby/display/renderers/url_link.rb +22 -0
  1365. data/lib/lcp_ruby/display/renderers/workflow_badge.rb +37 -0
  1366. data/lib/lcp_ruby/display/renderers/workflow_timeline.rb +173 -0
  1367. data/lib/lcp_ruby/display/renderers.rb +3 -0
  1368. data/lib/lcp_ruby/display/text_badge.rb +15 -0
  1369. data/lib/lcp_ruby/dsl/condition_builder.rb +190 -0
  1370. data/lib/lcp_ruby/dsl/dsl_loader.rb +365 -0
  1371. data/lib/lcp_ruby/dsl/field_builder.rb +35 -0
  1372. data/lib/lcp_ruby/dsl/job_builder.rb +92 -0
  1373. data/lib/lcp_ruby/dsl/model_builder.rb +544 -0
  1374. data/lib/lcp_ruby/dsl/presenter_builder.rb +1272 -0
  1375. data/lib/lcp_ruby/dsl/source_location_capture.rb +52 -0
  1376. data/lib/lcp_ruby/dsl/type_builder.rb +88 -0
  1377. data/lib/lcp_ruby/dsl/view_group_builder.rb +92 -0
  1378. data/lib/lcp_ruby/dsl/workflow_builder.rb +319 -0
  1379. data/lib/lcp_ruby/dynamic.rb +7 -0
  1380. data/lib/lcp_ruby/dynamic_references/resolver.rb +154 -0
  1381. data/lib/lcp_ruby/dynamic_references/validator.rb +92 -0
  1382. data/lib/lcp_ruby/embed_providers/base.rb +18 -0
  1383. data/lib/lcp_ruby/embed_providers/grafana.rb +38 -0
  1384. data/lib/lcp_ruby/embed_providers/metabase.rb +37 -0
  1385. data/lib/lcp_ruby/engine.rb +680 -0
  1386. data/lib/lcp_ruby/events/async_handler_job.rb +21 -0
  1387. data/lib/lcp_ruby/events/dispatcher.rb +52 -0
  1388. data/lib/lcp_ruby/events/handler_base.rb +51 -0
  1389. data/lib/lcp_ruby/events/handler_registry.rb +49 -0
  1390. data/lib/lcp_ruby/export/data_generator.rb +158 -0
  1391. data/lib/lcp_ruby/export/export_handler.rb +315 -0
  1392. data/lib/lcp_ruby/export/field_tree_builder.rb +219 -0
  1393. data/lib/lcp_ruby/export/setup.rb +94 -0
  1394. data/lib/lcp_ruby/export/value_formatter.rb +223 -0
  1395. data/lib/lcp_ruby/export.rb +9 -0
  1396. data/lib/lcp_ruby/gem_paths.rb +51 -0
  1397. data/lib/lcp_ruby/generators/entity_menu_writer.rb +258 -0
  1398. data/lib/lcp_ruby/generators/feature_registry.rb +208 -0
  1399. data/lib/lcp_ruby/generators/prerequisites.rb +90 -0
  1400. data/lib/lcp_ruby/grouped_query/builder.rb +206 -0
  1401. data/lib/lcp_ruby/grouped_query/result_wrapper.rb +72 -0
  1402. data/lib/lcp_ruby/grouped_query/row.rb +31 -0
  1403. data/lib/lcp_ruby/groups/change_handler.rb +18 -0
  1404. data/lib/lcp_ruby/groups/contract.rb +42 -0
  1405. data/lib/lcp_ruby/groups/contract_validator.rb +110 -0
  1406. data/lib/lcp_ruby/groups/host_loader.rb +54 -0
  1407. data/lib/lcp_ruby/groups/model_loader.rb +186 -0
  1408. data/lib/lcp_ruby/groups/registry.rb +113 -0
  1409. data/lib/lcp_ruby/groups/setup.rb +129 -0
  1410. data/lib/lcp_ruby/groups/yaml_loader.rb +97 -0
  1411. data/lib/lcp_ruby/hash_utils.rb +42 -0
  1412. data/lib/lcp_ruby/i18n_check/configuration.rb +104 -0
  1413. data/lib/lcp_ruby/i18n_check/heuristics.rb +26 -0
  1414. data/lib/lcp_ruby/i18n_check/key_deriver.rb +136 -0
  1415. data/lib/lcp_ruby/i18n_check/offense.rb +29 -0
  1416. data/lib/lcp_ruby/i18n_check/registry_walker.rb +621 -0
  1417. data/lib/lcp_ruby/i18n_check/reporter.rb +96 -0
  1418. data/lib/lcp_ruby/i18n_check/runner.rb +46 -0
  1419. data/lib/lcp_ruby/i18n_check.rb +15 -0
  1420. data/lib/lcp_ruby/i18n_lint.rb +145 -0
  1421. data/lib/lcp_ruby/import/auto_mapper.rb +98 -0
  1422. data/lib/lcp_ruby/import/field_tree_builder.rb +178 -0
  1423. data/lib/lcp_ruby/import/file_parser.rb +223 -0
  1424. data/lib/lcp_ruby/import/import_dialog_handler.rb +410 -0
  1425. data/lib/lcp_ruby/import/import_job_handler.rb +224 -0
  1426. data/lib/lcp_ruby/import/row_processor.rb +281 -0
  1427. data/lib/lcp_ruby/import/setup.rb +277 -0
  1428. data/lib/lcp_ruby/import/value_coercer.rb +143 -0
  1429. data/lib/lcp_ruby/import.rb +14 -0
  1430. data/lib/lcp_ruby/json_item_wrapper.rb +152 -0
  1431. data/lib/lcp_ruby/kanban/board.rb +28 -0
  1432. data/lib/lcp_ruby/kanban/column.rb +28 -0
  1433. data/lib/lcp_ruby/kanban/default_provider.rb +376 -0
  1434. data/lib/lcp_ruby/kanban/host_provider.rb +94 -0
  1435. data/lib/lcp_ruby/kanban/move_result.rb +52 -0
  1436. data/lib/lcp_ruby/kanban/provider_test_harness.rb +54 -0
  1437. data/lib/lcp_ruby/kanban/swimlane.rb +21 -0
  1438. data/lib/lcp_ruby/menu.rb +46 -0
  1439. data/lib/lcp_ruby/metadata/aggregate_definition.rb +6 -0
  1440. data/lib/lcp_ruby/metadata/association_definition.rb +196 -0
  1441. data/lib/lcp_ruby/metadata/auth_validator.rb +222 -0
  1442. data/lib/lcp_ruby/metadata/configuration_validator.rb +7958 -0
  1443. data/lib/lcp_ruby/metadata/contract_result.rb +9 -0
  1444. data/lib/lcp_ruby/metadata/display_template_definition.rb +77 -0
  1445. data/lib/lcp_ruby/metadata/enum_label_resolver.rb +27 -0
  1446. data/lib/lcp_ruby/metadata/erd_generator.rb +274 -0
  1447. data/lib/lcp_ruby/metadata/event_definition.rb +55 -0
  1448. data/lib/lcp_ruby/metadata/field_definition.rb +267 -0
  1449. data/lib/lcp_ruby/metadata/group_definition.rb +31 -0
  1450. data/lib/lcp_ruby/metadata/i18n_label.rb +29 -0
  1451. data/lib/lcp_ruby/metadata/loader.rb +916 -0
  1452. data/lib/lcp_ruby/metadata/menu_definition.rb +116 -0
  1453. data/lib/lcp_ruby/metadata/menu_item.rb +792 -0
  1454. data/lib/lcp_ruby/metadata/menu_item_resolver.rb +105 -0
  1455. data/lib/lcp_ruby/metadata/model_definition.rb +612 -0
  1456. data/lib/lcp_ruby/metadata/model_hash_merger.rb +88 -0
  1457. data/lib/lcp_ruby/metadata/model_inheritance_resolver.rb +165 -0
  1458. data/lib/lcp_ruby/metadata/page_definition.rb +245 -0
  1459. data/lib/lcp_ruby/metadata/path_template.rb +231 -0
  1460. data/lib/lcp_ruby/metadata/permission_definition.rb +237 -0
  1461. data/lib/lcp_ruby/metadata/permission_merger.rb +81 -0
  1462. data/lib/lcp_ruby/metadata/presenter_definition.rb +689 -0
  1463. data/lib/lcp_ruby/metadata/reserved_names.rb +79 -0
  1464. data/lib/lcp_ruby/metadata/responsive_policy.rb +95 -0
  1465. data/lib/lcp_ruby/metadata/schema_validator.rb +172 -0
  1466. data/lib/lcp_ruby/metadata/validation_definition.rb +69 -0
  1467. data/lib/lcp_ruby/metadata/view_group_definition.rb +208 -0
  1468. data/lib/lcp_ruby/metadata/virtual_column_definition.rb +154 -0
  1469. data/lib/lcp_ruby/metadata/zone_definition.rb +423 -0
  1470. data/lib/lcp_ruby/metrics/collector.rb +123 -0
  1471. data/lib/lcp_ruby/metrics/collector_registry.rb +57 -0
  1472. data/lib/lcp_ruby/metrics/error_recorder.rb +70 -0
  1473. data/lib/lcp_ruby/metrics/fingerprint.rb +33 -0
  1474. data/lib/lcp_ruby/metrics/json_query.rb +47 -0
  1475. data/lib/lcp_ruby/metrics/metric_definitions.rb +105 -0
  1476. data/lib/lcp_ruby/metrics/prometheus_check.rb +9 -0
  1477. data/lib/lcp_ruby/metrics/rate_limiter.rb +99 -0
  1478. data/lib/lcp_ruby/metrics/setup.rb +71 -0
  1479. data/lib/lcp_ruby/metrics/subscriber.rb +126 -0
  1480. data/lib/lcp_ruby/model_factory/aggregate_applicator.rb +14 -0
  1481. data/lib/lcp_ruby/model_factory/api_association_applicator.rb +119 -0
  1482. data/lib/lcp_ruby/model_factory/api_builder.rb +85 -0
  1483. data/lib/lcp_ruby/model_factory/array_type.rb +78 -0
  1484. data/lib/lcp_ruby/model_factory/array_type_applicator.rb +33 -0
  1485. data/lib/lcp_ruby/model_factory/association_applicator.rb +201 -0
  1486. data/lib/lcp_ruby/model_factory/attachment_applicator.rb +160 -0
  1487. data/lib/lcp_ruby/model_factory/auditing_applicator.rb +72 -0
  1488. data/lib/lcp_ruby/model_factory/builder.rb +235 -0
  1489. data/lib/lcp_ruby/model_factory/callback_applicator.rb +63 -0
  1490. data/lib/lcp_ruby/model_factory/computed_applicator.rb +55 -0
  1491. data/lib/lcp_ruby/model_factory/default_applicator.rb +85 -0
  1492. data/lib/lcp_ruby/model_factory/enum_applicator.rb +24 -0
  1493. data/lib/lcp_ruby/model_factory/inherited_parent_validator_applicator.rb +39 -0
  1494. data/lib/lcp_ruby/model_factory/label_method_builder.rb +82 -0
  1495. data/lib/lcp_ruby/model_factory/managed_tracking.rb +71 -0
  1496. data/lib/lcp_ruby/model_factory/positioning_applicator.rb +23 -0
  1497. data/lib/lcp_ruby/model_factory/ransack_applicator.rb +66 -0
  1498. data/lib/lcp_ruby/model_factory/registry.rb +33 -0
  1499. data/lib/lcp_ruby/model_factory/schema_manager.rb +655 -0
  1500. data/lib/lcp_ruby/model_factory/scope_applicator.rb +87 -0
  1501. data/lib/lcp_ruby/model_factory/sequence_applicator.rb +173 -0
  1502. data/lib/lcp_ruby/model_factory/service_accessor_applicator.rb +40 -0
  1503. data/lib/lcp_ruby/model_factory/soft_delete_applicator.rb +141 -0
  1504. data/lib/lcp_ruby/model_factory/transform_applicator.rb +51 -0
  1505. data/lib/lcp_ruby/model_factory/tree_applicator.rb +239 -0
  1506. data/lib/lcp_ruby/model_factory/userstamps_applicator.rb +73 -0
  1507. data/lib/lcp_ruby/model_factory/validation_applicator.rb +319 -0
  1508. data/lib/lcp_ruby/model_factory/virtual_column_applicator.rb +79 -0
  1509. data/lib/lcp_ruby/model_factory/workflow_applicator.rb +141 -0
  1510. data/lib/lcp_ruby/pages/change_handler.rb +15 -0
  1511. data/lib/lcp_ruby/pages/contract_validator.rb +74 -0
  1512. data/lib/lcp_ruby/pages/definition_validator.rb +42 -0
  1513. data/lib/lcp_ruby/pages/filter_form.rb +200 -0
  1514. data/lib/lcp_ruby/pages/filter_form_validator.rb +636 -0
  1515. data/lib/lcp_ruby/pages/registry.rb +133 -0
  1516. data/lib/lcp_ruby/pages/resolver.rb +32 -0
  1517. data/lib/lcp_ruby/pages/scope_context_resolver.rb +37 -0
  1518. data/lib/lcp_ruby/pages/scope_filter_set.rb +57 -0
  1519. data/lib/lcp_ruby/pages/setup.rb +46 -0
  1520. data/lib/lcp_ruby/path_utils.rb +12 -0
  1521. data/lib/lcp_ruby/permissions/change_handler.rb +22 -0
  1522. data/lib/lcp_ruby/permissions/contract_validator.rb +74 -0
  1523. data/lib/lcp_ruby/permissions/definition_validator.rb +119 -0
  1524. data/lib/lcp_ruby/permissions/registry.rb +135 -0
  1525. data/lib/lcp_ruby/permissions/setup.rb +51 -0
  1526. data/lib/lcp_ruby/permissions/source_resolver.rb +56 -0
  1527. data/lib/lcp_ruby/presenter/action_set.rb +236 -0
  1528. data/lib/lcp_ruby/presenter/breadcrumb_builder.rb +183 -0
  1529. data/lib/lcp_ruby/presenter/breadcrumb_path_helper.rb +17 -0
  1530. data/lib/lcp_ruby/presenter/column_set.rb +268 -0
  1531. data/lib/lcp_ruby/presenter/enrichment.rb +136 -0
  1532. data/lib/lcp_ruby/presenter/field_value_resolver.rb +237 -0
  1533. data/lib/lcp_ruby/presenter/includes_resolver/association_dependency.rb +59 -0
  1534. data/lib/lcp_ruby/presenter/includes_resolver/dependency_collector.rb +394 -0
  1535. data/lib/lcp_ruby/presenter/includes_resolver/loading_strategy.rb +70 -0
  1536. data/lib/lcp_ruby/presenter/includes_resolver/strategy_resolver.rb +123 -0
  1537. data/lib/lcp_ruby/presenter/includes_resolver.rb +42 -0
  1538. data/lib/lcp_ruby/presenter/layout_builder.rb +467 -0
  1539. data/lib/lcp_ruby/presenter/link_resolver.rb +65 -0
  1540. data/lib/lcp_ruby/presenter/metadata_lookup.rb +28 -0
  1541. data/lib/lcp_ruby/presenter/resolver.rb +25 -0
  1542. data/lib/lcp_ruby/record_aliases/metadata_checker.rb +213 -0
  1543. data/lib/lcp_ruby/record_aliases/setup.rb +212 -0
  1544. data/lib/lcp_ruby/reserved_route_segments.rb +37 -0
  1545. data/lib/lcp_ruby/roles/change_handler.rb +11 -0
  1546. data/lib/lcp_ruby/roles/contract_validator.rb +67 -0
  1547. data/lib/lcp_ruby/roles/registry.rb +89 -0
  1548. data/lib/lcp_ruby/roles/setup.rb +50 -0
  1549. data/lib/lcp_ruby/routing/presenter_routes.rb +104 -0
  1550. data/lib/lcp_ruby/saved_filters/change_handler.rb +13 -0
  1551. data/lib/lcp_ruby/saved_filters/contract_validator.rb +85 -0
  1552. data/lib/lcp_ruby/saved_filters/registry.rb +36 -0
  1553. data/lib/lcp_ruby/saved_filters/resolver.rb +108 -0
  1554. data/lib/lcp_ruby/saved_filters/setup.rb +42 -0
  1555. data/lib/lcp_ruby/saved_filters/stale_field_validator.rb +84 -0
  1556. data/lib/lcp_ruby/schemas/auth.json +208 -0
  1557. data/lib/lcp_ruby/schemas/menu.json +338 -0
  1558. data/lib/lcp_ruby/schemas/model.json +1161 -0
  1559. data/lib/lcp_ruby/schemas/page.json +877 -0
  1560. data/lib/lcp_ruby/schemas/permission.json +454 -0
  1561. data/lib/lcp_ruby/schemas/presenter.json +2274 -0
  1562. data/lib/lcp_ruby/schemas/theme.json +62 -0
  1563. data/lib/lcp_ruby/schemas/type.json +146 -0
  1564. data/lib/lcp_ruby/schemas/view_group.json +163 -0
  1565. data/lib/lcp_ruby/search/custom_field_filter.rb +171 -0
  1566. data/lib/lcp_ruby/search/custom_filter_interceptor.rb +40 -0
  1567. data/lib/lcp_ruby/search/filter_metadata_builder.rb +409 -0
  1568. data/lib/lcp_ruby/search/filter_param_builder.rb +177 -0
  1569. data/lib/lcp_ruby/search/operator_registry.rb +79 -0
  1570. data/lib/lcp_ruby/search/param_sanitizer.rb +25 -0
  1571. data/lib/lcp_ruby/search/parameter_definition.rb +187 -0
  1572. data/lib/lcp_ruby/search/parameterized_scope_applicator.rb +129 -0
  1573. data/lib/lcp_ruby/search/query_builder.rb +143 -0
  1574. data/lib/lcp_ruby/search/query_language_parser.rb +549 -0
  1575. data/lib/lcp_ruby/search/query_language_serializer.rb +193 -0
  1576. data/lib/lcp_ruby/search/quick_search.rb +162 -0
  1577. data/lib/lcp_ruby/search/relative_date_expander.rb +57 -0
  1578. data/lib/lcp_ruby/search_result.rb +70 -0
  1579. data/lib/lcp_ruby/sequences/sequence_manager.rb +51 -0
  1580. data/lib/lcp_ruby/services/accessors/json_field.rb +23 -0
  1581. data/lib/lcp_ruby/services/built_in_accessors.rb +17 -0
  1582. data/lib/lcp_ruby/services/built_in_defaults.rb +22 -0
  1583. data/lib/lcp_ruby/services/built_in_transforms.rb +20 -0
  1584. data/lib/lcp_ruby/services/checker.rb +133 -0
  1585. data/lib/lcp_ruby/services/registry.rb +83 -0
  1586. data/lib/lcp_ruby/skills_installer.rb +73 -0
  1587. data/lib/lcp_ruby/sort/enum_sort_order.rb +38 -0
  1588. data/lib/lcp_ruby/tasks/destroy_order_resolver.rb +57 -0
  1589. data/lib/lcp_ruby/tasks/doctor.rb +294 -0
  1590. data/lib/lcp_ruby/tasks/permission_resolve_formatter.rb +245 -0
  1591. data/lib/lcp_ruby/types/built_in_types.rb +157 -0
  1592. data/lib/lcp_ruby/types/transforms/base_transform.rb +11 -0
  1593. data/lib/lcp_ruby/types/transforms/downcase.rb +11 -0
  1594. data/lib/lcp_ruby/types/transforms/normalize_phone.rb +19 -0
  1595. data/lib/lcp_ruby/types/transforms/normalize_url.rb +16 -0
  1596. data/lib/lcp_ruby/types/transforms/strip.rb +11 -0
  1597. data/lib/lcp_ruby/types/type_definition.rb +112 -0
  1598. data/lib/lcp_ruby/types/type_registry.rb +75 -0
  1599. data/lib/lcp_ruby/url_safety.rb +97 -0
  1600. data/lib/lcp_ruby/user_snapshot.rb +15 -0
  1601. data/lib/lcp_ruby/version.rb +3 -0
  1602. data/lib/lcp_ruby/view_slots/registry.rb +71 -0
  1603. data/lib/lcp_ruby/view_slots/slot_component.rb +22 -0
  1604. data/lib/lcp_ruby/view_slots/slot_context.rb +20 -0
  1605. data/lib/lcp_ruby/virtual_columns/builder.rb +234 -0
  1606. data/lib/lcp_ruby/virtual_columns/collector.rb +186 -0
  1607. data/lib/lcp_ruby/virtual_columns.rb +4 -0
  1608. data/lib/lcp_ruby/virtual_fields/synthetic_marker.rb +17 -0
  1609. data/lib/lcp_ruby/virtual_fields/types/array_of.rb +49 -0
  1610. data/lib/lcp_ruby/virtual_fields/virtual_field.rb +107 -0
  1611. data/lib/lcp_ruby/virtual_fields/virtual_form.rb +144 -0
  1612. data/lib/lcp_ruby/widgets/chart_palette.rb +25 -0
  1613. data/lib/lcp_ruby/widgets/chartkick_check.rb +9 -0
  1614. data/lib/lcp_ruby/widgets/data_resolver.rb +676 -0
  1615. data/lib/lcp_ruby/widgets/date_grouper.rb +54 -0
  1616. data/lib/lcp_ruby/widgets/presenter_zone_resolver.rb +170 -0
  1617. data/lib/lcp_ruby/widgets/record_source_resolver.rb +56 -0
  1618. data/lib/lcp_ruby/widgets/scope_applicator.rb +187 -0
  1619. data/lib/lcp_ruby/workflow/approval/activation_handler.rb +39 -0
  1620. data/lib/lcp_ruby/workflow/approval/approval_definition.rb +117 -0
  1621. data/lib/lcp_ruby/workflow/approval/approver_resolver.rb +98 -0
  1622. data/lib/lcp_ruby/workflow/approval/cleanup_handler.rb +37 -0
  1623. data/lib/lcp_ruby/workflow/approval/contract_validator.rb +96 -0
  1624. data/lib/lcp_ruby/workflow/approval/data_builder.rb +53 -0
  1625. data/lib/lcp_ruby/workflow/approval/discard_handler.rb +51 -0
  1626. data/lib/lcp_ruby/workflow/approval/engine.rb +314 -0
  1627. data/lib/lcp_ruby/workflow/approval/registry.rb +40 -0
  1628. data/lib/lcp_ruby/workflow/approval/resolution_handler.rb +103 -0
  1629. data/lib/lcp_ruby/workflow/approval/setup.rb +138 -0
  1630. data/lib/lcp_ruby/workflow/approval/step_definition.rb +52 -0
  1631. data/lib/lcp_ruby/workflow/approval/step_evaluator.rb +163 -0
  1632. data/lib/lcp_ruby/workflow/approval/system_evaluator.rb +29 -0
  1633. data/lib/lcp_ruby/workflow/approval/task_manager.rb +202 -0
  1634. data/lib/lcp_ruby/workflow/audit_contract_validator.rb +64 -0
  1635. data/lib/lcp_ruby/workflow/audit_registry.rb +24 -0
  1636. data/lib/lcp_ruby/workflow/audit_writer.rb +51 -0
  1637. data/lib/lcp_ruby/workflow/change_handler.rb +14 -0
  1638. data/lib/lcp_ruby/workflow/contract.rb +21 -0
  1639. data/lib/lcp_ruby/workflow/contract_validator.rb +44 -0
  1640. data/lib/lcp_ruby/workflow/errors.rb +12 -0
  1641. data/lib/lcp_ruby/workflow/host_source.rb +19 -0
  1642. data/lib/lcp_ruby/workflow/mermaid_builder.rb +217 -0
  1643. data/lib/lcp_ruby/workflow/model_source.rb +79 -0
  1644. data/lib/lcp_ruby/workflow/registry.rb +113 -0
  1645. data/lib/lcp_ruby/workflow/resolver.rb +32 -0
  1646. data/lib/lcp_ruby/workflow/setup.rb +135 -0
  1647. data/lib/lcp_ruby/workflow/state_definition.rb +59 -0
  1648. data/lib/lcp_ruby/workflow/state_machine.rb +78 -0
  1649. data/lib/lcp_ruby/workflow/static_source.rb +20 -0
  1650. data/lib/lcp_ruby/workflow/transition_action_builder.rb +46 -0
  1651. data/lib/lcp_ruby/workflow/transition_definition.rb +70 -0
  1652. data/lib/lcp_ruby/workflow/transition_executor.rb +140 -0
  1653. data/lib/lcp_ruby/workflow/transition_label_resolver.rb +21 -0
  1654. data/lib/lcp_ruby/workflow/transition_result.rb +20 -0
  1655. data/lib/lcp_ruby/workflow/value_resolver.rb +58 -0
  1656. data/lib/lcp_ruby/workflow/workflow_definition.rb +195 -0
  1657. data/lib/lcp_ruby.rb +764 -0
  1658. data/lib/rubocop/cop/lcp_ruby/no_hardcoded_i18n_string.rb +249 -0
  1659. data/lib/tasks/lcp_ruby.rake +432 -0
  1660. data/lib/tasks/lcp_ruby_assets.rake +37 -0
  1661. data/lib/tasks/lcp_ruby_auth.rake +49 -0
  1662. data/lib/tasks/lcp_ruby_db.rake +76 -0
  1663. data/lib/tasks/lcp_ruby_doctor.rake +20 -0
  1664. data/lib/tasks/lcp_ruby_feature_catalog.rake +61 -0
  1665. data/lib/tasks/lcp_ruby_gapfree_sequences.rake +39 -0
  1666. data/lib/tasks/lcp_ruby_i18n_check.rake +23 -0
  1667. data/lib/tasks/lcp_ruby_i18n_lint.rake +20 -0
  1668. data/lib/tasks/lcp_ruby_invariant_check.rake +72 -0
  1669. data/vendor/assets/javascripts/lcp_ruby/activestorage.min.js +866 -0
  1670. data/vendor/assets/javascripts/lcp_ruby/highlight.min.js +1244 -0
  1671. data/vendor/assets/javascripts/lcp_ruby/lucide.min.js +12 -0
  1672. data/vendor/assets/javascripts/lcp_ruby/stimulus.umd.js +2588 -0
  1673. data/vendor/assets/javascripts/lcp_ruby/tom-select.complete.min.js +444 -0
  1674. data/vendor/assets/stylesheets/lcp_ruby/highlight-github.min.css +12 -0
  1675. data/vendor/assets/stylesheets/lcp_ruby/tom-select.css +412 -0
  1676. metadata +1950 -0
@@ -0,0 +1,763 @@
1
+ # Feature Catalog
2
+
3
+ Auto-generated from `docs/feature-catalog.yml`. Do not edit manually.
4
+ Regenerate: `cd examples/showcase && bundle exec rake lcp_ruby:feature_catalog`
5
+
6
+ 621 features across 45 categories.
7
+
8
+ ## API Backed Models
9
+
10
+ - **API-Backed Model (Host Provider)** — Host-provided data source (data_source type: :host, provider:). ActiveModel class, read-only. models/*.yml. _(beta)_ · `docs/reference/api-backed-models.md#data_sourceprovider` `docs/guides/api-backed-models.md#host-provided-data-source` `docs/design/api_backed_models.md#host-provided-data-source` `lib/lcp_ruby/data_source/host.rb` `lib/lcp_ruby/data_source/registry.rb`
11
+ - **API-Backed Model (REST JSON)** — External REST API data source (data_source: type: rest_json). base_url:, auth:, pagination:, cache: in model YAML. _(beta)_ · `docs/reference/api-backed-models.md#data_sourcetype` `docs/guides/api-backed-models.md#quick-start-rest-json-adapter` `docs/design/api_backed_models.md#rest-json-adapter-configuration` `lib/lcp_ruby/data_source/rest_json.rb` `lib/lcp_ruby/data_source/base.rb`
12
+ - **Caching & Resilience** — API cache wrapper (cache: ttl:, list_ttl:, stale_on_error:). Serves stale on failure. ApiErrorPlaceholder fallback. _(beta)_ · `docs/reference/api-backed-models.md#data_sourcecache` `docs/guides/api-backed-models.md#caching` `docs/design/api_backed_models.md#design` `lib/lcp_ruby/data_source/cached_wrapper.rb` `lib/lcp_ruby/data_source/resilient_wrapper.rb` `lib/lcp_ruby/data_source/api_error_placeholder.rb`
13
+ - **Cross-Source Associations** — DB-to-API associations (belongs_to/has_many). Lazy accessors with batch preloading. Detected at boot. _(beta)_ · `docs/reference/api-backed-models.md#cross-source-associations` `docs/guides/api-backed-models.md#cross-source-associations` `docs/design/api_backed_models.md#cross-source-associations` `lib/lcp_ruby/data_source/api_preloader.rb` `lib/lcp_ruby/data_source/api_model_concern.rb`
14
+
15
+ ## Association Primary Key
16
+
17
+ - **Boot-time validation: column exists** — Validate primary_key: column exists on target model. ConfigurationValidator check at boot. · `docs/reference/models.md` `docs/design/association_primary_key.md#validation-rules-boot-time` `lib/lcp_ruby/metadata/configuration_validator.rb`
18
+ - **Boot-time validation: missing-index warning** — Warning if explicit FK field has no indexes: entry. Auto-index only runs for auto-created FKs. · `docs/reference/models.md` `docs/design/association_primary_key.md#missing-index-warning-on-the-join-column` `lib/lcp_ruby/metadata/configuration_validator.rb`
19
+ - **Boot-time validation: reciprocity alignment** — Check forward/inverse declare same join pair. Disambiguate via inverse_of: or foreign_key match. · `docs/reference/models.md` `docs/design/association_primary_key.md#5b-reciprocity-check-extend-to-cover-fkpk-pair-alignment` `lib/lcp_ruby/metadata/configuration_validator.rb`
20
+ - **Boot-time validation: type-compat warning** — Warning if FK and join column types differ. Covers auto-managed FK case via AssociationFkType. · `docs/reference/models.md` `docs/design/association_primary_key.md#fk-column-creation` `lib/lcp_ruby/metadata/configuration_validator.rb` `lib/lcp_ruby/model_factory/schema_manager.rb`
21
+ - **Boot-time validation: uniqueness (tri-state)** — Warning if join column lacks uniqueness constraint. Tri-state: :unique/:scoped/:not_unique. · `docs/reference/models.md` `docs/design/association_primary_key.md#helper-tri-state-uniqueness-check-for-a-column-on-a-model-definition` `lib/lcp_ruby/metadata/configuration_validator.rb`
22
+ - **FK column type follows referenced column** — Auto-created FK type matches referenced column (string vema_code -> string FK). Not default bigint. · `docs/reference/models.md` `docs/design/association_primary_key.md#fk-column-creation` `lib/lcp_ruby/model_factory/schema_manager.rb` `lib/lcp_ruby/association_fk_type.rb`
23
+ - **Form select posts business key (not id)** — Select options use join column value (e.g. `D-ENG`). AssociationJoinColumn.for(assoc) resolution. · `docs/reference/models.md` `docs/design/association_primary_key.md#7a-liblcp_rubyassociation_options_builderrb-emit-join-column-values-not-id` `lib/lcp_ruby/association_options_builder.rb` `app/helpers/lcp_ruby/form_helper.rb`
24
+ - **Importer write-back via the join column** — Import always writes join column value to FK. Lookup by any attribute resolves to business key. · `docs/reference/models.md` `docs/design/association_primary_key.md#8-liblcp_rubyimportrow_processorrb-fk-write-back-via-the-associations-join-column` `lib/lcp_ruby/import/row_processor.rb`
25
+ - **Inverse has_many with primary_key:** — Reverse side of custom-key belongs_to. Both sides declare same join pair. Reciprocity validation. · `docs/reference/models.md` `docs/design/association_primary_key.md#scenario-2-inverse-has_many-with-custom-join-keys` `lib/lcp_ruby/model_factory/association_applicator.rb`
26
+ - **Rejected: through:, polymorphic, tree, cross-source** — MetadataError for primary_key: + through:/polymorphic:. Validator error for tree/cross-source. · `docs/reference/models.md` `docs/design/association_primary_key.md#scenario-5-rejected-primary_key-on-through-association-itself` `docs/design/association_primary_key.md#interaction-with-polymorphic` `docs/design/association_primary_key.md#interaction-with-tree` `lib/lcp_ruby/metadata/configuration_validator.rb`
27
+ - **Virtual columns join via primary_key** — Virtual column subqueries use primary_key: for WHERE clause. Not hardcoded to id. · `docs/reference/models.md` `docs/design/association_primary_key.md#9-liblcp_rubyvirtual_columnsbuilderrb-use-the-associations-primary_key-in-joingroup-by` `lib/lcp_ruby/virtual_columns/`
28
+ - **bind_to: model + primary_key:** — primary_key: allowed on bind_to target associations. YAML is join-column source. Host owns AR macro. · `docs/reference/models.md` `docs/design/association_primary_key.md#interaction-with-bind_to` `lib/lcp_ruby/model_factory/association_applicator.rb`
29
+ - **has_one :through over a custom-key belongs_to** — Transparent through: composition over custom-key links. No primary_key: on through: itself. · `docs/reference/models.md` `docs/design/association_primary_key.md#scenario-3-has_one-through-over-a-custom-key-association` `lib/lcp_ruby/model_factory/association_applicator.rb`
30
+ - **primary_key: on belongs_to** — Join on business key (primary_key: :vema_code). FK matches target column instead of id. No shadow _id. · `docs/reference/models.md` `docs/design/association_primary_key.md#yaml-syntax` `docs/design/association_primary_key.md#configuration-behavior` `lib/lcp_ruby/metadata/association_definition.rb` `lib/lcp_ruby/model_factory/association_applicator.rb`
31
+
32
+ ## Attachments
33
+
34
+ - **Image Variants** — Active Storage image processing. variants: block with resize_to_limit. models/*.yml attachment:. · `docs/guides/attachments.md#image-variants` `docs/guides/attachments.md#display-configuration` `lib/lcp_ruby/model_factory/attachment_applicator.rb` `lib/lcp_ruby/display/renderers/attachment_preview.rb`
35
+ - **Multiple File Upload** — Multi-file upload (mode: multiple). max_files:, max_size:, content_types:. models/*.yml attachment:. · `docs/guides/attachments.md#multiple-attachments` `docs/guides/attachments.md#complete-model-example` `lib/lcp_ruby/model_factory/attachment_applicator.rb`
36
+ - **Single File Upload** — One file via Active Storage (type: attachment, mode: single). max_size:. models/*.yml attachment: block. · `docs/guides/attachments.md#single-attachment` `docs/guides/attachments.md#defining-attachment-fields` `lib/lcp_ruby/model_factory/attachment_applicator.rb`
37
+ - **Upload Validations** — File validation: max_size:, content_types:, max_files:. Inline error messages. attachment: block. · `docs/guides/attachments.md#validation-options` `lib/lcp_ruby/model_factory/attachment_applicator.rb`
38
+
39
+ ## Auditing
40
+
41
+ - **Audit History Section** — Show page audit timeline (audit_history section). Field diffs, user info, timestamps. Presenter config. · `docs/reference/auditing.md#show-page-section` `docs/guides/auditing.md#show-page-integration` `docs/design/auditing.md#presenter-integration` `lib/lcp_ruby/auditing/`
42
+ - **Audit Log Model** — Dedicated audit log model. Fields: auditable_type/id, action, changes_data (JSON), user_snapshot. · `docs/reference/auditing.md#audit-log-model-contract` `docs/guides/auditing.md#querying-audit-logs` `docs/design/auditing.md#audit-log-table` `docs/design/auditing.md#1-lcprubyauditlog-internal-model` `lib/lcp_ruby/auditing/`
43
+ - **Model Auditing** — Field-level change tracking (options: { auditing: true }). Create/update/destroy events with diffs. · `docs/reference/auditing.md#model-option` `docs/guides/auditing.md#basic-setup` `docs/design/auditing.md#yaml-configuration` `docs/design/auditing.md#what-auditing-enables` `lib/lcp_ruby/auditing/` `lib/lcp_ruby/model_factory/`
44
+
45
+ ## Authentication
46
+
47
+ - **API Tokens — Personal Access Tokens** — Mint long-lived bearer tokens for non-interactive API access (Excel Power Query, CI/CD, automations). rails generate lcp_ruby:api_tokens. _(beta)_ · `docs/reference/api-tokens.md` `docs/design/api_tokens.md` `lib/lcp_ruby/api_tokens/token_generator.rb` `lib/lcp_ruby/api_tokens/verifier.rb` `lib/lcp_ruby/controller/bearer_authentication.rb` `lib/generators/lcp_ruby/api_tokens_generator.rb`
48
+ - **Account Locking** — Lock after N failures. config.auth_lock_after_attempts, auth_lock_duration. Devise Lockable. · `docs/guides/host-application.md#authentication` `lib/generators/lcp_ruby/install_auth_generator.rb`
49
+ - **Audit Logging** — Auth events via ActiveSupport::Notifications. Subscribe to authentication.lcp_ruby. · `docs/guides/host-application.md#auditing` `lib/generators/lcp_ruby/auditing_generator.rb`
50
+ - **Authentication Modes** — Four auth modes: :external, :built_in, :oidc, :none. config.authentication in initializer. · `docs/guides/host-application.md#authentication` `docs/guides/host-application.md#step-5-set-up-current_user` `docs/design/oidc_auth.md` `lib/generators/lcp_ruby/install_auth_generator.rb`
51
+ - **Bearer Authentication Resolver Registry** — Pluggable bearer-token resolvers. ResolverRegistry.register(name, priority:, matcher:, resolver:). v1 ships api_token; OIDC plugs in via the same API. _(beta)_ · `docs/reference/api-tokens.md` `docs/design/api_tokens.md` `lib/lcp_ruby/api_tokens/resolver_registry.rb` `lib/lcp_ruby/controller/bearer_authentication.rb`
52
+ - **Install Generator** — rails generate lcp_ruby:install_auth. Sets up users migration, Devise config. rake lcp_ruby:create_admin. · `docs/guides/host-application.md#authentication` `docs/guides/host-application.md#feature-generators` `lib/generators/lcp_ruby/install_auth_generator.rb`
53
+ - **Login Page** — Devise email/password login. config.authentication = :built_in. auth_after_login_path:. · `docs/guides/host-application.md#authentication` `lib/generators/lcp_ruby/install_auth_generator.rb`
54
+ - **OIDC Adaptive Login Page** — One canonical /auth/login that adapts to auth.yml — OIDC buttons, Devise form, or both stacked. · `docs/reference/oidc.md#login-page` `docs/guides/oidc-setup.md` `docs/design/oidc_auth.md` `app/views/lcp_ruby/auth/sessions/new.html.erb` `app/views/layouts/lcp_ruby/auth.html.erb` `app/helpers/lcp_ruby/oidc_button_helper.rb` `app/controllers/lcp_ruby/auth/sessions_controller.rb`
55
+ - **OIDC Authentication** — Single sign-on via OpenID Connect (Entra, Google, Okta, Keycloak, generic). config.authentication = :oidc + config/lcp_ruby/auth.yml. · `docs/reference/oidc.md` `docs/guides/oidc-setup.md` `docs/design/oidc_auth.md` `docs/design/oidc_auth.md` `lib/lcp_ruby/authentication/provider_registry.rb` `lib/lcp_ruby/authentication/user_resolver.rb` `lib/lcp_ruby/authentication/role_mapper.rb` `app/controllers/lcp_ruby/auth/callbacks_controller.rb` `lib/generators/lcp_ruby/templates/install_auth/oidc/`
56
+ - **OIDC Bearer Validation** — Phase 2 — validate OAuth 2.0 access tokens issued by the same OIDC providers used for web login (Power BI, MSAL scripts, native apps). · `docs/reference/oidc-bearer.md` `docs/reference/oidc.md` `docs/design/oidc_auth.md` `docs/design/oidc_auth.md` `lib/lcp_ruby/authentication/jwks_cache.rb` `lib/lcp_ruby/authentication/bearer_jwt_verifier.rb` `lib/lcp_ruby/authentication/oidc_bearer_resolver.rb` `lib/lcp_ruby/authentication/test_support.rb` `lib/lcp_ruby/authentication/role_mapper.rb` `lib/generators/lcp_ruby/oidc_role_mappings_generator.rb`
57
+ - **OIDC Custom Claims Synchronizer** — Host hook for syncing arbitrary claims into the user record on every login (avatars, profile_data, host associations). · `docs/reference/oidc.md#custom-synchronization` `docs/guides/oidc-setup.md#syncing-more-than-email--name` `docs/design/oidc_auth.md` `lib/lcp_ruby/authentication/user_resolver.rb` `lib/lcp_ruby/configuration.rb` `examples/showcase/config/initializers/lcp_ruby.rb`
58
+ - **OIDC Logout Modes** — Per-provider logout.mode: local (default — destroy LCP session only) or rp_initiated (also redirect to IdP end_session_endpoint with id_token_hint). · `docs/reference/oidc.md#logout-flow` `docs/design/oidc_auth.md` `app/controllers/lcp_ruby/auth/sessions_controller.rb` `app/controllers/lcp_ruby/auth/callbacks_controller.rb`
59
+ - **OIDC Migration redirect_uri Override** — Per-provider redirect_uri override + host-level redirect for legacy IdP App registrations whose callback URL doesn't match the engine mount. · `docs/reference/oidc.md#migration--legacy-redirect_uri-override` `docs/design/oidc_auth.md` `lib/lcp_ruby/authentication/omniauth_builder.rb` `lib/lcp_ruby/authentication/provider.rb`
60
+ - **OIDC Provider Templates** — Per-IdP scaffolding (entra, google, okta, keycloak, generic). install_auth --provider=<name> writes a tailored auth.yml. · `docs/reference/oidc.md` `docs/guides/oidc-setup.md` `docs/design/oidc_auth.md` `lib/generators/lcp_ruby/install_auth_generator.rb` `lib/generators/lcp_ruby/templates/install_auth/oidc/`
61
+ - **OIDC Role Mapping (yaml / host)** — Three-source principle for IdP claim → LCP role. role_source yaml (default) or host (resolver lambda); db reserved for Phase 2. · `docs/reference/oidc.md` `docs/guides/oidc-setup.md#role-mapping-options` `docs/design/oidc_auth.md` `lib/lcp_ruby/authentication/role_mapper.rb` `lib/lcp_ruby/metadata/auth_validator.rb`
62
+ - **OIDC User Provisioning Hook** — Tenant filter via reject_if_host_missing + LcpRuby.configuration.user_provisioner. Returning nil rejects sign-in with host_rejected. · `docs/reference/oidc.md` `docs/guides/oidc-setup.md#provisioning-options` `docs/design/oidc_auth.md` `lib/lcp_ruby/authentication/user_resolver.rb` `lib/lcp_ruby/metadata/auth_validator.rb`
63
+ - **Password Reset** — Devise Recoverable flow. config.auth_mailer_sender. Email token-based reset. · `docs/guides/host-application.md#authentication` `lib/generators/lcp_ruby/install_auth_generator.rb`
64
+ - **Session Timeout** — Auto-logout via Devise Timeoutable. config.auth_session_timeout = 30.minutes. · `docs/guides/host-application.md#authentication` `lib/generators/lcp_ruby/install_auth_generator.rb`
65
+ - **User Registration** — Self-registration opt-in. config.auth_allow_registration = true. Default role: viewer. · `docs/guides/host-application.md#authentication` `lib/generators/lcp_ruby/install_auth_generator.rb`
66
+
67
+ ## Background Jobs
68
+
69
+ - **Background Jobs Generator** — Generator creates model/presenter/permissions/views (rails generate lcp_ruby:background_jobs). · `docs/design/background_jobs.md` `docs/reference/engine-configuration.md` `docs/guides/host-application.md` `docs/design/background_jobs.md#generator` `lib/lcp_ruby/background_jobs/`
70
+ - **Cooperative Cancellation** — Cooperative cancellation (check_cancellation!). DB flag checked in loop. Mark as cancelled. · `docs/design/background_jobs.md` `docs/reference/engine-configuration.md` `docs/guides/host-application.md` `docs/design/background_jobs.md#5-cancellation` `docs/design/background_jobs.md#d8-cooperative-cancellation-via-db-flag` `lib/lcp_ruby/background_jobs/`
71
+ - **Declarative Handler (call_webhook)** — HTTP request handler (action: call_webhook). Net::HTTP, error classification, ${env:VAR} interpolation. · `docs/design/background_jobs.md` `docs/reference/engine-configuration.md` `docs/guides/host-application.md` `docs/design/background_jobs.md#call_webhook-details` `docs/design/background_jobs.md#d24-call_webhook-error-classification-and-response-handling` `lib/lcp_ruby/background_jobs/`
72
+ - **Declarative Handler (fire_event)** — Event dispatch handler (action: fire_event). Fires named event. Combine with multi-step for sequences. · `docs/design/background_jobs.md` `docs/reference/engine-configuration.md` `docs/guides/host-application.md` `docs/design/background_jobs.md#declarative-handler` `docs/design/background_jobs.md#send-notification` `lib/lcp_ruby/background_jobs/`
73
+ - **Declarative Handler (run_scope)** — No-code scope+operation handler (action: run_scope). destroy_all, delete_all, update_all, count. · `docs/design/background_jobs.md` `docs/reference/engine-configuration.md` `docs/guides/host-application.md` `docs/design/background_jobs.md#run_scope-details` `docs/design/background_jobs.md#d23-run_scope-calls-ruby-scope-methods-with-keyword-arguments` `lib/lcp_ruby/background_jobs/`
74
+ - **Enqueue API** — Programmatic job enqueue (BackgroundJobs::Enqueuer.enqueue). Params, unique_by, triggered_by support. · `docs/design/background_jobs.md` `docs/reference/engine-configuration.md` `docs/guides/host-application.md` `docs/design/background_jobs.md#programmatic-api-ruby` `lib/lcp_ruby/background_jobs/`
75
+ - **Event Triggers** — Jobs triggered by model events (triggers: [{ event: after_create }]). Automatic job enqueue on event. · `docs/design/background_jobs.md` `docs/reference/engine-configuration.md` `docs/guides/host-application.md` `docs/design/background_jobs.md#event-trigger-declarative` `docs/design/background_jobs.md#4-trigger-mechanism` `lib/lcp_ruby/background_jobs/`
76
+ - **Job Definition (YAML)** — Declarative job config (config/lcp_ruby/jobs/*.yml). Handler, queue, retry, timeout, triggers. · `docs/design/background_jobs.md` `docs/reference/engine-configuration.md` `docs/guides/host-application.md` `docs/design/background_jobs.md#source-yamldsl-static` `docs/design/background_jobs.md#2-job-definition-three-sources` `lib/lcp_ruby/background_jobs/`
77
+ - **Job Execution Model** — Async job tracking model (JobExecution). Status lifecycle, progress, log, errors. Generator: lcp_ruby:background_jobs. · `docs/design/background_jobs.md` `docs/reference/engine-configuration.md` `docs/guides/host-application.md` `docs/design/background_jobs.md#1-jobexecution-model` `lib/lcp_ruby/background_jobs/`
78
+ - **Multi-Step Jobs** — Sequential step execution (steps: array). Each step is a handler action. Progress auto-tracked per step. · `docs/design/background_jobs.md` `docs/reference/engine-configuration.md` `docs/guides/host-application.md` `docs/design/background_jobs.md#d22-job-chaining-via-steps-or-workflow-no-dedicated-pipeline-concept` `docs/design/background_jobs.md#d30-steps-progress-per-step-granularity-only` `lib/lcp_ruby/background_jobs/`
79
+ - **Retry Policy** — Configurable retry (retry:, retry_interval: exponential/linear/fixed). Max attempts with backoff. · `docs/design/background_jobs.md` `docs/reference/engine-configuration.md` `docs/guides/host-application.md` `docs/design/background_jobs.md#10-error-handling-and-retry` `docs/design/background_jobs.md#d19-retry-via-manual-re-enqueue-not-activejob-retry` `lib/lcp_ruby/background_jobs/`
80
+ - **Ruby Class Handler** — Custom job logic (BaseHandler subclass). check_cancellation!, update_progress!, log!, attach_result!. · `docs/design/background_jobs.md` `docs/reference/engine-configuration.md` `docs/guides/host-application.md` `docs/design/background_jobs.md#ruby-class-handler` `docs/design/background_jobs.md#d5-declarative-ruby-class-handlers` `lib/lcp_ruby/background_jobs/`
81
+ - **Schedule Adapter** — Cron-based scheduling (schedule: `0 3 * * *`). Requires external scheduler (e.g., solid_queue). · `docs/design/background_jobs.md` `docs/reference/engine-configuration.md` `docs/guides/host-application.md` `docs/design/background_jobs.md#schedule-trigger-recurring` `docs/design/background_jobs.md#d7-single-scheduling-backend-in-v1` `lib/lcp_ruby/background_jobs/`
82
+ - **Structured Job Log** — Append-only log entries (log! method). JSON array on execution. 2s flush debounce for performance. · `docs/design/background_jobs.md` `docs/reference/engine-configuration.md` `docs/guides/host-application.md` `docs/design/background_jobs.md#9-job-log` `docs/design/background_jobs.md#d21-job-log-for-retry-history-and-handler-messages` `lib/lcp_ruby/background_jobs/`
83
+ - **Unique Key Enforcement** — Prevent duplicate jobs (unique_by: [field1, field2]). Checked before enqueue. Pending/running dedup. · `docs/design/background_jobs.md` `docs/reference/engine-configuration.md` `docs/guides/host-application.md` `docs/design/background_jobs.md#6-concurrency-uniqueness` `docs/design/background_jobs.md#d27-unique_key-computation-sha256-of-sorted-key-value-pairs` `lib/lcp_ruby/background_jobs/`
84
+
85
+ ## Batch Actions
86
+
87
+ - **Auto-Derived Batch Actions (batch: true)** — Auto-derive batch from single action (batch: true or batch: { overrides }). Inherits name/type/icon. · `docs/guides/batch-actions.md#auto-derived-batch-actions` `docs/design/batch_action_auto_derive.md` `docs/design/multiselect_and_batch_infrastructure.md` `lib/lcp_ruby/batch_actions/`
88
+ - **Batch Action Toolbar** — Sticky footer toolbar on selection. Count, action buttons, clear. Stimulus: lcp-batch-select. · `docs/guides/batch-actions.md#enabling-batch-actions` `docs/design/multiselect_and_batch_infrastructure.md` `lib/lcp_ruby/batch_actions/`
89
+ - **Batch Actions on Soft Delete** — Batch delete calls discard!(by:) on soft-deletable models. Archive auto-derives restore/perm_destroy. · `docs/guides/batch-actions.md#batch-delete-soft-delete` `docs/design/multiselect_and_batch_infrastructure.md` `lib/lcp_ruby/batch_actions/`
90
+ - **Batch Delete (Destroy)** — Built-in batch delete. Respects soft delete (discard!/destroy!). Per-record permission check, skip count. · `docs/guides/batch-actions.md#batch-delete-hard-delete` `docs/design/batch_action_delete.md` `docs/design/multiselect_and_batch_infrastructure.md` `lib/lcp_ruby/batch_actions/`
91
+ - **Batch Permanently Destroy** — Hard-delete discarded records in batch. select_all_filter: false for safety. Archive presenters. · `docs/guides/batch-actions.md#archive-presenter-with-restore-and-permanent-delete` `docs/design/multiselect_and_batch_infrastructure.md` `lib/lcp_ruby/batch_actions/`
92
+ - **Batch Restore** — Batch restore soft-deleted records (on archive presenters). Auto-derived from single action with batch:. · `docs/guides/batch-actions.md#archive-presenter-with-restore-and-permanent-delete` `docs/design/multiselect_and_batch_infrastructure.md` `lib/lcp_ruby/batch_actions/`
93
+ - **Batch Result Log** — Operation log (result_log: true). batch_operation + batch_operation_item records. Detail link in flash. _(beta)_ · `docs/guides/batch-actions.md#result-logging` `docs/design/multiselect_and_batch_infrastructure.md` `lib/lcp_ruby/batch_actions/`
94
+ - **Batch Select (Multiselect)** — Checkbox selection on index (batch: true on actions). Shift-click range, cross-page sessionStorage. · `docs/guides/batch-actions.md#selection-modes` `docs/design/multiselect_and_batch_infrastructure.md` `lib/lcp_ruby/batch_actions/`
95
+ - **Bulk Custom Batch Action (batch_capable?)** — Single-call bulk execution (batch_capable? true). Receives full records array. For SQL UPDATE_ALL. · `docs/guides/batch-actions.md#bulk-execution-batch_capable` `docs/design/multiselect_and_batch_infrastructure.md` `lib/lcp_ruby/batch_actions/`
96
+ - **Cross-Page Selection** — Selections persist across pagination (sessionStorage). Configurable max_explicit_ids (default 500). · `docs/guides/batch-actions.md#selection-modes` `docs/design/multiselect_and_batch_infrastructure.md` `lib/lcp_ruby/batch_actions/`
97
+ - **Per-Record Custom Batch Action** — Per-record iteration for custom actions (batch_capable? false). Same class for single + batch. · `docs/guides/batch-actions.md#per-record-iteration-default` `docs/design/multiselect_and_batch_infrastructure.md` `lib/lcp_ruby/batch_actions/`
98
+ - **Per-Record Permission in Batch** — Per-record permission check in batch. Denied records skipped. Split counts in flash message. · `docs/guides/batch-actions.md#per-record-permission-checks` `docs/design/multiselect_and_batch_infrastructure.md` `lib/lcp_ruby/batch_actions/`
99
+ - **Select All Matching Filter** — Bulk ops on entire filter set (select_all_filter). Backend receives filter params, not IDs. · `docs/guides/batch-actions.md#select-all-filter-mode` `docs/design/multiselect_and_batch_infrastructure.md` `lib/lcp_ruby/batch_actions/`
100
+
101
+ ## Bind To
102
+
103
+ - **Bind To (Host Model) — basic** — Connect LCP metadata to existing AR class (bind_to:). Skip builder/schema. Presenters/permissions work. · `docs/reference/host-controller-integration.md` `docs/design/host_app_controller_integration.md` `lib/lcp_ruby/model_factory/`
104
+ - **bind_to: Ransack required-but-missing detection** — Boot error if presenter has search but bound class lacks ransackable_attributes. Actionable message. · `docs/reference/host-controller-integration.md` `docs/reference/host-controller-integration.md` `docs/design/host_app_controller_integration.md` `lib/lcp_ruby/model_factory/`
105
+ - **bind_to: associations are metadata-only** — YAML associations on bind_to are metadata-only. Never applied as AR macros. Host owns associations. · `docs/reference/host-controller-integration.md` `docs/design/host_app_controller_integration.md` `lib/lcp_ruby/model_factory/`
106
+ - **bind_to: boot-time field warnings** — Cross-check YAML fields vs bound class columns/methods on boot. Warnings for typos, not errors. · `docs/reference/host-controller-integration.md` `docs/design/host_app_controller_integration.md` `lib/lcp_ruby/model_factory/`
107
+ - **bind_to: label_method always applied** — to_label always defined on bind_to class (options.label_method). Not opt-in. For selects/breadcrumbs. · `docs/reference/host-controller-integration.md` `docs/design/host_app_controller_integration.md` `lib/lcp_ruby/model_factory/`
108
+ - **bind_to_apply: [attachments]** — Active Storage macros on bound class (bind_to_apply: [attachments]). has_one/many_attached from YAML. · `docs/reference/host-controller-integration.md` `docs/guides/attachments.md#defining-attachment-fields` `docs/design/host_app_controller_integration.md` `lib/lcp_ruby/model_factory/`
109
+ - **bind_to_apply: [positioning]** — Positioning gem integration on bound class (bind_to_apply: [positioning]). Drag-reorder in indexes. · `docs/reference/host-controller-integration.md` `docs/reference/models.md` `docs/design/host_app_controller_integration.md` `lib/lcp_ruby/model_factory/`
110
+ - **bind_to_apply: [ransack]** — Opt-in ransackable_attributes from YAML fields (bind_to_apply: [ransack]). Required for search/filters. · `docs/reference/host-controller-integration.md` `docs/reference/host-controller-integration.md` `docs/design/host_app_controller_integration.md` `lib/lcp_ruby/model_factory/`
111
+ - **bind_to_apply: [scopes]** — Register YAML scopes on bound class (bind_to_apply: [scopes]). AR scope class methods from YAML. · `docs/reference/host-controller-integration.md` `docs/design/host_app_controller_integration.md` `lib/lcp_ruby/model_factory/`
112
+ - **bind_to_apply: [soft_delete]** — Soft delete on bound class (bind_to_apply: [soft_delete]). discard!/undiscard!, kept/discarded scopes. · `docs/reference/host-controller-integration.md` `docs/design/host_app_controller_integration.md` `lib/lcp_ruby/model_factory/`
113
+ - **bind_to_apply: [transforms]** — Field normalizations on bound class (bind_to_apply: [transforms]). strip, downcase, normalize_url/phone. · `docs/reference/host-controller-integration.md` `docs/design/host_app_controller_integration.md` `lib/lcp_ruby/model_factory/`
114
+ - **bind_to_apply: [userstamps]** — Auto-set created_by/updated_by on bound class (bind_to_apply: [userstamps]). before_create/save callbacks. · `docs/reference/host-controller-integration.md` `docs/design/host_app_controller_integration.md` `lib/lcp_ruby/model_factory/`
115
+ - **bind_to_apply: [validations]** — Apply YAML validators to bound class (bind_to_apply: [validations]). presence, length, numericality, etc. · `docs/reference/host-controller-integration.md` `docs/design/host_app_controller_integration.md` `lib/lcp_ruby/model_factory/`
116
+ - **bind_to_apply: combined opt-ins** — Multiple applicators in one YAML (bind_to_apply: [ransack, scopes, ...]). Idempotent on reload. · `docs/reference/host-controller-integration.md` `docs/design/host_app_controller_integration.md` `lib/lcp_ruby/model_factory/`
117
+ - **lcp_managed: auto_migrate=false escape hatch** — Production hosts with auto_migrate: false can pre-migrate FK columns by hand; LCP detects them and applies AR macros without modifying schema. · `docs/design/bind_to_managed_fields_and_associations.md` `docs/design/bind_to_managed_fields_and_associations.md` `lib/lcp_ruby/engine.rb#all_managed_fk_columns_present?`
118
+ - **lcp_managed: belongs_to + auto FK column** — Managed belongs_to on bind_to model — LCP adds the FK column AND declares the AR macro on the host class. · `docs/design/bind_to_managed_fields_and_associations.md` `docs/improve-tasks/school-improve-tasks.md` `docs/design/bind_to_managed_fields_and_associations.md` `lib/lcp_ruby/model_factory/schema_manager.rb#add_managed_fk_columns!` `lib/lcp_ruby/model_factory/association_applicator.rb` `lib/lcp_ruby/engine.rb#apply_bind_to_managed_associations`
119
+ - **lcp_managed: dual-row idempotence (field + belongs_to)** — Same column declared as both a managed `field:` row AND a managed `belongs_to:` row — added exactly once. · `docs/design/bind_to_managed_fields_and_associations.md` `docs/design/bind_to_managed_fields_and_associations.md` `lib/lcp_ruby/model_factory/schema_manager.rb#apply_managed!`
120
+ - **lcp_managed: enum field (column only, no AR macro)** — Managed enum field — LCP adds the column (as :string) but NOT an AR enum macro; host owns the macro. · `docs/design/bind_to_managed_fields_and_associations.md` `docs/design/bind_to_managed_fields_and_associations.md` `lib/lcp_ruby/model_factory/schema_manager.rb#add_managed_field_columns!` `lib/lcp_ruby/model_factory/enum_applicator.rb`
121
+ - **lcp_managed: has_many / has_one (no schema on this side)** — Managed has_many / has_one — LCP declares the AR macro on the host class without changing schema on the bound side; FK lives on the target. · `docs/design/bind_to_managed_fields_and_associations.md` `docs/design/bind_to_managed_fields_and_associations.md` `lib/lcp_ruby/model_factory/association_applicator.rb#apply_has_many` `lib/lcp_ruby/model_factory/association_applicator.rb#apply_has_one`
122
+ - **lcp_managed: polymorphic belongs_to** — Polymorphic managed belongs_to — LCP adds <name>_id + <name>_type pair with composite index, declares polymorphic AR macro. · `docs/design/bind_to_managed_fields_and_associations.md` `docs/design/bind_to_managed_fields_and_associations.md` `lib/lcp_ruby/model_factory/schema_manager.rb#add_managed_fk_columns!`
123
+ - **lcp_managed: regular column** — Per-item flag that makes LCP additively add a column to a bind_to host table at boot. `field: { name: ..., type: ..., lcp_managed: true }`. · `docs/design/bind_to_managed_fields_and_associations.md` `docs/reference/host-controller-integration.md` `docs/design/bind_to_managed_fields_and_associations.md` `lib/lcp_ruby/model_factory/schema_manager.rb#apply_managed!` `lib/lcp_ruby/engine.rb#apply_bind_to_managed_schema`
124
+ - **lcp_managed: validation + reload safety** — 7 ConfigurationValidator checks (type collision, sub-option mismatch, macro collision, method shadow, nullability, assoc options, dynamic-model misuse) + reload carve-out via lcp_managed_summary. · `docs/design/bind_to_managed_fields_and_associations.md` `docs/design/bind_to_managed_fields_and_associations.md` `lib/lcp_ruby/metadata/configuration_validator.rb#validate_managed_field_collisions` `lib/lcp_ruby/model_factory/managed_tracking.rb`
125
+
126
+ ## Composite Pages
127
+
128
+ - **Composite Page (Semantic Layout)** — Multi-zone record page (area: main|tabs|sidebar|below). pages/*.yml zones: array. scope_context: for filtering. · `docs/reference/pages.md#composite-pages-semantic-layout` `docs/guides/composite-pages.md#composite-pages-guide` `docs/design/composite_pages_v2.md` `lib/lcp_ruby/pages/resolver.rb` `lib/lcp_ruby/pages/registry.rb`
129
+ - **Conditional Zone on Composite Page** — Role-gated composite zone (visible_when: { role: admin }). Evaluated before queries. Same as dashboard zones. · `docs/reference/pages.md#conditional-zone-visibility` `docs/guides/composite-pages.md#conditional-zone-visibility` `docs/design/composite_pages_v2.md` `lib/lcp_ruby/pages/resolver.rb`
130
+ - **Dialog Reload Zone (Single)** — Dialog success reloads one zone (on_success: :reload_zone, reload_zone: `name`). Turbo Frame src reassigned. · `docs/guides/composite-pages.md#reloading-zones-from-dialogs` `docs/guides/dialogs.md#zone-reload-after-dialog` `docs/design/composite_pages_v2.md` `app/views/lcp_ruby/resources/_semantic_page.html.erb` `app/views/lcp_ruby/resources/_semantic_index_page.html.erb` `app/controllers/lcp_ruby/resources_controller.rb`
131
+ - **Dialog Reload Zones (Multiple)** — Dialog success reloads multiple zones (on_success: :reload_zones, reload_zones: [...]). Parallel Turbo refreshes. · `docs/guides/composite-pages.md#reloading-zones-from-dialogs` `docs/guides/dialogs.md#reload-multiple-zones` `docs/design/composite_pages_v2.md` `app/views/lcp_ruby/resources/_semantic_page.html.erb` `app/views/lcp_ruby/resources/_semantic_index_page.html.erb` `app/controllers/lcp_ruby/resources_controller.rb`
132
+ - **Different Layout Examples** — Six composite layout variants demonstrated: main+tabs+sidebar, main+tabs, main+sidebar, main+below, form+below. · `docs/reference/pages.md#areas` `docs/guides/composite-pages.md#areas` `docs/design/composite_pages_v2.md` `app/views/lcp_ruby/resources/_semantic_page.html.erb` `app/views/lcp_ruby/resources/_semantic_index_page.html.erb` `app/controllers/lcp_ruby/resources_controller.rb`
133
+ - **Form Zone (submit_redirect: self)** — Edit form in main zone (submit_redirect: self). Stays on composite page after save. Needs show+update perms. · `docs/reference/pages.md#form-zones` `docs/guides/composite-pages.md#form-zones` `docs/design/composite_pages_v2.md` `app/views/lcp_ruby/resources/_semantic_page.html.erb` `app/views/lcp_ruby/resources/_semantic_index_page.html.erb` `app/controllers/lcp_ruby/resources_controller.rb`
134
+ - **Index Composite: Conditional Sidebar Zone** — visible_when on index composite sidebar. Same as regular composite zones. Role-based widget visibility. · `docs/reference/pages.md#conditional-zone-visibility` `docs/guides/composite-pages.md#conditional-zone-visibility` `docs/design/composite_pages_v2.md` `app/views/lcp_ruby/resources/_semantic_page.html.erb` `app/views/lcp_ruby/resources/_semantic_index_page.html.erb` `app/controllers/lcp_ruby/resources_controller.rb`
135
+ - **Index Composite: Sidebar KPI Widgets** — Sidebar KPIs on index page (aggregate: count/sum). Scoped to full collection, not a single record. · `docs/reference/pages.md#widget-zones` `docs/reference/pages.md#widget-zones-with-scope_context` `docs/design/composite_pages_v2.md` `lib/lcp_ruby/widgets/data_resolver.rb`
136
+ - **Index-Level Composite Page** — Index table as main zone with sidebar KPIs. No record ID in URL. Tabs not supported. table_columns required. · `docs/reference/pages.md#index-level-composite-pages` `docs/guides/composite-pages.md#index-level-composite-pages` `docs/design/composite_pages_v2.md` `lib/lcp_ruby/pages/resolver.rb`
137
+ - **Main + Below Layout** — Main zone + full-width below zone (area: below). No tabs or sidebar. Simple parent-child relationship view. · `docs/reference/pages.md#sidebarbelow-zones` `docs/guides/composite-pages.md#areas` `docs/design/composite_pages_v2.md` `app/views/lcp_ruby/resources/_semantic_page.html.erb` `app/views/lcp_ruby/resources/_semantic_index_page.html.erb` `app/controllers/lcp_ruby/resources_controller.rb`
138
+ - **Main + Sidebar Layout** — Main + sidebar zones (area: sidebar). KPI widgets, presenter zones. Narrower right column for context data. · `docs/reference/pages.md#sidebarbelow-zones` `docs/guides/composite-pages.md#adding-a-sidebar` `docs/design/composite_pages_v2.md` `app/views/lcp_ruby/resources/_semantic_page.html.erb` `app/views/lcp_ruby/resources/_semantic_index_page.html.erb` `app/controllers/lcp_ruby/resources_controller.rb`
139
+ - **Main + Tabs + Sidebar Layout** — Full semantic layout: main + tabs + sidebar. All composite features combined. Most complete page layout. · `docs/reference/pages.md#tab-navigation` `docs/guides/composite-pages.md#tab-navigation` `docs/guides/composite-pages.md#adding-a-sidebar` `docs/design/composite_pages_v2.md` `app/views/lcp_ruby/resources/_semantic_page.html.erb` `app/views/lcp_ruby/resources/_semantic_index_page.html.erb` `app/controllers/lcp_ruby/resources_controller.rb`
140
+ - **Main + Tabs Layout** — Master-detail: main zone + tab bar (area: tabs). Each tab is a zone. First tab active by default. · `docs/reference/pages.md#tab-navigation` `docs/guides/composite-pages.md#tab-navigation` `docs/design/composite_pages_v2.md` `app/helpers/lcp_ruby/dashboard_helper.rb` `app/views/lcp_ruby/resources/_grid_page.html.erb`
141
+ - **Main + Tabs Layout (No Sidebar)** — Tabs-only composite: main + tabs, no sidebar. Full-width tabs below main. Simpler than full layout. · `docs/reference/pages.md#tab-navigation` `docs/guides/composite-pages.md#tab-navigation` `docs/design/composite_pages_v2.md` `app/views/lcp_ruby/resources/_semantic_page.html.erb` `app/views/lcp_ruby/resources/_semantic_index_page.html.erb` `app/controllers/lcp_ruby/resources_controller.rb`
142
+ - **Record Click: dialog** — Row click opens modal (record_click: dialog). Show page in dialog via ?_dialog=1. Stays on composite page. · `docs/reference/pages.md#zone-record-click` `docs/guides/composite-pages.md#record-click-behavior` `docs/design/composite_pages_v2.md` `app/views/lcp_ruby/resources/_semantic_page.html.erb` `app/views/lcp_ruby/resources/_semantic_index_page.html.erb` `app/controllers/lcp_ruby/resources_controller.rb`
143
+ - **Record Click: navigate** — Default row click (record_click: navigate). Full-page navigation to record show page. data-href attribute. · `docs/reference/pages.md#zone-record-click` `docs/guides/composite-pages.md#record-click-behavior` `docs/design/composite_pages_v2.md` `app/views/lcp_ruby/resources/_semantic_page.html.erb` `app/views/lcp_ruby/resources/_semantic_index_page.html.erb` `app/controllers/lcp_ruby/resources_controller.rb`
144
+ - **Record Click: none** — Non-clickable rows (record_click: none). No cursor change, no click action. For informational lists. · `docs/reference/pages.md#zone-record-click` `docs/guides/composite-pages.md#record-click-behavior` `docs/design/composite_pages_v2.md` `app/views/lcp_ruby/resources/_semantic_page.html.erb` `app/views/lcp_ruby/resources/_semantic_index_page.html.erb` `app/controllers/lcp_ruby/resources_controller.rb`
145
+ - **Record Source Zone** — Single-record zone by URL param (record_source: { param: field_id }). Shows one record, not a collection. · `docs/reference/pages.md#record-source-zones` `docs/guides/composite-pages.md#record-source-zones` `docs/design/composite_pages_v2.md` `lib/lcp_ruby/widgets/record_source_resolver.rb`
146
+ - **Show in Dialog** — Dialog frame for record show (record_click: dialog + ?_dialog=1). Read-only header + show sections + close button. · `docs/reference/pages.md#show-in-dialog` `docs/reference/dialogs.md#dialog-routing` `docs/design/modal_dialogs.md#dialog-trigger-client-side` `app/views/lcp_ruby/resources/_semantic_page.html.erb` `app/views/lcp_ruby/resources/_semantic_index_page.html.erb` `app/controllers/lcp_ruby/resources_controller.rb`
147
+ - **Sidebar Widget with scope_context** — Record-scoped sidebar KPI (scope_context: { fk: `:record.id` }). Aggregate filtered to parent record. · `docs/reference/pages.md#widget-zones-with-scope_context` `docs/reference/pages.md#scope_context` `docs/design/composite_pages_v2.md` `lib/lcp_ruby/pages/scope_context_resolver.rb` `lib/lcp_ruby/widgets/scope_applicator.rb`
148
+ - **Tab Label i18n (label_key)** — Tab label via i18n (label_key:). Falls back to humanized zone name. Locale file under lcp_ruby.composite.*.tabs. · `docs/reference/pages.md#tab-navigation` `docs/guides/composite-pages.md#tab-navigation` `docs/design/composite_pages_v2.md` `app/views/lcp_ruby/resources/_semantic_page.html.erb` `app/views/lcp_ruby/resources/_semantic_index_page.html.erb` `app/controllers/lcp_ruby/resources_controller.rb`
149
+ - **Tab Navigation (Turbo Frames)** — Tabs load via Turbo Frame requests to zone endpoint. No full page reload. Client-side tab switching. · `docs/reference/pages.md#tab-navigation` `docs/guides/composite-pages.md#tab-navigation` `docs/design/composite_pages_v2.md` `app/views/lcp_ruby/resources/_semantic_page.html.erb` `app/views/lcp_ruby/resources/_semantic_index_page.html.erb` `app/controllers/lcp_ruby/resources_controller.rb`
150
+ - **Turbo Frame Lazy Loading** — First tab loads via src= immediately. Other tabs load on click. Reduces initial page load. No prefetch. · `docs/reference/pages.md#zone-endpoint` `docs/guides/composite-pages.md#zone-endpoint` `docs/design/composite_pages_v2.md` `app/views/lcp_ruby/resources/_semantic_page.html.erb` `app/views/lcp_ruby/resources/_semantic_index_page.html.erb` `app/controllers/lcp_ruby/resources_controller.rb`
151
+ - **URL Bookmarkability (?tab=)** — Tab state in URL (?tab=zone_name). history.replaceState on tab switch. Bookmarkable and shareable tab links. · `docs/reference/pages.md#tab-navigation` `docs/guides/composite-pages.md#tab-navigation` `docs/design/composite_pages_v2.md` `app/views/lcp_ruby/resources/_semantic_page.html.erb` `app/views/lcp_ruby/resources/_semantic_index_page.html.erb` `app/controllers/lcp_ruby/resources_controller.rb`
152
+ - **Zone Endpoint** — Per-zone HTTP endpoint (GET /:slug/:id/zones/:zone). Supports ?page=, ?sort=, ?direction=. Turbo Frame response. · `docs/reference/pages.md#zone-endpoint` `docs/guides/composite-pages.md#zone-endpoint` `docs/design/composite_pages_v2.md` `app/views/lcp_ruby/resources/_semantic_page.html.erb` `app/views/lcp_ruby/resources/_semantic_index_page.html.erb` `app/controllers/lcp_ruby/resources_controller.rb`
153
+ - **Zone Filters (full)** — Full advanced filter pipeline in zone (filters: full). Ransack + custom filters inside tab Turbo Frame. · `docs/reference/pages.md#zone-filters` `docs/guides/composite-pages.md#zone-filtering` `docs/design/composite_pages_v2.md` `app/views/lcp_ruby/resources/_semantic_page.html.erb` `app/views/lcp_ruby/resources/_semantic_index_page.html.erb` `app/controllers/lcp_ruby/resources_controller.rb`
154
+ - **Zone Filters (none)** — No search UI in zone (filters: none). Default for sidebar/below. For compact lists where search adds no value. · `docs/reference/pages.md#zone-filters` `docs/guides/composite-pages.md#zone-filtering` `docs/design/composite_pages_v2.md` `app/views/lcp_ruby/resources/_semantic_page.html.erb` `app/views/lcp_ruby/resources/_semantic_index_page.html.erb` `app/controllers/lcp_ruby/resources_controller.rb`
155
+ - **Zone Filters (quick)** — Quick text search in zone (filters: quick). Default for tabs. Renders inside Turbo Frame. No page reload. · `docs/reference/pages.md#zone-filters` `docs/guides/composite-pages.md#zone-filtering` `docs/design/composite_pages_v2.md` `app/views/lcp_ruby/resources/_semantic_page.html.erb` `app/views/lcp_ruby/resources/_semantic_index_page.html.erb` `app/controllers/lcp_ruby/resources_controller.rb`
156
+ - **Zone Pagination** — Kaminari pagination inside zone Turbo Frame (per_page on zone presenter). Only zone content updates on page click. · `docs/reference/pages.md#zone-attributes` `docs/guides/composite-pages.md#composite-pages-guide` `docs/design/composite_pages_v2.md` `app/views/lcp_ruby/resources/_semantic_page.html.erb` `app/views/lcp_ruby/resources/_semantic_index_page.html.erb` `app/controllers/lcp_ruby/resources_controller.rb`
157
+ - **Zone Sorting** — Sortable zone columns (sortable: true). Click header to sort within Turbo Frame. Independent per zone. · `docs/reference/pages.md#zone-attributes` `docs/guides/composite-pages.md#composite-pages-guide` `docs/design/composite_pages_v2.md` `app/views/lcp_ruby/resources/_semantic_page.html.erb` `app/views/lcp_ruby/resources/_semantic_index_page.html.erb` `app/controllers/lcp_ruby/resources_controller.rb`
158
+ - **Zone Width (Grid Proportions)** — CSS grid ratio (width: 1-12). Default main:sidebar = 8:4. Custom e.g. 9:3 for wider main area. · `docs/reference/pages.md#zone-width` `docs/guides/composite-pages.md#custom-mainsidebar-proportions` `docs/design/composite_pages_v2.md` `app/views/lcp_ruby/resources/_semantic_page.html.erb` `app/views/lcp_ruby/resources/_semantic_index_page.html.erb` `app/controllers/lcp_ruby/resources_controller.rb`
159
+ - **Zone default_scope** — Always-on base filter (default_scope: scope_name). Applied before zone scope_context. Cumulative with scope. · `docs/reference/pages.md#zone-default-scope` `docs/guides/composite-pages.md#default-scope` `docs/design/composite_pages_v2.md` `app/views/lcp_ruby/resources/_semantic_page.html.erb` `app/views/lcp_ruby/resources/_semantic_index_page.html.erb` `app/controllers/lcp_ruby/resources_controller.rb`
160
+ - **index_presenter (Index Presenter Override)** — Index action presenter override (index_presenter:). Needed when show zone has no table_columns. Same model required. · `docs/reference/pages.md#index-level-composite-pages` `docs/guides/composite-pages.md#index-presenter-override` `docs/design/composite_pages_v2.md` `app/views/lcp_ruby/resources/_semantic_page.html.erb` `app/views/lcp_ruby/resources/_semantic_index_page.html.erb` `app/controllers/lcp_ruby/resources_controller.rb`
161
+ - **scope_context (Record Scoping)** — Dynamic zone filtering (scope_context: { field: `:record.id` }). Supports :record.<field>, :current_user, :current_date. · `docs/reference/pages.md#scope_context` `docs/guides/composite-pages.md#scope_context` `docs/design/composite_pages_v2.md` `lib/lcp_ruby/pages/scope_context_resolver.rb`
162
+
163
+ ## Custom Fields
164
+
165
+ - **Boolean Custom Fields** — Boolean custom fields. default_value: true/false. custom_type: boolean. Renders as Yes/No badge. · `docs/guides/custom-fields.md#field-types` `docs/reference/custom-fields.md#custom-field-definition-attributes` `lib/lcp_ruby/custom_fields/applicator.rb` `lib/lcp_ruby/custom_fields/registry.rb`
166
+ - **Conditional Custom Field Form** — visible_when on form sections by custom_type. Text/Numeric/Enum constraints shown conditionally. · `docs/guides/custom-fields.md#working-with-sections` `docs/reference/custom-fields.md#visibility-attributes` `lib/lcp_ruby/custom_fields/applicator.rb`
167
+ - **Custom Field Display Options** — Visibility: show_in_table, show_in_form, show_in_show. sortable:, searchable:, column_width:, active:. · `docs/reference/custom-fields.md#rendering-attributes` `docs/reference/custom-fields.md#input_type` `docs/reference/custom-fields.md#renderer` `lib/lcp_ruby/custom_fields/applicator.rb`
168
+ - **Custom Field Hints** — Optional hint: attribute on definitions. Displayed below form inputs. Propagated via LayoutBuilder. · `docs/reference/custom-fields.md#description` `docs/reference/custom-fields.md#placeholder` `lib/lcp_ruby/custom_fields/applicator.rb`
169
+ - **Custom Field Permissions** — Per-field granularity: fields.readable/writable lists. custom_data aggregate. field_overrides:. · `docs/guides/custom-fields.md#permission-model` `docs/reference/custom-fields.md#permissions` `docs/reference/custom-fields.md#readable_by_roles` `docs/reference/custom-fields.md#writable_by_roles` `lib/lcp_ruby/custom_fields/applicator.rb` `lib/lcp_ruby/custom_fields/contract_validator.rb`
170
+ - **Custom Field Sections** — Group fields by section: attribute. position: controls ordering. Rendered as separate headings. · `docs/guides/custom-fields.md#working-with-sections` `docs/reference/custom-fields.md#section` `lib/lcp_ruby/custom_fields/applicator.rb`
171
+ - **Custom Fields Generator** — rails generate lcp_ruby:custom_fields. Creates model, presenter, permissions, view group. --format=yaml. · `docs/guides/custom-fields.md#step-1-generate-custom-field-definition-metadata` `docs/reference/custom-fields.md#how-it-works` `lib/generators/lcp_ruby/custom_fields_generator.rb` `lib/lcp_ruby/custom_fields/setup.rb`
172
+ - **Custom Fields Overview** — Runtime user-defined fields. custom_fields: true in model options. Generator: lcp_ruby:custom_fields. · `docs/guides/custom-fields.md#custom-fields-guide` `docs/reference/custom-fields.md#custom-fields-reference` `lib/lcp_ruby/custom_fields/`
173
+ - **Custom Fields on Multiple Models** — Multiple models with custom_fields: true. Scoped by target_model. Nested management routes. · `docs/guides/custom-fields.md#step-2-enable-custom-fields-on-a-model` `docs/reference/custom-fields.md#enabling-custom-fields` `lib/lcp_ruby/custom_fields/registry.rb` `lib/lcp_ruby/custom_fields/applicator.rb`
174
+ - **Date & DateTime Custom Fields** — Date/datetime custom fields. custom_type: date/datetime. sortable:, show_in_table:. · `docs/guides/custom-fields.md#field-types` `docs/reference/custom-fields.md#custom_type` `lib/lcp_ruby/custom_fields/applicator.rb`
175
+ - **Enum Custom Fields** — Enum custom fields. enum_values: array of strings or {value,label}. custom_type: enum. default_value:. · `docs/guides/custom-fields.md#enum-fields` `docs/reference/custom-fields.md#enum_values` `lib/lcp_ruby/custom_fields/applicator.rb`
176
+ - **Numeric Custom Fields** — Integer/float/decimal custom fields. min_value:, max_value:, precision:. custom_type: integer/float/decimal. · `docs/guides/custom-fields.md#field-types` `docs/reference/custom-fields.md#min_value` `docs/reference/custom-fields.md#max_value` `docs/reference/custom-fields.md#precision` `lib/lcp_ruby/custom_fields/applicator.rb`
177
+ - **Programmatic Custom Field Access** — Dynamic accessors: record.nickname. Low-level: read_custom_field/write_custom_field. No restart needed. · `docs/guides/custom-fields.md#programmatic-access` `docs/reference/custom-fields.md#programmatic-api` `docs/reference/custom-fields.md#reading-and-writing-values` `lib/lcp_ruby/custom_fields/registry.rb` `lib/lcp_ruby/custom_fields/query.rb`
178
+ - **String Custom Fields** — String custom fields. min_length:, max_length:, searchable:, show_in_table:. custom_type: string. · `docs/guides/custom-fields.md#field-types` `docs/reference/custom-fields.md#min_length` `docs/reference/custom-fields.md#max_length` `lib/lcp_ruby/custom_fields/applicator.rb`
179
+
180
+ ## Custom Render Blocks
181
+
182
+ - **Custom Form Section (type: custom)** — Replace form section with host partial. Receives form builder. additional_permitted_params for inputs. · `docs/guides/rendering-extension-points.md` `docs/design/custom_render_blocks.md` `lib/lcp_ruby/presenter/`
183
+ - **Custom Render Blocks vs View Slots** — Substitution (render blocks) vs injection (view slots). Declarative YAML vs imperative Registry.register. · `docs/guides/rendering-extension-points.md` `docs/design/custom_render_blocks.md` `lib/lcp_ruby/presenter/`
184
+ - **Custom Show Section (type: custom)** — Replace show section with host partial (custom_section). Receives record, presenter, evaluator locals. · `docs/guides/rendering-extension-points.md` `docs/design/custom_render_blocks.md` `lib/lcp_ruby/presenter/`
185
+ - **Custom Zone in Composite Page (tabs)** — Custom zone in page tabs/sidebar (type: custom, partial:). Lazy Turbo Frame or eager: true rendering. · `docs/guides/rendering-extension-points.md` `docs/design/custom_render_blocks.md` `lib/lcp_ruby/presenter/` `lib/lcp_ruby/pages/`
186
+ - **Custom Zone in Sidebar (eager: true)** — Inline-rendered sidebar zone (eager: true). No lazy loading. For lightweight or script-needing content. · `docs/guides/rendering-extension-points.md` `docs/design/custom_render_blocks.md` `lib/lcp_ruby/presenter/`
187
+ - **Custom Zone with scope_context** — Pass resolved values to custom partials (scope_context:). Optional scoped_records AR relation. · `docs/guides/rendering-extension-points.md` `docs/design/custom_render_blocks.md` `lib/lcp_ruby/presenter/`
188
+ - **Index render_with (custom index layout)** — Replace index content area with host partial (render_with). LCP layout preserved, records pre-filtered. · `docs/guides/rendering-extension-points.md` `docs/design/custom_render_blocks.md` `lib/lcp_ruby/presenter/`
189
+ - **Production Error Handling for Custom Partials** — Graceful degradation in production. Dev: propagate. Prod: rescue, log, show error block. · `docs/guides/rendering-extension-points.md` `docs/design/custom_render_blocks.md` `lib/lcp_ruby/presenter/`
190
+ - **Show render_with (custom show layout)** — Replace show content area with host partial (show render_with). LCP frame preserved. Not in dialogs. · `docs/guides/rendering-extension-points.md` `docs/design/custom_render_blocks.md` `lib/lcp_ruby/presenter/`
191
+ - **action_set in render_with Partials** — Permission-aware action resolver in partials (action_set). collection_actions, single_actions(record). · `docs/guides/rendering-extension-points.md` `docs/design/custom_render_blocks.md` `lib/lcp_ruby/presenter/`
192
+ - **additional_permitted_params on Custom Form Sections** — Whitelist custom form inputs (additional_permitted_params:). Scalar names or nested hash specs. · `docs/guides/rendering-extension-points.md` `docs/design/custom_render_blocks.md` `lib/lcp_ruby/presenter/` `lib/lcp_ruby/controller/`
193
+
194
+ ## Dashboards
195
+
196
+ - **Apply Button Dirty State** — .is-dirty class on the filter Apply button + i18n unapplied-count badge. Stimulus controller snapshots initial values, compares on change/input. · `docs/reference/page_filters.md#apply-button--dirty-state` `docs/design/page_filters_as_virtual_forms.md` `app/assets/javascripts/lcp_ruby/controllers/filter_dirty_controller.js`
197
+ - **Auto-Refresh (depends_on)** — Auto-refresh zone on model CUD (depends_on: [model]). Turbo Streams broadcast. Requires turbo-rails gem. _(beta)_ · `docs/reference/pages.md#auto-refresh-depends_on` `docs/guides/composite-pages.md#auto-refresh-with-depends_on` `docs/design/dashboards.md#configuration-behavior` `app/helpers/lcp_ruby/dashboard_helper.rb` `app/views/lcp_ruby/resources/_grid_page.html.erb`
198
+ - **Cascading Filter Selects** — input_options.depends_on on filter association_select/multi_select. Parent change reloads child via /select_options. Reuses form-side cascade JS. · `docs/reference/page_filters.md#cascading-associations-depends_on` `docs/reference/cascading_selects.md` `docs/design/page_filters_as_virtual_forms.md` `app/controllers/lcp_ruby/resources_controller.rb` `app/assets/javascripts/lcp_ruby/controllers/cascading_selects_controller.js` `app/helpers/lcp_ruby/form_helper.rb`
199
+ - **Chart Axis Titles** — X/Y axis titles (xtitle:, xtitle_key:, ytitle:, ytitle_key:). Literal or i18n key. Not applicable to pie/donut. · `docs/reference/pages.md#chart` `docs/design/chart_widget_multi_series.md` `lib/lcp_ruby/widgets/data_resolver.rb`
200
+ - **Chart Colors** — Default Okabe-Ito 8-color palette; chart-level colors: array; per-series color:. Priority: per-series > colors[index] > palette. · `docs/reference/pages.md#chart` `docs/design/chart_widget_multi_series.md` `lib/lcp_ruby/widgets/chart_palette.rb`
201
+ - **Chart Empty-State Banner** — Localized empty banner when ALL series have zero rows. empty:/empty_key:. link_to: is suppressed. · `docs/reference/pages.md#chart` `docs/design/chart_widget_multi_series.md` `lib/lcp_ruby/widgets/data_resolver.rb` `app/views/lcp_ruby/widgets/_chart.html.erb`
202
+ - **Chart Legend Control** — Legend visibility/position via legend: enum (auto/true/false/top/bottom/left/right). auto is context-aware. · `docs/reference/pages.md#chart` `docs/design/chart_widget_multi_series.md` `lib/lcp_ruby/widgets/data_resolver.rb`
203
+ - **Chart Library Escape Hatch** — Raw Chart.js options passthrough via library:. Deep-merged over platform defaults; has last word. · `docs/reference/pages.md#chart` `docs/design/chart_widget_multi_series.md` `lib/lcp_ruby/widgets/data_resolver.rb`
204
+ - **Chart Line Smoothing** — curve: / points: for line/area charts. curve: false for sharp line; points: true for visible dot markers. · `docs/reference/pages.md#chart` `docs/design/chart_widget_multi_series.md` `lib/lcp_ruby/widgets/data_resolver.rb`
205
+ - **Chart PNG Download** — Chartkick PNG download button (download: true). Captures the canvas only; chart title outside the canvas is not included. · `docs/reference/pages.md#chart` `docs/design/chart_widget_multi_series.md` `lib/lcp_ruby/widgets/data_resolver.rb`
206
+ - **Chart Sort Order** — sort: asc / desc / none / value_asc / value_desc. Default asc for date group_period, none otherwise. value_* sorts by per-category sum for multi-series. · `docs/reference/pages.md#chart` `docs/design/chart_widget_multi_series.md` `lib/lcp_ruby/widgets/data_resolver.rb`
207
+ - **Chart Value Formatting** — Value prefix/suffix/precision/thousands. e.g. prefix: "€", thousands: " ", precision: 0. · `docs/reference/pages.md#chart` `docs/design/chart_widget_multi_series.md` `lib/lcp_ruby/widgets/data_resolver.rb`
208
+ - **Chart Widget** — Chartkick chart (widget type: chart). chart_type:, group_by:, aggregate:, group_period:. Supports line / bar / column / pie / donut / area. Requires chartkick gem. · `docs/reference/pages.md#chart` `docs/guides/dashboards.md#chart` `docs/design/dashboards.md#widget-zone-types` `docs/design/chart_widget_multi_series.md` `lib/lcp_ruby/widgets/data_resolver.rb` `lib/lcp_ruby/widgets/chartkick_check.rb` `lib/lcp_ruby/widgets/chart_palette.rb` `lib/lcp_ruby/widgets/date_grouper.rb`
209
+ - **Chart Y-Axis Bounds** — Y axis min:/max: numeric bounds. Not applicable to pie/donut. · `docs/reference/pages.md#chart` `docs/design/chart_widget_multi_series.md` `lib/lcp_ruby/widgets/data_resolver.rb`
210
+ - **Column Chart Type** — Vertical column chart (chart_type: column). Counterpart to bar (horizontal). Typical business reporting chart. · `docs/reference/pages.md#chart` `docs/design/chart_widget_multi_series.md` `lib/lcp_ruby/widgets/data_resolver.rb` `app/views/lcp_ruby/widgets/_chart.html.erb`
211
+ - **Conditional Zone (visible_when)** — Role/condition gated zone (visible_when: { role: admin }). Evaluated before data queries. Works on all page types. · `docs/reference/pages.md#conditional-zone-visibility` `docs/guides/dashboards.md#conditional-zones` `docs/design/dashboards.md#configuration-behavior` `app/helpers/lcp_ruby/dashboard_helper.rb` `app/views/lcp_ruby/resources/_grid_page.html.erb`
212
+ - **Dashboard Page (Grid Layout)** — Standalone grid page (layout: grid). pages/*.yml zones: array. KPI cards, text, list, presenter, chart widgets. · `docs/reference/pages.md#grid-positioning` `docs/guides/dashboards.md#grid-layout` `docs/design/dashboards.md#grid-layout` `app/helpers/lcp_ruby/dashboard_helper.rb` `app/views/lcp_ruby/resources/_grid_page.html.erb`
213
+ - **Date Range Filter** — input_type: date_range on filter form. Two date inputs, gteq/lteq translation via ScopeApplicator. · `docs/reference/page_filters.md#date-range-input_type-date_range` `docs/design/page_filters_as_virtual_forms.md` `lib/lcp_ruby/widgets/scope_applicator.rb`
214
+ - **Embed Widget** — Iframe BI embed (widget type: embed). provider:, resource_type:, resource_id:. Metabase/Grafana JWT auth. _(beta)_ · `docs/reference/pages.md#embed-widget` `docs/guides/composite-pages.md#embedding-external-dashboards` `docs/design/dashboards.md#dashboard-with-external-bi-embed-tier-3` `app/controllers/lcp_ruby/dialogs_controller.rb` `app/assets/javascripts/lcp_ruby/controllers/dialog_controller.js` `app/views/lcp_ruby/dialogs/_dialog_frame.html.erb`
215
+ - **Filter Auto-Submit Derivation** — auto_submit: derive | true | false. Derives Apply button vs auto-submit from filter_form shape (multi: / depends_on:). · `docs/reference/page_filters.md#auto_submit-derivation` `docs/design/page_filters_as_virtual_forms.md` `lib/lcp_ruby/pages/filter_form.rb`
216
+ - **Grid CSS Positioning** — Zone placement (position: { row:, col:, width:, height: }). 12-column CSS grid. Zones span multiple cols/rows. · `docs/reference/pages.md#grid-positioning` `docs/guides/dashboards.md#grid-layout` `docs/design/dashboards.md#grid-layout` `app/helpers/lcp_ruby/dashboard_helper.rb` `app/views/lcp_ruby/resources/_grid_page.html.erb`
217
+ - **KPI Card Widget** — Aggregate metric card (widget type: kpi_card). model:, aggregate:, scope:, icon:, link_to:. In page zones. · `docs/reference/pages.md#kpi_card` `docs/guides/dashboards.md#kpi-card` `docs/design/dashboards.md#widget-zone-types` `lib/lcp_ruby/widgets/data_resolver.rb`
218
+ - **KPI Trend Indicator** — KPI with delta arrow (compare_scope: on kpi_card). Shows percentage change vs comparison scope. Up/down/neutral. · `docs/reference/pages.md#kpi_card` `docs/guides/dashboards.md#kpi-trend-indicators` `docs/design/dashboards.md#widget-zone-types` `lib/lcp_ruby/widgets/data_resolver.rb`
219
+ - **Landing Page Configuration** — Post-login redirect (config.landing_page = { role => slug }). Per-role landing pages with default fallback. · `docs/reference/pages.md#page-attributes` `docs/guides/dashboards.md#3-configure-landing-page-optional` `docs/design/dashboards.md#dashboard-as-landing-page` `app/helpers/lcp_ruby/dashboard_helper.rb` `app/views/lcp_ruby/resources/_grid_page.html.erb`
220
+ - **List Widget** — Compact record list (widget type: list). model:, limit:, link_to:. Shows label_method values in a list. · `docs/reference/pages.md#list` `docs/guides/dashboards.md#list` `docs/design/dashboards.md#widget-zone-types` `lib/lcp_ruby/widgets/data_resolver.rb`
221
+ - **Multi-Select Filter** — input_options.multi: true on filter form fields. URL emits bracket-array (?page_filter[field][]=…). Defensive Type::ArrayOf coercion. · `docs/reference/page_filters.md#multi-select-multi-true` `docs/reference/virtual_forms.md#security-invariants` `docs/design/page_filters_as_virtual_forms.md` `lib/lcp_ruby/virtual_fields/types/array_of.rb` `lib/lcp_ruby/pages/filter_form.rb`
222
+ - **Multi-Series Chart** — Multiple data series in one chart (series: array). Each series has its own name, color, scope, and may override group_by/aggregate. · `docs/reference/pages.md#chart` `docs/design/chart_widget_multi_series.md` `lib/lcp_ruby/widgets/data_resolver.rb`
223
+ - **Page Filter Form** — Page-level filter bar (filter_form: array, form-syntax fields). Propagated to all zones via ScopeApplicator. Supports text, select, multi-select, association_select, date_range, boolean, … · `docs/reference/page_filters.md` `docs/reference/pages.md#page-filters` `docs/design/page_filters_as_virtual_forms.md` `lib/lcp_ruby/pages/filter_form.rb` `lib/lcp_ruby/pages/filter_form_validator.rb` `lib/lcp_ruby/widgets/scope_applicator.rb` `app/views/lcp_ruby/resources/_filter_form.html.erb`
224
+ - **Presenter Zone on Dashboard** — Embedded index table in dashboard grid (presenter:, limit:). Reuses existing presenter columns. No widget config. · `docs/reference/pages.md#presenter-zones` `docs/guides/dashboards.md#presenter-zone` `docs/design/dashboards.md#widget-zone-types` `lib/lcp_ruby/widgets/presenter_zone_resolver.rb`
225
+ - **Scope Filters** — Page-level AR-scope toggle bar (scope_filters: array). Each entry maps UI options to named scopes on the page model. widget: select/radio/button_group. · `docs/reference/page_filters.md#scope_filters-syntax` `docs/design/page_filters_as_virtual_forms.md` `lib/lcp_ruby/pages/scope_filter_set.rb` `lib/lcp_ruby/widgets/scope_applicator.rb` `app/views/lcp_ruby/resources/_scope_filters.html.erb`
226
+ - **Stacked Chart** — Stack series on the Y axis (stacked: true). Legal for column/bar/line/area; hard error for pie/donut. · `docs/reference/pages.md#chart` `docs/design/chart_widget_multi_series.md` `lib/lcp_ruby/widgets/data_resolver.rb`
227
+ - **Text Widget** — Static i18n content (widget type: text, content_key:). For welcome messages, announcements on dashboard pages. · `docs/reference/pages.md#text` `docs/guides/dashboards.md#text` `docs/design/dashboards.md#widget-zone-types` `app/helpers/lcp_ruby/dashboard_helper.rb` `app/views/lcp_ruby/resources/_grid_page.html.erb`
228
+
229
+ ## Dialogs
230
+
231
+ - **Composite Dialog Page** — Multi-zone dialog (page dialog: { size: }). Form + sidebar/below zones in one dialog. All zones render inline. · `docs/reference/dialogs.md#composite-dialog-pages` `docs/reference/pages.md#composite-dialog-pages` `docs/guides/dialogs.md#composite-dialog-pages` `docs/design/modal_dialogs.md#configuration-behavior` `app/controllers/lcp_ruby/dialogs_controller.rb` `app/assets/javascripts/lcp_ruby/controllers/dialog_controller.js` `app/views/lcp_ruby/dialogs/_dialog_frame.html.erb`
232
+ - **Composite Dialog: Sidebar with record_source** — Dialog sidebar showing context (record_source: { param: }). Loaded from defaults: { field: `:record.id` }. · `docs/reference/dialogs.md#composite-dialog-pages` `docs/reference/pages.md#record-source-zones` `docs/guides/dialogs.md#composite-dialog-pages` `docs/design/modal_dialogs.md#configuration-behavior` `lib/lcp_ruby/widgets/record_source_resolver.rb`
233
+ - **Dialog Nesting (Max 2 Levels)** — Nested dialog on top of primary (max 2 levels). on_success: :reload re-fetches primary. :close closes nested only. · `docs/reference/dialogs.md#dialog-nesting` `docs/guides/dialogs.md#dialog-nesting` `docs/design/modal_dialogs.md#d7-no-nesting-in-tier-1` `app/controllers/lcp_ruby/dialogs_controller.rb` `app/assets/javascripts/lcp_ruby/controllers/dialog_controller.js` `app/views/lcp_ruby/dialogs/_dialog_frame.html.erb`
234
+ - **Dialog Sizing** — Four dialog sizes (dialog size: :small|:medium|:large|:fullscreen). 400/600/800/95vw. Centered with backdrop. · `docs/reference/dialogs.md#dialog-config-object` `docs/reference/pages.md#dialog-configuration` `docs/design/modal_dialogs.md#dialog-config-properties` `app/controllers/lcp_ruby/dialogs_controller.rb` `app/assets/javascripts/lcp_ruby/controllers/dialog_controller.js` `app/views/lcp_ruby/dialogs/_dialog_frame.html.erb`
235
+ - **Dual-Use Presenter (Page + Dialog)** — Same presenter as standalone page and dialog. Dialog renders form portion; page renders full CRUD. No duplication. · `docs/reference/dialogs.md#dialog-routing` `docs/guides/dialogs.md#dual-use-presenter` `docs/design/modal_dialogs.md#dual-use-presenter-page-and-dialog` `app/controllers/lcp_ruby/dialogs_controller.rb` `app/assets/javascripts/lcp_ruby/controllers/dialog_controller.js` `app/views/lcp_ruby/dialogs/_dialog_frame.html.erb`
236
+ - **Page-Based Confirmation Dialog** — Full form before action (confirm: { page: `dialog_name` }). Virtual model validates, confirmation_data[] forwarded. · `docs/reference/dialogs.md#page-based-confirmation` `docs/guides/dialogs.md#page-based-confirmation-dialog` `docs/design/modal_dialogs.md#confirmation-dialog-lightweight-no-page-needed` `app/controllers/lcp_ruby/dialogs_controller.rb` `app/assets/javascripts/lcp_ruby/controllers/dialog_controller.js` `app/views/lcp_ruby/dialogs/_dialog_frame.html.erb`
237
+ - **Presenter-Driven Dialog** — Dialog form via presenter (dialog size:, title_key:). Served at /lcp_dialog/:page/new. No slug needed. · `docs/reference/dialogs.md#dialog-action-configuration` `docs/reference/pages.md#dialog-only-pages` `docs/design/modal_dialogs.md#dialog-only-presenter-most-common-case` `app/controllers/lcp_ruby/dialogs_controller.rb` `app/assets/javascripts/lcp_ruby/controllers/dialog_controller.js` `app/views/lcp_ruby/dialogs/_dialog_frame.html.erb`
238
+ - **Quick Create Dialog** — Collection-level dialog create (type: :dialog, on: :collection). Minimal form, on_success: :reload. No slug needed. · `docs/reference/dialogs.md#dialog-action-configuration` `docs/guides/dialogs.md#quick-create-dialog` `docs/design/modal_dialogs.md#quick-create-real-model-in-dialog` `app/controllers/lcp_ruby/dialogs_controller.rb` `app/assets/javascripts/lcp_ruby/controllers/dialog_controller.js` `app/views/lcp_ruby/dialogs/_dialog_frame.html.erb`
239
+ - **Quick Note Dialog (Virtual Model)** — Virtual model dialog (table_name: `_virtual`). Validates but never persists. Per-row action from another presenter. · `docs/reference/dialogs.md#virtual-model-dialog-flow` `docs/guides/dialogs.md#virtual-model-dialog` `docs/design/modal_dialogs.md#virtual-model-dialog-no-persistence` `app/controllers/lcp_ruby/dialogs_controller.rb` `app/assets/javascripts/lcp_ruby/controllers/dialog_controller.js` `app/views/lcp_ruby/dialogs/_dialog_frame.html.erb`
240
+ - **Resource Dialog (?_dialog=1)** — Open any resource as dialog (?_dialog=1). type: :dialog action, record: :current. Reuses existing controller/form. · `docs/reference/dialogs.md#dialog-routing` `docs/reference/pages.md#dialog-configuration` `docs/design/modal_dialogs.md#submit-flow-two-routing-paths` `app/controllers/lcp_ruby/dialogs_controller.rb` `app/assets/javascripts/lcp_ruby/controllers/dialog_controller.js` `app/views/lcp_ruby/dialogs/_dialog_frame.html.erb`
241
+ - **Saved Filter Dialog** — Save filter presenter dialog with visible_when conditions. beforeSubmit JS hook injects condition_tree params. · `docs/reference/dialogs.md#dialog-action-configuration` `docs/guides/dialogs.md#quick-create-dialog` `docs/design/modal_dialogs.md#replacing-the-hardcoded-saved-filter-dialog` `app/controllers/lcp_ruby/dialogs_controller.rb` `app/assets/javascripts/lcp_ruby/controllers/dialog_controller.js` `app/views/lcp_ruby/dialogs/_dialog_frame.html.erb`
242
+ - **Simple Browser Confirm** — Native browser confirm (confirm: true or confirm: `message`). Simplest one-line confirmation. · `docs/reference/dialogs.md#simple-boolean` `docs/reference/dialogs.md#confirm-dialog-variants` `docs/design/modal_dialogs.md#confirmation-dialog-lightweight-no-page-needed` `app/controllers/lcp_ruby/dialogs_controller.rb` `app/assets/javascripts/lcp_ruby/controllers/dialog_controller.js` `app/views/lcp_ruby/dialogs/_dialog_frame.html.erb`
243
+ - **Styled Confirmation Dialog** — Custom confirm prompt (confirm: { title_key:, message_key:, style: :danger }). Platform dialog, not browser native. · `docs/reference/dialogs.md#styled-confirmation` `docs/guides/dialogs.md#styled-confirmation-dialog` `docs/design/modal_dialogs.md#confirmation-dialog-lightweight-no-page-needed` `app/controllers/lcp_ruby/dialogs_controller.rb` `app/assets/javascripts/lcp_ruby/controllers/dialog_controller.js` `app/views/lcp_ruby/dialogs/_dialog_frame.html.erb`
244
+
245
+ ## Display Types
246
+
247
+ - **Attachment Display Types** — File renderers (renderer: attachment_preview/list/link). variant:. presenters/*.yml show fields. · `docs/guides/display-types.md#image` `docs/guides/display-types.md#avatar` `docs/guides/attachments.md#display-configuration` `docs/guides/attachments.md#attachment_preview` `docs/guides/attachments.md#attachment_list` `docs/guides/attachments.md#attachment_link` `docs/reference/presenters.md#attachment_preview` `docs/reference/presenters.md#attachment_list` `docs/reference/presenters.md#attachment_link` `lib/lcp_ruby/display/renderers/attachment_preview.rb` `lib/lcp_ruby/display/renderers/attachment_list.rb` `lib/lcp_ruby/display/renderers/attachment_link.rb` `lib/lcp_ruby/display/renderers/image.rb` `lib/lcp_ruby/display/renderers/avatar.rb`
248
+ - **Badge Display** — Colored pill renderer (renderer: badge). color_map: per value. presenters/*.yml column options. · `docs/guides/display-types.md#badge` `docs/reference/presenters.md#badge` `lib/lcp_ruby/display/renderers/badge.rb`
249
+ - **Boolean Icon Display** — Yes/No colored text (renderer: boolean_icon). true_icon:, false_icon:. presenters/*.yml columns. · `docs/guides/display-types.md#boolean_icon` `docs/reference/presenters.md#boolean_icon` `lib/lcp_ruby/display/renderers/boolean_icon.rb`
250
+ - **Code Display** — Monospace <code> rendering (renderer: code). For UUIDs, JSON, IDs. presenters/*.yml columns/show. · `docs/guides/display-types.md#code` `docs/reference/presenters.md#code` `lib/lcp_ruby/display/renderers/code.rb`
251
+ - **Collection Display** — Array value renderer (renderer: collection). separator:, limit:, item_renderer:. presenters/*.yml. · `docs/guides/display-types.md#collection-renderer` `docs/reference/presenters.md#collection-renderer` `lib/lcp_ruby/display/renderers/collection.rb`
252
+ - **Color Swatch Display** — Colored square preview (renderer: color_swatch). Safe CSS validation. presenters/*.yml columns. · `docs/guides/display-types.md#color_swatch` `docs/reference/presenters.md#color_swatch` `lib/lcp_ruby/display/renderers/color_swatch.rb`
253
+ - **Currency Display** — Money formatter (renderer: currency). currency:, precision:. presenters/*.yml column options. · `docs/guides/display-types.md#currency` `docs/reference/presenters.md#currency` `lib/lcp_ruby/display/renderers/currency.rb`
254
+ - **Email / Phone / URL Link Displays** — Clickable links (renderer: email_link/phone_link/url_link). mailto:, tel:, external. presenters/*.yml. · `docs/guides/display-types.md#email_link` `docs/guides/display-types.md#phone_link` `docs/guides/display-types.md#url_link` `docs/reference/presenters.md#email_link` `docs/reference/presenters.md#phone_link` `docs/reference/presenters.md#url_link` `lib/lcp_ruby/display/renderers/email_link.rb` `lib/lcp_ruby/display/renderers/phone_link.rb` `lib/lcp_ruby/display/renderers/url_link.rb`
255
+ - **Heading Display** — Bold <strong> text (renderer: heading). link_to: show for clickable. presenters/*.yml columns. · `docs/guides/display-types.md#heading` `docs/reference/presenters.md#heading` `lib/lcp_ruby/display/renderers/heading.rb`
256
+ - **Internal Link Display** — In-app link (renderer: internal_link). label: custom text. presenters/*.yml column options. · `docs/guides/display-types.md#internal_link` `docs/reference/presenters.md#internal_link` `lib/lcp_ruby/display/renderers/internal_link.rb`
257
+ - **Markdown Display** — GFM-to-HTML renderer (renderer: markdown). Commonmarker-based. presenters/*.yml show fields. · `docs/guides/display-types.md#rich_text` `docs/reference/presenters.md#rich_text` `lib/lcp_ruby/display/renderers/markdown.rb`
258
+ - **Number / Percentage / File Size Displays** — Numeric formatters (renderer: number/percentage/file_size). precision:. presenters/*.yml columns. · `docs/guides/display-types.md#number` `docs/guides/display-types.md#percentage` `docs/guides/display-types.md#file_size` `docs/reference/presenters.md#number` `docs/reference/presenters.md#percentage` `docs/reference/presenters.md#file_size` `lib/lcp_ruby/display/renderers/number.rb` `lib/lcp_ruby/display/renderers/percentage.rb` `lib/lcp_ruby/display/renderers/file_size.rb`
259
+ - **Progress Bar Display** — Visual bar (renderer: progress_bar). max: default 100. presenters/*.yml column options. · `docs/guides/display-types.md#progress_bar` `docs/reference/presenters.md#progress_bar` `lib/lcp_ruby/display/renderers/progress_bar.rb`
260
+ - **Rating Display** — Star rating renderer (renderer: rating). max: configurable. presenters/*.yml column options. · `docs/guides/display-types.md#rating` `docs/reference/presenters.md#rating` `lib/lcp_ruby/display/renderers/rating.rb`
261
+ - **Relative Date Display** — Human-readable time ago (renderer: relative_date). '3 days ago' style. presenters/*.yml columns. · `docs/guides/display-types.md#relative_date` `docs/reference/presenters.md#relative_date` `lib/lcp_ruby/display/renderers/relative_date.rb`
262
+ - **Truncate Display** — Ellipsis text overflow (renderer: truncate). max: char limit, tooltip on hover. presenters/*.yml. · `docs/guides/display-types.md#truncate` `docs/reference/presenters.md#truncate` `lib/lcp_ruby/display/renderers/truncate.rb`
263
+
264
+ ## Export
265
+
266
+ - **Association Field Expansion** — Dot-path fields for belongs_to/has_one (e.g. department.name). Max depth 3, auto eager-loading. · `docs/reference/export.md#dot-path-fields` `docs/guides/export.md#association-fields` `docs/design/export.md#recursive-belongs_tohas_one-field-resolution` `lib/lcp_ruby/export/`
267
+ - **Batch Export** — Export selected records via batch toolbar. Explicit IDs or filter mode. Session token for large sets. · `docs/reference/export.md#batch-export` `docs/guides/export.md` `docs/design/export.md#d13-unified-export-covers-both-collection-and-batch` `docs/design/batch_action_export.md` `lib/lcp_ruby/export/`
268
+ - **CSV Export** — CSV with UTF-8 BOM (export formats: [:csv]). Configurable delimiter (csv_delimiter: `;`). · `docs/reference/export.md#csv-format` `docs/guides/export.md` `docs/design/export.md#csv-generation` `docs/design/export.md#d14-csv-encoding-utf-8-with-bom` `lib/lcp_ruby/export/`
269
+ - **Collection Export** — Toolbar export button with dialog (export formats: [:csv, :xlsx]). Field picker, format choice, filters. · `docs/reference/export.md#collection-export` `docs/guides/export.md#basic-setup` `docs/design/export.md#enabling-export-on-a-presenter` `lib/lcp_ruby/export/`
270
+ - **Export Column Headers (i18n)** — i18n headers (lcp_ruby.export.headers.<model>.<path>). Humanized fallback. Dot-path segments joined. · `docs/reference/export.md#column-headers-i18n` `docs/guides/export.md#custom-column-headers` `docs/design/export.md#column-headers` `lib/lcp_ruby/export/`
271
+ - **Export Dialog** — Built-in dialog with Stimulus controller (lcp-export-dialog). Fetch-based download, no page reload. · `docs/reference/export.md#export-dialog` `docs/guides/export.md` `docs/design/export.md#export-dialog` `docs/design/export.md#dialog-ui-layout` `lib/lcp_ruby/export/`
272
+ - **Export Formatting Options** — Per-type formatting: enum_mode, date_format, boolean_mode, decimal_separator. Saved with profiles. · `docs/reference/export.md#formatting-options` `docs/guides/export.md#formatting-options` `docs/design/export.md#field-value-formatting` `docs/design/export.md#d15-field-value-formatting-is-configurable` `lib/lcp_ruby/export/`
273
+ - **Export Generator** — Generator: lcp_ruby:export. Creates export_profile + export_log models, presenters, permissions. · `docs/reference/export.md#generator` `docs/design/export.md#generator` `lib/lcp_ruby/export/`
274
+ - **Export History** — Log exports (save_history: true). export_log model with fields, filters, file attachment, user. · `docs/reference/export.md#export-history` `docs/guides/export.md#export-history` `docs/design/export.md#export_log-export-history-with-file-attachment` `docs/design/export.md#d3-export_log-is-opt-in` `lib/lcp_ruby/export/`
275
+ - **Export Max Records** — Safety limit (export max_records: 5000). COUNT check before loading. Dialog error if exceeded. · `docs/reference/export.md` `docs/guides/export.md#max-records` `docs/design/export.md#max_records-enforcement` `lib/lcp_ruby/export/`
276
+ - **Export Profiles** — Save/reuse field selections (export_profile model). Visibility: personal/role/global. Stale field detection. · `docs/reference/export.md#export-profiles` `docs/guides/export.md#saved-profiles` `docs/design/export.md#export_profile-saved-field-selections-reusable` `docs/design/export.md#d11-profile-visibility-personal-role-global` `lib/lcp_ruby/export/`
277
+ - **Export Sort Preservation** — Exported file preserves current sort order. Sort params passed via URL to export handler. · `docs/reference/export.md` `docs/guides/export.md#filter-and-sort-preservation` `docs/design/export.md#d18-sort-order-preserved` `lib/lcp_ruby/export/`
278
+ - **Export with Filters** — Collection export preserves current filter/sort state. Exported file matches screen (minus pagination). · `docs/reference/export.md` `docs/guides/export.md#filter-and-sort-preservation` `docs/design/export.md#passing-current-filters-and-sort-to-the-dialog` `docs/design/export.md#d8-filters-passed-via-url-params` `lib/lcp_ruby/export/`
279
+ - **Export with Soft Delete** — Active view exports non-discarded. Archive exports discarded. Batch explicit exports selected IDs. · `docs/reference/export.md#soft-delete-integration` `docs/guides/export.md#soft-delete-integration` `docs/design/export.md#d17-soft-delete-follows-presenter-scope` `lib/lcp_ruby/export/`
280
+ - **Field Ceiling** — Restrict export fields (export fields: [...]). Permission ceiling further filtered by readable_fields. · `docs/reference/export.md#fields-ceiling-and-fk-mapping` `docs/guides/export.md#field-ceiling` `docs/design/export.md#export-fields-what-appears-in-the-field-picker` `docs/design/export.md#d10-export-section-as-optional-ceiling` `lib/lcp_ruby/export/`
281
+ - **Field Picker** — Checkbox tree for field selection. Expandable association groups, recursive depth 3, dot-path notation. · `docs/reference/export.md#field-picker` `docs/design/export.md#1-field_picker-input-type` `docs/design/export.md#d7-field-picker-is-a-platform-input-type` `lib/lcp_ruby/export/`
282
+ - **Permission-Filtered Export** — Export respects permissions: action, field-level, association-level, record-level (policy_scope). · `docs/reference/export.md#permissions` `docs/guides/export.md#basic-setup` `docs/design/export.md#permission-integration` `lib/lcp_ruby/export/`
283
+ - **XLSX Export** — Excel export (export formats: [:xlsx]). Requires caxlsx gem. Bold headers, auto column width. · `docs/reference/export.md#xlsx-format` `docs/guides/export.md#xlsx-support` `docs/design/export.md#xlsx-generation` `docs/design/export.md#d4-xlsx-as-optional-dependency` `lib/lcp_ruby/export/`
284
+
285
+ ## Extensibility
286
+
287
+ - **Built-in Condition Service — `feature_flag`** — Returns true when a named feature flag is on. Default backend reads `LcpRuby.configuration.feature_flags`; hosts can swap in their own backend. · `docs/reference/menu.md#conditional-visibility` `docs/design/user-menu.md` `lib/lcp_ruby/condition_services/feature_flag.rb`
288
+ - **Built-in Condition Service — `impersonating`** — Returns true when the current user is wrapped in `LcpRuby::ImpersonatedUser`. Use to gate "Stop impersonating" menu items / impersonation banner. · `docs/reference/menu.md#conditional-visibility` `docs/design/user-menu.md` `lib/lcp_ruby/condition_services/impersonating.rb`
289
+ - **Condition DSL Builder** — Ruby DSL for conditions: field(:name).eq/gt/present, all/any/not_condition/collection blocks. · `docs/guides/extensibility.md#condition-services` `lib/lcp_ruby/dsl/condition_builder.rb` `lib/lcp_ruby/condition_evaluator.rb`
290
+ - **Condition Services** — Custom Ruby evaluators for visible_when/disable_when. app/condition_services/. Returns boolean. · `docs/guides/extensibility.md#condition-services` `lib/lcp_ruby/condition_service_registry.rb` `lib/lcp_ruby/condition_evaluator.rb`
291
+ - **Custom Actions** — Host-app Ruby action classes (type: custom). app/actions/ directory. ActionRegistry. · `docs/guides/custom-actions.md#custom-actions` `docs/guides/extensibility.md#custom-actions` `docs/guides/custom-actions.md#creating-an-action` `docs/guides/custom-actions.md#registering-the-action-in-yaml` `lib/lcp_ruby/actions/base_action.rb` `lib/lcp_ruby/actions/action_executor.rb` `lib/lcp_ruby/actions/action_registry.rb` `lib/lcp_ruby/actions/form_action_pipeline.rb`
292
+ - **Custom Display Renderers** — Host-app renderer classes. app/renderers/ directory. Extends Display::BaseRenderer. Auto-discovered. · `docs/guides/custom-renderers.md#custom-renderers` `docs/guides/custom-renderers.md#creating-a-custom-renderer` `docs/guides/custom-renderers.md#auto-discovery` `lib/lcp_ruby/display/base_renderer.rb` `lib/lcp_ruby/display/renderer_registry.rb`
293
+ - **Dev Metadata Reload (Auto-Watch)** — ActiveSupport::FileUpdateChecker against config/lcp_ruby/. YAML/DSL edits auto-trigger Engine.reload! on the next request. Dev only (enable_reloading). · `docs/getting-started.md#dev-workflow` `docs/reference/boot_lifecycle.md` `docs/design/boot_reload_lifecycle.md` `lib/lcp_ruby/engine.rb`
294
+ - **Event Handlers** — Lifecycle callbacks (after_create, after_update). app/event_handlers/ directory. Events::BaseHandler. · `docs/guides/event-handlers.md#event-handlers` `docs/guides/extensibility.md#event-handlers` `docs/guides/event-handlers.md#creating-a-handler` `docs/guides/event-handlers.md#async-handlers` `lib/lcp_ruby/events/handler_base.rb` `lib/lcp_ruby/events/dispatcher.rb` `lib/lcp_ruby/events/handler_registry.rb` `lib/lcp_ruby/events/async_handler_job.rb`
295
+ - **LcpRuby.on_models_loaded Hook** — Boot/reload hook: register a block that fires inside Engine.load_metadata! after every dynamic model is built. Persistent across reloads. · `docs/guides/extensibility.md#hook-timing` `docs/reference/boot_lifecycle.md` `docs/design/authorization_hardening.md#boot-lifecycle-lcprubyon_models_loaded-new-hook` `docs/design/boot_reload_lifecycle.md` `lib/lcp_ruby.rb` `lib/lcp_ruby/engine.rb`
296
+ - **Value Services (Parameterized)** — Computed values for condition comparisons. service: key + params:. app/condition_services/ directory. · `docs/guides/extensibility.md#dynamic-defaults` `docs/guides/extensibility.md#computed-fields` `docs/guides/extensibility.md#service-validators` `lib/lcp_ruby/services/registry.rb` `lib/lcp_ruby/services/checker.rb` `lib/lcp_ruby/services/built_in_defaults.rb` `lib/lcp_ruby/services/built_in_transforms.rb`
297
+ - **Virtual Forms (Synthetic Form Objects)** — LcpRuby::VirtualFields::VirtualField + VirtualForm + Type::ArrayOf. Per-request AM::API class for non-AR-backed forms. · `docs/reference/virtual_forms.md` `docs/reference/page_filters.md` `docs/design/page_filters_as_virtual_forms.md` `lib/lcp_ruby/virtual_fields/virtual_field.rb` `lib/lcp_ruby/virtual_fields/virtual_form.rb` `lib/lcp_ruby/virtual_fields/types/array_of.rb` `lib/lcp_ruby/virtual_fields/synthetic_marker.rb`
298
+
299
+ ## Field Types
300
+
301
+ - **Array Field (Float)** — Multi-value floats (type: array, item_type: float). Cast to float on save. DSL field block. · `docs/reference/models.md#array-fields` `docs/reference/models.md#item_type` `docs/design/array_field_type.md` `lib/lcp_ruby/model_factory/array_type_applicator.rb` `lib/lcp_ruby/model_factory/array_type.rb`
302
+ - **Array Field (Integer)** — Multi-value integers (type: array, item_type: integer). array_inclusion validates. DSL field block. · `docs/reference/models.md#array-fields` `docs/reference/models.md#item_type` `docs/design/array_field_type.md` `lib/lcp_ruby/model_factory/array_type_applicator.rb` `lib/lcp_ruby/model_factory/array_type.rb`
303
+ - **Array Field (String)** — Multi-value strings (type: array, item_type: string). Chip input. DSL field block or models/*.yml. · `docs/reference/models.md#array-fields` `docs/reference/models.md#item_type` `docs/design/array_field_type.md` `lib/lcp_ruby/model_factory/array_type_applicator.rb` `lib/lcp_ruby/model_factory/array_type.rb`
304
+ - **Attachment Field** — File upload (type: attachment). mode:, max_size:, content_types:, variants:. models/*.yml fields. · `docs/reference/models.md#attachment-fields` `docs/guides/attachments.md#defining-attachment-fields` `docs/guides/attachments.md#single-attachment` `docs/guides/attachments.md#multiple-attachments` `docs/guides/attachments.md#validation-options` `lib/lcp_ruby/model_factory/attachment_applicator.rb`
305
+ - **Boolean Field** — True/false flag (type: boolean). default: true/false. models/*.yml fields section. · `docs/reference/models.md#type` `lib/lcp_ruby/model_factory/schema_manager.rb`
306
+ - **Color Type** — Hex color value (type: color). Validates #rrggbb, shows swatch preview. models/*.yml fields. · `docs/reference/types.md#built-in-types` `docs/guides/custom-types.md#example-d-hex_color-dsl` `lib/lcp_ruby/types/built_in_types.rb`
307
+ - **Date / DateTime Field** — Calendar date or timestamp (type: date/datetime). strftime format. models/*.yml fields section. · `docs/reference/models.md#type` `docs/guides/display-types.md#date` `docs/guides/display-types.md#datetime` `lib/lcp_ruby/model_factory/schema_manager.rb`
308
+ - **Decimal / Float Field** — Decimal number (type: decimal/float). precision:, scale:. models/*.yml fields section. · `docs/reference/models.md#type` `lib/lcp_ruby/model_factory/schema_manager.rb`
309
+ - **Email Type** — Auto-validated email (type: email). Downcase+strip transform. models/*.yml fields section. · `docs/reference/types.md#built-in-types` `docs/reference/models.md#type` `lib/lcp_ruby/types/built_in_types.rb`
310
+ - **Enum Field** — Predefined value list (type: enum). values:, default:. models/*.yml fields section. · `docs/reference/models.md#type` `docs/reference/models.md#enum_values` `lib/lcp_ruby/model_factory/schema_manager.rb`
311
+ - **Integer Field** — Whole number (type: integer). default:, min:, max:. models/*.yml fields section. · `docs/reference/models.md#type` `lib/lcp_ruby/model_factory/schema_manager.rb`
312
+ - **JSON Field** — Arbitrary JSON data (type: json). Edited as textarea, displayed as code block. models/*.yml fields. · `docs/reference/models.md#type` `docs/reference/presenters.md#json-field-source-inline` `docs/reference/presenters.md#json-field-source-model-backed` `lib/lcp_ruby/model_factory/schema_manager.rb`
313
+ - **Phone Type** — Auto-validated phone (type: phone). normalize_phone transform. models/*.yml fields section. · `docs/reference/types.md#built-in-types` `docs/reference/models.md#type` `lib/lcp_ruby/types/built_in_types.rb`
314
+ - **Rich Text Field** — HTML content via Action Text (type: rich_text). Trix editor in forms. models/*.yml fields section. · `docs/reference/models.md#type` `docs/guides/display-types.md#rich_text` `lib/lcp_ruby/model_factory/schema_manager.rb`
315
+ - **String Field** — Short text (type: string). limit:, null:. models/*.yml fields section. · `docs/reference/models.md#type` `lib/lcp_ruby/model_factory/schema_manager.rb`
316
+ - **Text Field** — Unlimited-length text (type: text). models/*.yml fields section. · `docs/reference/models.md#type` `lib/lcp_ruby/model_factory/schema_manager.rb`
317
+ - **URL Type** — Auto-validated URL (type: url). normalize_url adds https://. models/*.yml fields section. · `docs/reference/types.md#built-in-types` `docs/reference/models.md#type` `lib/lcp_ruby/types/built_in_types.rb`
318
+ - **UUID Field** — Unique identifier string (type: uuid). Displayed with code formatting. models/*.yml fields section. · `docs/reference/models.md#type` `lib/lcp_ruby/model_factory/schema_manager.rb`
319
+
320
+ ## Form
321
+
322
+ - **Cascade Accessibility (a11y)** — aria-busy during AJAX rebuild, aria-live announcement on options-updated, focus restoration after Tom Select rebuild. · `docs/reference/cascading_selects.md` `docs/design/page_filters_as_virtual_forms.md#cascade-ux-accessibility` `app/assets/javascripts/lcp_ruby/controllers/cascading_selects_controller.js`
323
+ - **Cascading Selects** — Dependent dropdowns (depends_on:). Parent change reloads child options. presenters/*.yml form field. · `docs/reference/presenters.md#how-association-selects-work` `docs/guides/selectbox.md#cascading-dependent-selects` `docs/guides/selectbox.md#two-level-cascade` `docs/guides/selectbox.md#three-level-cascade` `docs/guides/selectbox.md#depends_on-options` `lib/lcp_ruby/association_options_builder.rb`
324
+ - **Conditional Disable (disable_when)** — Disable fields by other field values (disable_when: {field:, operator:, value:}). Native widget API. presenters/*.yml form fields. · `docs/reference/presenters.md#conditional-disabling` `docs/reference/condition-operators.md#condition-operators-reference` `docs/guides/conditional-rendering.md#disable_when-on-fields` `docs/guides/conditional-rendering.md#form-section-disable_when` `docs/design/unified_condition_operators.md#unified-condition-operators-design-document` `lib/lcp_ruby/condition_evaluator.rb` `lib/lcp_ruby/presenter/layout_builder.rb`
325
+ - **Conditional Visibility (visible_when)** — Show/hide fields by other field values (visible_when: {field:, operator:, value:}). Client-side. presenters/*.yml form fields. · `docs/reference/presenters.md#conditional-visibility` `docs/reference/condition-operators.md#condition-operators-reference` `docs/guides/conditional-rendering.md#visible_when-on-fields` `docs/guides/conditional-rendering.md#section-level-conditions` `docs/design/unified_condition_operators.md#unified-condition-operators-design-document` `lib/lcp_ruby/condition_evaluator.rb` `lib/lcp_ruby/presenter/layout_builder.rb`
326
+ - **Date Range Form Input** — input_type: date_range as general form input. Pairs <field>_from / <field>_to date pickers in a <fieldset>. · `docs/reference/forms.md` `docs/reference/page_filters.md#date-range-input_type-date_range` `docs/design/page_filters_as_virtual_forms.md` `app/helpers/lcp_ruby/form_helper.rb`
327
+ - **Dialog Behavior — show_result** — Render a result partial after dialog form submit (one-time secret display,
328
+ recovery codes, generated credentials). dialog_behavior show_result + result.style. _(beta)_ · `docs/reference/api-tokens.md` `docs/design/api_tokens.md` `app/controllers/concerns/lcp_ruby/dialog_rendering.rb` `app/views/lcp_ruby/dialogs/_show_secret.html.erb`
329
+ - **Field Renderer — copy_code** — Monospace value with inline clipboard-copy button. Reusable in show layouts, dialog result partials, and index cells. _(beta)_ · `docs/reference/api-tokens.md` `docs/design/api_tokens.md` `lib/lcp_ruby/display/renderers/copy_code.rb` `app/assets/javascripts/lcp_ruby/controllers/clipboard_controller.js`
330
+ - **Form-Level Reverse-Cascade Opt-Out** — data-lcp-reverse-cascade="off" on form. Filter forms opt out — child change does NOT auto-fill its parent. · `docs/reference/cascading_selects.md` `docs/reference/page_filters.md` `docs/design/page_filters_as_virtual_forms.md` `app/assets/javascripts/lcp_ruby/controllers/cascading_selects_controller.js`
331
+ - **JSON Field Inline Editing** — Edit JSON fields as key-value pairs inline (type: json, input_type: json_editor). presenters/*.yml form fields. · `docs/reference/presenters.md#json-field-source-inline` `docs/guides/presenters.md#json-field-source-inline` `docs/design/inline_collection_editor.md#3-json-field-source-json_field` `docs/design/inline_collection_editor.md#3a-inline-mode-fields-declared-in-presenter` `lib/lcp_ruby/presenter/layout_builder.rb` `lib/lcp_ruby/controller/crud_helpers.rb`
332
+ - **JSON Field Sub-Sections** — Render JSON keys as separate form sub-sections. presenters/*.yml form section type: json_section. · `docs/reference/presenters.md#sub-sections-in-nested-rows` `docs/guides/presenters.md#sub-sections-in-nested-rows` `docs/design/inline_collection_editor.md#phase-5-sub-sections-in-nested-rows` `lib/lcp_ruby/presenter/layout_builder.rb`
333
+ - **JSON Field with Virtual Model** — Map JSON keys to virtual model fields for typed editing. models/*.yml virtual_attributes + presenters/*.yml. · `docs/reference/presenters.md#json-field-source-model-backed` `docs/guides/presenters.md#json-field-source-model-backed` `docs/design/inline_collection_editor.md#3b-model-backed-mode-fields-from-a-virtual-model` `lib/lcp_ruby/presenter/layout_builder.rb` `lib/lcp_ruby/controller/crud_helpers.rb`
334
+ - **Multi-Column Form Layout** — Side-by-side form fields (columns: 2/3). presenters/*.yml form section layout. · `docs/reference/presenters.md#form-section-attributes` `docs/reference/presenters.md#layout` `docs/guides/presenters.md#flat-vs-tabs-layout` `lib/lcp_ruby/presenter/layout_builder.rb`
335
+ - **Multi-Select Cascade Activation** — render_multi_select honors depends_on (was silent no-op before PR 3). Same JS path as association_select. · `docs/reference/forms.md` `docs/reference/page_filters.md#cascading-associations-depends_on` `docs/design/page_filters_as_virtual_forms.md` `app/helpers/lcp_ruby/form_helper.rb`
336
+ - **Nested Forms** — Inline editing of associations (type: nested, accepts_nested_attributes_for). Sortable rows. presenters/*.yml form sections. · `docs/reference/presenters.md#nested-fields` `docs/reference/presenters.md#association-source` `docs/guides/presenters.md#nested-fields` `docs/guides/presenters.md#association-source-has_many` `docs/design/inline_collection_editor.md#design-inline-collection-editor` `lib/lcp_ruby/presenter/layout_builder.rb` `lib/lcp_ruby/controller/crud_helpers.rb`
337
+ - **Selectbox Sorting** — Sort selectbox options (sort: true/false, sort_direction:). presenters/*.yml form field. · `docs/reference/presenters.md#input-options` `docs/guides/selectbox.md#selectbox-guide` `lib/lcp_ruby/association_options_builder.rb`
338
+ - **has_one Nested Fields in Form** — Inline has_one editing (nested_fields section). Zero or one nested record. Auto-create on save. · `docs/reference/presenters.md#nested-fields` `docs/reference/presenters.md#nested-fields-section-attributes` `docs/guides/presenters.md#nested-fields` `docs/design/inline_collection_editor.md#design-inline-collection-editor` `lib/lcp_ruby/presenter/layout_builder.rb` `lib/lcp_ruby/controller/crud_helpers.rb`
339
+
340
+ ## Form Submit Actions
341
+
342
+ - **Confirmation Dialogs** — Pre-submit confirmation (confirm: true, confirm_message:). data-turbo-confirm or window.confirm. · `docs/guides/action-buttons.md` `docs/reference/workflow.md` `docs/guides/workflow.md#confirmation-dialogs` `docs/design/form_submit_actions.md` `docs/design/workflow_state_machine.md` `lib/lcp_ruby/controller/` `lib/lcp_ruby/workflow/`
343
+ - **Cross-Presenter Redirect** — Navigate to different presenter after save (redirect: { association: :order, action: :show }). · `docs/guides/action-buttons.md` `docs/design/form_submit_actions.md` `lib/lcp_ruby/controller/`
344
+ - **Default Form Actions (Backward Compatibility)** — Default Save + Cancel when no form actions configured. Full backward compatibility. · `docs/guides/action-buttons.md` `docs/design/form_submit_actions.md` `lib/lcp_ruby/presenter/`
345
+ - **Deferred Event Dispatch** — Events deferred until after transaction commit (defer_events: true). Prevents rollback event firing. · `docs/guides/action-buttons.md` `docs/design/form_submit_actions.md` `lib/lcp_ruby/controller/` `lib/lcp_ruby/events/`
346
+ - **Dialog: Save & Close / Save & Add Another** — Dialog-specific behavior (dialog_behavior: :close/:reset/:reload). Reset clears form for next entry. · `docs/guides/action-buttons.md` `docs/design/form_submit_actions.md` `lib/lcp_ruby/controller/`
347
+ - **Double-Submit Protection** — Stimulus controller disables buttons on submit (lcp-form-actions). Re-enables after response/5s timeout. · `docs/guides/action-buttons.md` `docs/design/form_submit_actions.md` `lib/lcp_ruby/controller/`
348
+ - **Form Action i18n** — 4-level i18n lookup: explicit label > presenter-specific > global > humanized name fallback. · `docs/guides/action-buttons.md` `docs/design/form_submit_actions.md` `lib/lcp_ruby/presenter/`
349
+ - **Multiple Submit Buttons** — Multiple form submit buttons (actions: { form: [...] }). Each sends _form_action param. · `docs/guides/action-buttons.md` `docs/design/form_submit_actions.md` `lib/lcp_ruby/presenter/` `lib/lcp_ruby/controller/`
350
+ - **Overflow Dropdown** — Collapse excess buttons into More dropdown (max_inline_actions:). position: :dropdown forces dropdown. · `docs/guides/action-buttons.md` `docs/design/form_submit_actions.md` `lib/lcp_ruby/presenter/`
351
+ - **Pipeline Execution** — Ordered operation list per button (pipeline: [:save, { transition: :submit }]). Single transaction. · `docs/guides/action-buttons.md` `docs/design/form_submit_actions.md` `lib/lcp_ruby/controller/`
352
+ - **Redirect per Button** — Per-button redirect target (redirect: :show/:edit/:new/:index). Falls back to redirect_after. · `docs/guides/action-buttons.md` `docs/design/form_submit_actions.md` `lib/lcp_ruby/controller/`
353
+ - **Role-Restricted Form Actions** — Role-based button visibility (only_roles:, except_roles:). Re-checked at submit time. · `docs/guides/action-buttons.md` `docs/design/form_submit_actions.md` `lib/lcp_ruby/presenter/` `lib/lcp_ruby/authorization/`
354
+ - **Single Action Pipeline (Show Page)** — Pipeline on show page single actions. No save step. Direct transition or custom action execution. · `docs/guides/action-buttons.md` `docs/design/form_submit_actions.md` `lib/lcp_ruby/controller/`
355
+ - **only_on (Create / Update)** — Restrict button to create or update context (only_on: :create/:update). Checked at render + submit. · `docs/guides/action-buttons.md` `docs/design/form_submit_actions.md` `lib/lcp_ruby/presenter/`
356
+ - **set_fields (Field Injection)** — Inject field values on submit (set_fields:). Merged after user params. Same syntax as workflow. · `docs/guides/action-buttons.md` `docs/design/form_submit_actions.md` `lib/lcp_ruby/controller/`
357
+ - **visible_when on Form Actions** — Conditional button visibility (visible_when:). Server-side evaluation against record state. · `docs/guides/action-buttons.md` `docs/design/form_submit_actions.md` `lib/lcp_ruby/presenter/` `lib/lcp_ruby/condition_evaluator.rb`
358
+
359
+ ## Grouped Query
360
+
361
+ - **Grouped Query Mode (query_mode: :grouped)** — GROUP BY index mode (query_mode: :grouped, group_by:). Aggregates: count, sum, avg, min, max. · `docs/design/grouped_query_presenter.md` `docs/reference/presenters.md` `app/helpers/lcp_ruby/grouped_query_helper.rb` `docs/design/grouped_query_presenter.md` `lib/lcp_ruby/grouped_query/`
362
+ - **Grouped Query: Aggregate Functions** — SQL aggregates on columns (aggregate: :count or { function: :sum, field: :amount }). Standard renderers. · `docs/design/grouped_query_presenter.md` `docs/reference/presenters.md` `app/helpers/lcp_ruby/grouped_query_helper.rb` `docs/design/grouped_query_presenter.md` `lib/lcp_ruby/grouped_query/`
363
+ - **Grouped Query: Association Dot-Path JOINs** — Group by association field (group_by: [`category.name`]). Auto-generates LEFT JOIN. · `docs/design/grouped_query_presenter.md` `docs/reference/presenters.md` `app/helpers/lcp_ruby/grouped_query_helper.rb` `docs/design/grouped_query_presenter.md` `lib/lcp_ruby/grouped_query/`
364
+ - **Grouped Query: Date Period Grouping** — Date truncation grouping ({ field:, period: :month }). DATE_TRUNC (PG) or strftime (SQLite). · `docs/design/grouped_query_presenter.md` `docs/reference/presenters.md` `app/helpers/lcp_ruby/grouped_query_helper.rb` `docs/design/grouped_query_presenter.md` `lib/lcp_ruby/grouped_query/`
365
+ - **Grouped Query: HAVING Conditions** — Filter groups by aggregate value (having: { count: { gt: 5 } }). SQL HAVING clause from config. · `docs/design/grouped_query_presenter.md` `docs/reference/presenters.md` `app/helpers/lcp_ruby/grouped_query_helper.rb` `docs/design/grouped_query_presenter.md` `lib/lcp_ruby/grouped_query/`
366
+ - **Grouped Query: LIMIT (Top N Groups)** — Limit grouped results (limit: N on grouped index). Top N groups by sort order. · `docs/design/grouped_query_presenter.md` `docs/reference/presenters.md` `app/helpers/lcp_ruby/grouped_query_helper.rb` `docs/design/grouped_query_presenter.md` `lib/lcp_ruby/grouped_query/`
367
+ - **Grouped Query: Multi-Column Group By** — Group by multiple fields (group_by: [:stage, :region]). Each combination = one row. · `docs/design/grouped_query_presenter.md` `docs/reference/presenters.md` `app/helpers/lcp_ruby/grouped_query_helper.rb` `docs/design/grouped_query_presenter.md` `lib/lcp_ruby/grouped_query/`
368
+ - **Grouped Query: Row Click Filter** — Click grouped row to drill-down (row_click: :filter, target:). Auto-builds Ransack filter params. · `docs/design/grouped_query_presenter.md` `docs/reference/presenters.md` `app/helpers/lcp_ruby/grouped_query_helper.rb` `docs/design/grouped_query_presenter.md` `lib/lcp_ruby/grouped_query/`
369
+ - **Grouped Query: View Group Integration** — Grouped + flat presenters coexist in view groups. Overview (grouped) to detail (flat) drill-through. · `docs/design/grouped_query_presenter.md` `docs/reference/presenters.md` `app/helpers/lcp_ruby/grouped_query_helper.rb` `docs/design/grouped_query_presenter.md` `lib/lcp_ruby/grouped_query/`
370
+
371
+ ## Groups
372
+
373
+ - **DB-Backed Groups (Model)** — Store groups in DB (group_source: :model). Dynamic group management via UI. Generator available. · `docs/reference/groups.md#source-model-db` `docs/reference/groups.md#model-contracts` `docs/guides/groups.md#db-backed-groups` `docs/design/groups_roles_and_org_structure.md` `lib/lcp_ruby/groups/model_loader.rb` `lib/lcp_ruby/groups/contract.rb` `lib/lcp_ruby/groups/contract_validator.rb`
374
+ - **Group Cache Invalidation** — Auto-invalidate group cache on membership/role changes. Groups::Registry.invalidate!. · `docs/reference/groups.md#cache-invalidation` `docs/guides/groups.md#testing-groups` `docs/design/groups_roles_and_org_structure.md` `lib/lcp_ruby/groups/registry.rb` `lib/lcp_ruby/groups/change_handler.rb`
375
+ - **Group Memberships** — Assign users to groups (has_many :memberships). Membership model links users and groups. · `docs/reference/groups.md#source-model-db` `docs/reference/groups.md#membership-only-mode` `docs/guides/groups.md#step-3-membership-only-mode-default` `docs/design/groups_roles_and_org_structure.md` `lib/lcp_ruby/groups/model_loader.rb` `lib/generators/lcp_ruby/templates/groups/group_membership_model.rb`
376
+ - **Group Role Mappings** — Map roles to groups (group_roles:). All group members inherit mapped roles. · `docs/reference/groups.md#role-resolution-strategy` `docs/guides/groups.md#role-resolution-strategies` `docs/design/groups_roles_and_org_structure.md` `lib/lcp_ruby/groups/registry.rb` `lib/generators/lcp_ruby/templates/groups/group_role_mapping_model.rb`
377
+ - **Group Source Configuration** — Set group source per-environment (config.group_source = :yaml/:model/:host). config/initializers/lcp_ruby.rb. · `docs/reference/groups.md#configuration` `docs/reference/groups.md#complexity-levels` `docs/guides/groups.md#quick-start-with-yaml-groups` `docs/design/groups_roles_and_org_structure.md` `lib/lcp_ruby/groups/setup.rb`
378
+ - **Groups Generator** — Scaffold DB group models (rails g lcp_ruby:groups). Creates group, membership, and role mapping models. · `docs/reference/groups.md#source-model-db` `docs/guides/groups.md#step-1-run-the-generator` `docs/design/groups_roles_and_org_structure.md` `lib/generators/lcp_ruby/groups_generator.rb` `lib/generators/lcp_ruby/templates/groups/group_model.rb` `lib/generators/lcp_ruby/templates/groups/group_presenter.rb`
379
+ - **Groups Overview** — Organize users into groups for shared role assignments. config/lcp_ruby/groups.yml or DB-backed. · `docs/reference/groups.md#groups-reference` `docs/guides/groups.md#groups-guide` `docs/design/groups_roles_and_org_structure.md` `lib/lcp_ruby/groups/registry.rb` `lib/lcp_ruby/groups/setup.rb`
380
+ - **Groups Registry API** — Query groups programmatically (Groups::Registry.for_user, .all, .find). Cached lookups. · `docs/reference/groups.md#registry-api` `docs/design/groups_roles_and_org_structure.md` `lib/lcp_ruby/groups/registry.rb`
381
+ - **Groups with Impersonation** — Impersonation inherits target user group roles. Groups resolved for impersonated identity. · `docs/reference/groups.md#impersonation` `docs/guides/impersonation.md#impersonation-view-as-role-x` `docs/design/groups_roles_and_org_structure.md` `lib/lcp_ruby/groups/registry.rb` `lib/lcp_ruby/authorization/impersonated_user.rb`
382
+ - **Host Adapter (AD/LDAP)** — Integrate external directory groups (group_source: :host). Implement Groups::HostAdapter contract. · `docs/reference/groups.md#source-host-adapter` `docs/guides/groups.md#host-adapter-for-adldap` `docs/design/groups_roles_and_org_structure.md` `lib/lcp_ruby/groups/host_loader.rb`
383
+ - **Role Resolution: Direct Only** — Use only direct user roles (role_resolution: :direct_only). Ignore group roles. · `docs/reference/groups.md#role-resolution-strategy` `docs/guides/groups.md#direct-only` `docs/design/groups_roles_and_org_structure.md` `lib/lcp_ruby/groups/registry.rb`
384
+ - **Role Resolution: Groups Only** — Use only group-assigned roles (role_resolution: :groups_only). Ignore direct user roles. · `docs/reference/groups.md#role-resolution-strategy` `docs/guides/groups.md#groups-only` `docs/design/groups_roles_and_org_structure.md` `lib/lcp_ruby/groups/registry.rb`
385
+ - **Role Resolution: Merged** — Combine direct + group roles (role_resolution: :merged). Union of all role sources. Default mode. · `docs/reference/groups.md#role-resolution-strategy` `docs/guides/groups.md#merged-default` `docs/design/groups_roles_and_org_structure.md` `lib/lcp_ruby/groups/registry.rb`
386
+ - **YAML Groups (Static)** — Define groups in YAML (group_source: :yaml). config/lcp_ruby/groups.yml with members and roles. · `docs/reference/groups.md#source-yaml` `docs/guides/groups.md#quick-start-with-yaml-groups` `docs/design/groups_roles_and_org_structure.md` `lib/lcp_ruby/groups/yaml_loader.rb`
387
+
388
+ ## Host Controller
389
+
390
+ - **Concern dependency guards** — method_defined? checks at class load time. Descriptive error if concerns included in wrong order. · `docs/reference/host-controller-integration.md` `docs/design/host_app_controller_integration.md` `lib/lcp_ruby/controller/`
391
+ - **Hybrid routing (static catch-all + dynamic per-presenter)** — Two routing layers: explicit slug routes for host controllers + :lcp_slug catch-all for LCP. · `docs/reference/host-controller-integration.md` `docs/design/host_app_controller_integration.md` `lib/lcp_ruby/routing/`
392
+ - **LcpRuby::Controller::Authentication concern** — current_user, effective_user, authenticate_user!. Sets LcpRuby::Current.user for the request. · `docs/reference/host-controller-integration.md` `docs/design/host_app_controller_integration.md` `lib/lcp_ruby/controller/`
393
+ - **LcpRuby::Controller::Authorization concern** — Pundit-compatible authorize/policy_scope. Presenter-based policy lookup. authorize_presenter_access. · `docs/reference/host-controller-integration.md` `docs/design/host_app_controller_integration.md` `lib/lcp_ruby/controller/`
394
+ - **LcpRuby::Controller::CrudHelpers concern** — permitted_params, set_record, setup_show/index_view_objects. For rendering LCP view templates. · `docs/reference/host-controller-integration.md` `docs/design/host_app_controller_integration.md` `lib/lcp_ruby/controller/`
395
+ - **LcpRuby::Controller::ErrorHandling concern** — rescue_from for MetadataError, RecordNotFound. No dependencies. Include in any host controller. · `docs/reference/host-controller-integration.md` `docs/design/host_app_controller_integration.md` `lib/lcp_ruby/controller/`
396
+ - **LcpRuby::Controller::Impersonation concern** — Override effective_user for impersonation. Must include before Authorization in MRO. · `docs/reference/host-controller-integration.md` `docs/design/host_app_controller_integration.md` `lib/lcp_ruby/controller/`
397
+ - **LcpRuby::Controller::PathHelpers concern** — All LCP *_path helpers: resource_path, new_resource_path, edit_resource_path, etc. · `docs/reference/host-controller-integration.md` `docs/design/host_app_controller_integration.md` `lib/lcp_ruby/controller/`
398
+ - **LcpRuby::Controller::PresenterSetup concern** — Core concern: set_presenter_and_model from params[:lcp_slug]. Registers 11 LCP view helpers. · `docs/reference/host-controller-integration.md` `docs/design/host_app_controller_integration.md` `lib/lcp_ruby/controller/`
399
+ - **LcpRuby::Controller::Search concern** — Search/sort/filter pipeline. apply_advanced_search, apply_sort, apply_saved_filter. · `docs/reference/host-controller-integration.md` `docs/design/host_app_controller_integration.md` `lib/lcp_ruby/controller/`
400
+ - **LcpRuby::Controller::ViewHelpers concern** — Sort, breadcrumbs, view-group helpers. current_sort_field, toggle_direction, filter_metadata. · `docs/reference/host-controller-integration.md` `docs/design/host_app_controller_integration.md` `lib/lcp_ruby/controller/`
401
+ - **View instance variable contract** — Required ivars for LCP templates: @column_set, @action_set, @field_resolver, @layout_builder. · `docs/reference/host-controller-integration.md` `docs/design/host_app_controller_integration.md` `lib/lcp_ruby/controller/`
402
+ - **action_controllers: per-action override** — Override specific actions only (action_controllers: { new: `wizard#new` }). Rest flows through LCP. · `docs/reference/host-controller-integration.md` `docs/design/host_app_controller_integration.md` `lib/lcp_ruby/controller/` `lib/lcp_ruby/routing/`
403
+ - **controller: + read_only + custom views (gradual adoption)** — Host controller with own ERB views (controller: + read_only: true). Gradual LCP nav integration. · `docs/reference/host-controller-integration.md` `docs/design/host_app_controller_integration.md` `lib/lcp_ruby/controller/`
404
+ - **controller: full CRUD takeover** — Route all CRUD to host controller (controller: `checkouts`). Include LcpRuby::Controller::* concerns. · `docs/reference/host-controller-integration.md` `docs/design/host_app_controller_integration.md` `lib/lcp_ruby/controller/` `lib/lcp_ruby/routing/`
405
+ - **lcp_ruby:host_controller generator** — Generator scaffolds host controller with selected concerns. Auto-resolves dependencies, correct order. · `docs/reference/host-controller-integration.md` `docs/design/host_app_controller_integration.md` `lib/lcp_ruby/controller/`
406
+
407
+ ## I18n
408
+
409
+ - **Automatic locale binding** — around_action chain: current_user.profile[:locale] → Accept-Language → I18n.default_locale — authenticated and anonymous pages alike. · `docs/reference/i18n.md` `docs/design/my_settings_on_user.md` `lib/lcp_ruby/controller/locale_binding.rb` `app/controllers/lcp_ruby/application_controller.rb` `app/controllers/lcp_ruby/auth/base_controller.rb`
410
+
411
+ ## Import
412
+
413
+ - **Association Lookup** — FK lookup by attribute (e.g. Category.find_by(name:)). Direct ID or text-to-ID resolution. · `docs/reference/import.md#association-lookup` `docs/guides/import.md` `docs/design/import.md#association-resolution` `docs/design/import.md#d6-association-resolution-via-lookup-attribute` `lib/lcp_ruby/import/`
414
+ - **CSV Import** — CSV import with auto encoding detection (BOM, UTF-8, fallback). Auto delimiter detection. · `docs/reference/import.md` `docs/guides/import.md#basic-setup` `docs/design/import.md#file-parsing` `docs/design/import.md#d4-file-format-detected-from-file-not-user-input` `lib/lcp_ruby/import/`
415
+ - **Collection Import** — Toolbar import button with two-phase dialog. Upload + mapping. Runs as background job. · `docs/reference/import.md#presenter-configuration` `docs/guides/import.md#basic-setup` `docs/design/import.md#enabling-import-on-a-presenter` `lib/lcp_ruby/import/`
416
+ - **Column Auto-Mapping** — Auto-match CSV headers to fields. Exact name, humanized label, underscore normalization. · `docs/reference/import.md#auto-mapping` `docs/guides/import.md` `docs/design/import.md#d12-auto-mapping-by-name-label-and-alias` `lib/lcp_ruby/import/`
417
+ - **Duplicate Column Handling** — Duplicate CSV headers get column-index prefix (e.g. `3:Name`). Ensures unique mapping keys. · `docs/reference/import.md#column-mapping` `docs/design/import.md` `lib/lcp_ruby/import/`
418
+ - **Import Background Job** — Import runs as background job (data_import). Progress tracking, cancellation, no auto-retry. · `docs/reference/import.md#background-execution` `docs/guides/import.md` `docs/design/import.md#importjobhandler-background-job-execution` `docs/design/import.md#d1-reuse-job_execution-not-a-separate-import_job-table` `lib/lcp_ruby/import/`
419
+ - **Import Error Report** — Auto-generated error CSV on job_execution (result_file). Row number, status, error, original data. · `docs/reference/import.md` `docs/guides/import.md` `docs/design/import.md#d9-error-report-as-csv-attachment` `lib/lcp_ruby/import/`
420
+ - **Import Generator** — Generator: lcp_ruby:import. Creates import_row + import_profile models. Prereq: background_jobs generator. · `docs/reference/import.md#generator` `docs/guides/import.md#basic-setup` `docs/design/import.md#generator` `lib/lcp_ruby/import/`
421
+ - **Import Max Rows** — Safety limit (import max_rows: 5000). File parsed in phase 1, rejected before job enqueue. · `docs/reference/import.md` `docs/guides/import.md` `docs/design/import.md#i7-max-rows-check-on-xlsx-sheet-switch` `lib/lcp_ruby/import/`
422
+ - **Import Nested Permission Filtering** — Nested import fields respect target model permissions (field_writable? on target evaluator). · `docs/reference/import.md#permission-filtering` `docs/guides/import.md#permissions` `docs/design/import.md` `lib/lcp_ruby/import/`
423
+ - **Import Nested has_one** — Import flat CSV into parent + has_one associations. Dot-notation mapping to nested_attributes. · `docs/reference/import.md#nested-has_one-import` `docs/guides/import.md#nested-has_one-import` `docs/design/import_nested_has_one.md` `docs/design/import.md` `lib/lcp_ruby/import/`
424
+ - **Import Per-Row Tracking** — Per-row import_row records. Status: pending/created/updated/skipped/error. source_data, target_record_id. · `docs/reference/import.md#per-row-tracking` `docs/design/import.md#import_row-per-row-tracking-generated` `docs/design/import.md#d2-import_row-as-a-dedicated-table` `lib/lcp_ruby/import/`
425
+ - **Import Profiles** — Save column mappings + strategy (import_profile model). Visibility: personal/role/global. · `docs/reference/import.md#import-profiles` `docs/guides/import.md#saved-profiles` `docs/design/import.md#import_profile-saved-column-mappings-generated` `docs/design/import.md#d14-import_profile-follows-export_profile-pattern` `lib/lcp_ruby/import/`
426
+ - **Import Strategies** — Four strategies: create_only, update_only, upsert, skip_existing. Match attribute for find+update. · `docs/reference/import.md#import-strategies` `docs/guides/import.md#import-strategies` `docs/design/import.md#import-strategies` `docs/design/import.md#d5-strategy-chosen-per-import-not-per-presenter` `lib/lcp_ruby/import/`
427
+ - **Import Undo** — Undo completed imports. Created records destroyed, updated reverted via previous_values snapshot. · `docs/reference/import.md` `docs/design/import.md#undo-import` `docs/design/import.md#d11-full-undo-via-previous_values-snapshot` `lib/lcp_ruby/import/`
428
+ - **Nested Associations Whitelist** — Control which has_one associations appear in import (nested_associations: [:profile]). · `docs/reference/import.md#nested-associations-whitelist` `docs/design/import.md` `docs/design/import_nested_has_one.md` `lib/lcp_ruby/import/`
429
+ - **Nested Blank Strategy** — Blank value handling in nested import (nested_blank_strategy: `skip` or `null`). · `docs/reference/import.md#blank-handling` `docs/guides/import.md#nested-has_one-import` `docs/design/import_nested_has_one.md` `lib/lcp_ruby/import/`
430
+ - **Nested Field Auto-Mapping** — Auto-map CSV headers to nested fields by suffix. Direct fields win collisions. · `docs/reference/import.md#column-mapping-format` `docs/design/import_nested_has_one.md` `lib/lcp_ruby/import/`
431
+ - **Permission-Filtered Import** — Import respects permissions: action, strategy (create/update), field-level (writable_fields only). · `docs/reference/import.md#permissions` `docs/guides/import.md#permissions` `docs/design/import.md#permission-integration` `lib/lcp_ruby/import/`
432
+ - **Two-Phase Import Dialog** — Phase 1: upload + strategy. Phase 2: column mapping. Result.continue for multi-step dialog flow. · `docs/reference/import.md` `docs/guides/import.md` `docs/design/import.md#import-dialog` `docs/design/import.md#d3-two-phase-dialog-with-resultcontinue` `lib/lcp_ruby/import/`
433
+ - **Type Coercion** — String-to-type coercion pipeline. Configurable date/boolean/decimal parsing. Enum label reverse lookup. · `docs/reference/import.md#type-coercion` `docs/guides/import.md#type-coercion` `docs/design/import.md#type-coercion-and-value-parsing` `lib/lcp_ruby/import/`
434
+ - **Upsert with Nested Records** — Upsert strategy with nested has_one: find parent, update/create nested. update_only: true preserves IDs. · `docs/reference/import.md#upsert-behavior` `docs/guides/import.md#nested-has_one-import` `docs/design/import_nested_has_one.md` `docs/design/import.md` `lib/lcp_ruby/import/`
435
+ - **XLSX Import** — Excel import via roo gem. Multi-sheet support, sheet selector in mapping phase. · `docs/reference/import.md` `docs/guides/import.md` `docs/design/import.md#d10-xlsx-reading-via-roo-gem-optional-dependency` `lib/lcp_ruby/import/`
436
+
437
+ ## Input Types
438
+
439
+ - **Array Input** — Tag chip input (input_type: array_input). suggestions:, max:, placeholder:. presenters/*.yml form. · `docs/reference/presenters.md#input-types` `docs/design/array_field_type.md#10-form-input--array_input` `docs/design/array_field_type.md` `app/helpers/lcp_ruby/form_helper.rb`
440
+ - **Number Input with Prefix/Suffix** — Number field with addon (input_type: number). prefix:, suffix: for units. presenters/*.yml form. · `docs/reference/presenters.md#input-types` `docs/reference/presenters.md#input-options` `app/helpers/lcp_ruby/form_helper.rb`
441
+ - **Radio Group Input** — Horizontal radio buttons (input_type: radio_group). Best for 2-5 enum options. presenters/*.yml form. · `docs/reference/presenters.md#input-types` `docs/guides/presenters.md#input-types` `app/helpers/lcp_ruby/form_helper.rb`
442
+ - **Rich Text Editor Input** — WYSIWYG Trix editor (input_type: rich_text_editor). For rich_text fields. presenters/*.yml form. · `docs/reference/presenters.md#input-types` `docs/guides/presenters.md#input-types` `app/helpers/lcp_ruby/form_helper.rb`
443
+ - **Select Input** — Standard HTML dropdown (input_type: select). Auto-populated for enums. presenters/*.yml form fields. · `docs/reference/presenters.md#input-types` `docs/reference/presenters.md#input-options` `docs/guides/presenters.md#input-types` `docs/guides/selectbox.md#association-select` `app/helpers/lcp_ruby/form_helper.rb`
444
+ - **Slider Input** — Range slider (input_type: slider). min:, max:, step: via input_options. presenters/*.yml form. · `docs/reference/presenters.md#input-types` `docs/guides/presenters.md#input-types` `app/helpers/lcp_ruby/form_helper.rb`
445
+ - **Textarea Input** — Multi-line text box (input_type: textarea). rows:, hint:, char_counter:. presenters/*.yml form. · `docs/reference/presenters.md#input-types` `docs/guides/presenters.md#input-types` `app/helpers/lcp_ruby/form_helper.rb`
446
+ - **Toggle Input** — iOS-style boolean switch (input_type: toggle). presenters/*.yml form field input_type. · `docs/reference/presenters.md#input-types` `docs/guides/presenters.md#input-types` `app/helpers/lcp_ruby/form_helper.rb`
447
+ - **Tom Select (Enhanced Select)** — Searchable dropdown (input_type: association_select/multi_select). search:, allow_create:. presenters/*.yml. · `docs/reference/presenters.md#input-types` `docs/reference/presenters.md#how-association-selects-work` `docs/guides/selectbox.md#remote-search` `docs/guides/selectbox.md#inline-create` `docs/guides/selectbox.md#multi-select` `app/helpers/lcp_ruby/form_helper.rb`
448
+ - **Tree Select Input** — Hierarchical dropdown (input_type: tree_select). For parent-child associations. presenters/*.yml form. · `docs/reference/presenters.md#input-types` `docs/guides/selectbox.md#tree-select` `docs/design/tree_structures.md` `app/helpers/lcp_ruby/form_helper.rb`
449
+
450
+ ## Master Detail
451
+
452
+ - **Master-Detail Split View** — Selection-driven split view (selection: single). Sidebar master list, main+tabs detail. record_source: selection. · `docs/reference/pages.md#master-detail-pages` `docs/guides/composite-pages.md#master-detail-pages` `docs/design/composite_pages_v2.md` `lib/lcp_ruby/pages/resolver.rb`
453
+
454
+ ## Model Features
455
+
456
+ - **Array Condition Operators** — Array-aware visible_when/disable_when operators: contains, any_of, empty. presenters/*.yml conditions. · `docs/reference/models.md#array-fields` `lib/lcp_ruby/model_factory/array_type_applicator.rb`
457
+ - **Array Query Scopes** — Auto-generated with_<field>/with_any_<field> scopes for array fields. type: array in models/*.yml or DSL. · `docs/reference/models.md#array-fields` `docs/reference/model-dsl.md#array-fields` `lib/lcp_ruby/model_factory/array_type_applicator.rb` `lib/lcp_ruby/model_factory/scope_applicator.rb`
458
+ - **Array Validations** — Array-specific validations (array_length, array_inclusion, array_uniqueness). validates: on array fields. models/*.rb. · `docs/reference/models.md#array_length` `docs/reference/models.md#array_inclusion` `docs/reference/models.md#array_uniqueness` `docs/reference/model-dsl.md#array_length` `lib/lcp_ruby/model_factory/validation_applicator.rb` `lib/lcp_ruby/model_factory/array_type_applicator.rb`
459
+ - **Associations** — AR associations (belongs_to, has_many, has_many :through). associations: key. models/*.yml or DSL. · `docs/reference/models.md#associations` `docs/reference/model-dsl.md#associations` `lib/lcp_ruby/model_factory/association_applicator.rb`
460
+ - **Computed Fields** — Read-only fields computed by Ruby service class on save. computed: { service: ClassName }. models/*.yml. · `docs/reference/models.md#computed` `docs/guides/computed-fields.md#computed-fields-guide` `docs/reference/model-dsl.md#examples` `lib/lcp_ruby/model_factory/computed_applicator.rb`
461
+ - **Custom Types** — Reusable field types with base_type + validations + transforms. config/lcp_ruby/types/*.yml. · `docs/reference/models.md#type` `docs/reference/model-dsl.md#business-types` `lib/lcp_ruby/types/type_registry.rb` `lib/lcp_ruby/types/built_in_types.rb`
462
+ - **Default Values** — Static or service-computed field defaults. default: key (literal or service: class). models/*.yml. · `docs/reference/models.md#default` `docs/reference/model-dsl.md#boolean-with-default` `lib/lcp_ruby/model_factory/default_applicator.rb`
463
+ - **Nested has_one Boolean Shorthand** — nested_attributes: true shorthand on has_one. Defaults: reject_if: :all_blank, update_only: true. · `docs/reference/models.md#boolean-shorthand` `docs/reference/models.md#nested-attributes` `lib/lcp_ruby/model_factory/association_applicator.rb`
464
+ - **Scopes** — Named query scopes via where/where_not/order/limit. scopes: key in model definition. models/*.yml. · `docs/reference/models.md#scopes` `docs/reference/model-dsl.md#scopes` `lib/lcp_ruby/model_factory/scope_applicator.rb`
465
+ - **Timestamps** — Auto-managed created_at/updated_at columns. timestamps: true in model options. models/*.yml or DSL. · `docs/reference/models.md#timestamps` `docs/reference/model-dsl.md#timestamps` `lib/lcp_ruby/model_factory/builder.rb`
466
+ - **Transforms** — Auto value transforms on save (strip, downcase, parameterize). transforms: key on fields. models/*.yml. · `docs/reference/models.md#transforms` `docs/reference/model-dsl.md#examples` `lib/lcp_ruby/model_factory/transform_applicator.rb`
467
+ - **Validations** — Declarative field validations (presence, uniqueness, format, length). validations: key. models/*.yml. · `docs/reference/models.md#validations` `docs/reference/model-dsl.md#validations` `lib/lcp_ruby/model_factory/validation_applicator.rb`
468
+
469
+ ## Model Inheritance
470
+
471
+ - **Abstract + STI Combined Chain** — STI parent can inherit from abstract model. Three-level chain: abstract -> STI parent -> children. · `docs/reference/models.md#chaining-with-abstract-inheritance` `docs/design/model_inheritance.md#3-impact-on-other-subsystems` `lib/lcp_ruby/metadata/model_inheritance_resolver.rb`
472
+ - **Abstract Base Model** — Abstract parent model (abstract: true). No table/AR class. Prefix with underscore. models/*.rb or *.yml. · `docs/reference/models.md#abstract` `docs/reference/model-dsl.md#abstract` `docs/design/model_inheritance.md#1-abstract-base-models` `lib/lcp_ruby/metadata/model_inheritance_resolver.rb`
473
+ - **Additive Validation Inheritance** — Parent validations always concatenated with child (no override). validates: is additive across inherits:. · `docs/reference/models.md#validations` `docs/design/model_inheritance.md#4-validation-rules` `lib/lcp_ruby/metadata/model_inheritance_resolver.rb` `lib/lcp_ruby/model_factory/validation_applicator.rb`
474
+ - **Chained Inheritance (3 levels)** — Multi-level abstract inheritance resolved by topological sort. inherits: chains. models/*.rb or *.yml. · `docs/reference/models.md#inherits` `docs/design/model_inheritance.md#example-3-chained-abstract-inheritance` `lib/lcp_ruby/metadata/model_inheritance_resolver.rb`
475
+ - **Field Override in Child** — Child redefines parent field by same name (full replacement). field :name in child model. models/*.rb. · `docs/reference/models.md#inherits` `docs/design/model_inheritance.md#1-abstract-base-models` `lib/lcp_ruby/metadata/model_inheritance_resolver.rb`
476
+ - **Multiple Children from Same Parent** — One abstract model inherited by many concrete children independently. inherits: key. models/*.rb. · `docs/reference/models.md#abstract` `docs/design/model_inheritance.md#example-1-shared-address-block` `lib/lcp_ruby/metadata/model_inheritance_resolver.rb`
477
+ - **Option Inheritance (Deep Merge)** — Model options (timestamps, userstamps, etc.) deep-merged from parent. Override individual opts in child. · `docs/reference/models.md#inherits` `docs/design/model_inheritance.md#1-abstract-base-models` `lib/lcp_ruby/metadata/model_inheritance_resolver.rb`
478
+ - **STI Automatic Type Scoping** — Rails auto WHERE type = class. Parent.all returns all types. Child.all returns only that type. · `docs/reference/models.md#single-table-inheritance-sti` `docs/reference/models.md#how-it-works` `docs/design/model_inheritance.md#2-single-table-inheritance-sti` `lib/lcp_ruby/model_factory/builder.rb`
479
+ - **STI Child Model** — STI child model (inherits: :parent). No own table. Child-specific columns added to parent table. · `docs/reference/models.md#single-table-inheritance-sti` `docs/reference/models.md#enabling-sti` `docs/design/model_inheritance.md#2-single-table-inheritance-sti` `lib/lcp_ruby/model_factory/builder.rb` `lib/lcp_ruby/metadata/model_inheritance_resolver.rb`
480
+ - **STI Parent Model (options.sti: true)** — Single Table Inheritance (options.sti: true). Adds type column. Children share parent table. · `docs/reference/models.md#sti` `docs/reference/models.md#enabling-sti` `docs/design/model_inheritance.md#2-single-table-inheritance-sti` `lib/lcp_ruby/model_factory/builder.rb`
481
+ - **STI Permission Fallback** — STI children inherit parent permissions. Lookup chain: child -> parent -> _default. · `docs/reference/models.md#permission-fallback` `docs/design/model_inheritance.md#3-impact-on-other-subsystems` `lib/lcp_ruby/authorization/permission_evaluator.rb`
482
+ - **STI Shared Table** — All STI children share parent table. SchemaManager#add_sti_child_columns! adds nullable columns. · `docs/reference/models.md#single-table-inheritance-sti` `docs/reference/models.md#restrictions` `docs/design/model_inheritance.md#2-single-table-inheritance-sti` `lib/lcp_ruby/model_factory/schema_manager.rb`
483
+ - **STI Validation Rules** — Boot-time validation: no table_name on children, no nested STI, no non-abstract/non-STI inherits. · `docs/reference/models.md#validations` `docs/design/model_inheritance.md#4-validation-rules` `lib/lcp_ruby/model_factory/validation_applicator.rb`
484
+ - **Scope Inheritance** — Scopes from abstract parents inherited by children. Override by same name. scope: in models/*.rb or *.yml. · `docs/reference/models.md#scopes` `docs/reference/models.md#inherits` `docs/design/model_inheritance.md#1-abstract-base-models` `lib/lcp_ruby/metadata/model_inheritance_resolver.rb` `lib/lcp_ruby/model_factory/scope_applicator.rb`
485
+ - **Separate Presenters per STI Variant** — Each STI variant gets own presenter with unique slug, columns, form layout. Parent shows all types. · `docs/reference/models.md#single-table-inheritance-sti` `docs/reference/presenters.md#model` `docs/design/model_inheritance.md#3-impact-on-other-subsystems` `lib/lcp_ruby/metadata/presenter_definition.rb`
486
+ - **Simple Inheritance (inherits:)** — Pull parent fields/validations/scopes into child. inherits: :_parent_name in define_model. models/*.rb. · `docs/reference/models.md#inherits` `docs/reference/model-dsl.md#inherits-keyword-argument` `docs/design/model_inheritance.md#1-abstract-base-models` `lib/lcp_ruby/metadata/model_inheritance_resolver.rb`
487
+ - **YAML Format Inheritance** — Inheritance works in YAML and DSL interchangeably. inherits: key in models/*.yml. Can cross formats. · `docs/reference/models.md#inherits` `docs/reference/models.md#abstract` `docs/design/model_inheritance.md#1-abstract-base-models` `lib/lcp_ruby/metadata/model_inheritance_resolver.rb` `lib/lcp_ruby/metadata/loader.rb`
488
+
489
+ ## Monitoring
490
+
491
+ - **ActiveSupport::Notifications Events** — Instrumented events: request/error/cache/workflow_transition/boot/reload .lcp_ruby. Custom subscriptions. · `docs/reference/monitoring.md#asnotifications-events` `docs/guides/monitoring.md` `docs/design/monitoring.md#layer-1-activesupportnotifications-instrumentation` `lib/lcp_ruby/metrics/`
492
+ - **Authorization Invariant Validator** — Boot-time check that permission YAML references runtime concepts (custom scope methods, columns, parent permissions) that actually exist. AUTH-001..009 codes; dev/test raises, prod records via record_error. · `docs/reference/invariant_check.md` `docs/design/authorization_hardening.md` `lib/lcp_ruby/authorization/runtime_invariant_validator.rb` `lib/lcp_ruby/authorization/invariant_check/configuration.rb` `lib/tasks/lcp_ruby_invariant_check.rake`
493
+ - **Custom Metric Collectors** — Host app collectors (app/lcp_metrics/). DSL: gauge/counter/histogram. cache_ttl, subscribe events. · `docs/reference/monitoring.md#custom-collectors` `docs/guides/monitoring.md#custom-collectors` `docs/design/monitoring.md#host-app-custom-metrics` `docs/design/monitoring.md#auto-discovered-collectors` `lib/lcp_ruby/metrics/`
494
+ - **Error Fingerprinting & Deduplication** — SHA256 fingerprint (class + message + frame). Normalized IDs/UUIDs. Atomic upsert on occurrence. · `docs/reference/monitoring.md#fingerprint-algorithm` `docs/design/monitoring.md#error-log` `lib/lcp_ruby/metrics/`
495
+ - **Error Log (Model + Presenter)** — Fingerprint-based error log (lcp_error_log). Dedup by SHA256. Generator: lcp_ruby:monitoring. · `docs/reference/monitoring.md#error-log-model` `docs/guides/monitoring.md#error-log` `docs/design/monitoring.md#error-log` `docs/design/monitoring.md#model` `lib/lcp_ruby/metrics/`
496
+ - **Error Log Cleanup (Data Retention)** — cleanup_before scope for data retention. Combine with background jobs for automated daily cleanup. · `docs/reference/monitoring.md` `docs/guides/monitoring.md#cleanup` `docs/design/monitoring.md#cleanup` `lib/lcp_ruby/metrics/`
497
+ - **Error Rate Limiting** — In-memory rate limiter per fingerprint (error_log_rate_limit: 1s). Batched flush. 10K entry cap. · `docs/reference/monitoring.md#rate-limiting` `docs/design/monitoring.md#rate-limiting-write-pressure-protection` `lib/lcp_ruby/metrics/`
498
+ - **Health Check Endpoint** — Built-in /lcp_health JSON endpoint. DB + boot checks. 200/503. Unauthenticated for K8s probes. · `docs/reference/monitoring.md#health-check` `docs/guides/monitoring.md#health-check` `docs/design/monitoring.md#layer-3-health-check-endpoint` `docs/design/monitoring.md#health-check-response` `lib/lcp_ruby/metrics/`
499
+ - **Monitoring Dashboard (Page)** — Dashboard page (/monitoring). KPI cards from Prometheus metrics + recent errors list widget. · `docs/reference/monitoring.md` `docs/guides/monitoring.md#monitoring-dashboard` `docs/design/monitoring.md#monitoring-dashboard` `docs/design/monitoring.md#layer-5-dashboard-visualization` `lib/lcp_ruby/metrics/` `lib/lcp_ruby/pages/`
500
+ - **Monitoring Generator** — Single generator (lcp_ruby:monitoring). Creates error log model, presenter, permissions, dashboard page. · `docs/reference/monitoring.md#generator` `docs/design/monitoring.md#generator-output` `lib/lcp_ruby/metrics/`
501
+ - **Prometheus Metrics Endpoint** — /metrics endpoint in Prometheus format. Requires prometheus-client gem. 9 built-in metrics. · `docs/reference/monitoring.md#prometheus-metrics` `docs/guides/monitoring.md#prometheus-grafana` `docs/design/monitoring.md#prometheus-metrics` `docs/design/monitoring.md#layer-2-prometheus-metrics-collection` `lib/lcp_ruby/metrics/`
502
+ - **Verify Authorized Framework Guarantee** — after_action :verify_authorized on ResourcesController. Future contributor forgets authorize → 500 in dev/test (Pundit::AuthorizationNotPerformedError). Skips 4xx/5xx + Devise. · `docs/design/authorization_hardening.md` `docs/design/authorization_hardening.md` `lib/lcp_ruby/authorized_controller.rb` `lib/lcp_ruby/controller/authorization.rb`
503
+
504
+ ## Navigation
505
+
506
+ - **Bare Widget Items (widget:)** — `widget: true` drops the `<a>`/`<button_to>` wrapper entirely so the `render:` partial can emit interactive HTML — search inputs, theme pickers, etc. · `docs/reference/menu.md#custom-renderers` `docs/design/user-menu.md` `app/views/lcp_ruby/navigation/_widget_item.html.erb` `lib/lcp_ruby/metadata/menu_item.rb`
507
+ - **Breadcrumb Navigation** — Hierarchical path for parent-child models. breadcrumb.relation: in view group YAML. views/*.yml. · `docs/guides/menu.md#menu-guide` `docs/reference/menu.md#menu-reference` `app/views/lcp_ruby/shared/_breadcrumbs.html.erb` `lib/lcp_ruby/controller/view_helpers.rb`
508
+ - **Bundled Lucide icon library** — Lucide ships in the engine layout and replaces every <i data-lucide="…"> placeholder with an inline SVG, on full-page loads and Turbo navigations. · `docs/reference/engine-configuration.md#bundled-front-end-assets` `docs/reference/menu.md#icon-only-items` `vendor/assets/javascripts/lcp_ruby/lucide.min.js` `app/assets/javascripts/lcp_ruby/lucide_init.js` `app/views/layouts/lcp_ruby/application.html.erb` `app/helpers/lcp_ruby/layout_helper.rb`
509
+ - **Computed Menu Items (provider: / panel_provider:)** — Compute menu items at render time from a registered Ruby class — "Current organization", multi-tenant switchers, "recently visited", DB-backed lists. · `docs/reference/menu.md#computed-items-provider` `docs/design/user-menu.md` `examples/showcase/app/lcp_services/menu_items/recent_announcements.rb` `app/helpers/lcp_ruby/layout_helper.rb` `lib/lcp_ruby/services/registry.rb`
510
+ - **Custom Panel Renderer (render_panel:)** — A partial owns the inner HTML of a `:group`'s dropdown panel — for profile-card headers, tenant switchers, custom dropdown layouts. · `docs/reference/menu.md#custom-renderers` `docs/design/user-menu.md` `app/views/lcp_ruby/menu_renderers/_user_menu_panel.html.erb` `app/views/lcp_ruby/navigation/_panel_item.html.erb`
511
+ - **Custom Trigger Renderer (render:)** — A partial owns the inner HTML of a menu item's link/button — for items where `<icon> <label>` doesn't fit (avatar+name+caret, search input, …). · `docs/reference/menu.md#custom-renderers` `docs/design/user-menu.md` `app/views/lcp_ruby/menu_renderers/_user_menu.html.erb` `lib/lcp_ruby/metadata/menu_item.rb`
512
+ - **Dropdown Menu** — Top nav with dropdowns. menu.yml top_menu: with children: arrays. Supports icons, separators. · `docs/guides/menu.md#step-2-add-dropdown-grouping` `docs/reference/menu.md#group-dropdown-collapsible-section` `lib/lcp_ruby/metadata/menu_definition.rb` `lib/lcp_ruby/metadata/menu_item.rb` `app/views/lcp_ruby/navigation/_top.html.erb`
513
+ - **Field Anchors** — Deep links to show-page fields via #field-{name} URL hash. Auto-generated id attributes. · `docs/guides/menu.md#menu-guide` `lib/lcp_ruby/controller/view_helpers.rb`
514
+ - **Icon-Only Menu Items** — Render menu items with only an icon (no visible label). Notifications bell, help link, compact secondary entries — with screen-reader-friendly aria_label. · `docs/reference/menu.md#icon-only-items` `docs/design/menu_icon_only_items.md` `lib/lcp_ruby/metadata/menu_item.rb` `app/views/lcp_ruby/navigation/_item_content.html.erb` `app/helpers/lcp_ruby/layout_helper.rb`
515
+ - **Menu HTTP Method Override (button_to)** — `method:` on a menu item dispatches to `button_to` (with CSRF + form-wrapping) instead of `<a href>` — for sign-out, custom actions, anything non-GET. · `docs/reference/menu.md#method-aware-rendering` `docs/design/user-menu.md` `app/views/lcp_ruby/navigation/_link_or_button.html.erb` `lib/lcp_ruby/metadata/menu_item.rb`
516
+ - **Menu Item Disabled State (disable_when)** — Render a menu item visible but in a disabled (greyed-out, non-clickable) state when a condition is true. Mirror of visible_when. · `docs/reference/menu.md#disabled-state` `docs/design/user-menu.md` `lib/lcp_ruby/metadata/menu_item.rb` `app/views/lcp_ruby/navigation/_link_or_button.html.erb` `app/assets/javascripts/lcp_ruby/controllers/menu_controller.js`
517
+ - **Mobile Header (sidebar-only off-canvas trigger)** — Thin sticky header strip with hamburger button. Auto-rendered in sidebar-only layouts when below_breakpoint: off_canvas is active — provides a way to open the drawer when no top_menu exists to host an auto-injected sidebar_toggle. · `docs/reference/menu.md#mobile-header-sidebar-only-layouts` `docs/design/responsive-menu.md#101-mobile_headerhtmlerb--sidebar-only-off-canvas-trigger` `docs/design/responsive-menu.md` `app/views/lcp_ruby/navigation/_mobile_header.html.erb` `app/assets/javascripts/lcp_ruby/controllers/sidebar_toggle_controller.js` `app/assets/javascripts/lcp_ruby/controllers/responsive_sidebar_controller.js` `app/views/layouts/lcp_ruby/application.html.erb`
518
+ - **Nested Menu Dropdowns** — Sub-groups inside dropdowns/sidebar. Max 2 levels of children: nesting. Flyout submenus. · `docs/guides/menu.md#organizing-large-dropdowns-with-sub-groups` `docs/reference/menu.md#nested-sub-groups` `lib/lcp_ruby/metadata/menu_definition.rb` `lib/lcp_ruby/metadata/menu_item.rb`
519
+ - **Path Templating in Menu YAML** — `{namespace.member}` tokens in `url:` / `label:` / `aria_label:` / `defaults:` resolve at render time. Three closed-whitelist namespaces. · `docs/reference/menu.md#path-templating` `docs/design/user-menu.md#path-templating` `lib/lcp_ruby/metadata/path_template.rb` `app/helpers/lcp_ruby/layout_helper.rb`
520
+ - **Per-Item Responsive Keys (priority / pin / hide_below / show_below)** — Per-item knobs for the responsive top nav. responsive_priority orders overflow collapse; pin: always anchors an item; hide_below / show_below toggle visibility at viewport thresholds; collapse_label_below drops the label on rails. · `docs/reference/menu.md#per-item-responsive-keys` `docs/design/responsive-menu.md` `docs/design/responsive-menu.md` `lib/lcp_ruby/metadata/menu_item.rb` `lib/lcp_ruby/metadata/configuration_validator.rb` `app/helpers/lcp_ruby/layout_helper.rb` `app/views/lcp_ruby/navigation/_top_item.html.erb`
521
+ - **Presenter Resolver in Menu (slug-rename-resilient)** — `presenter: + alias: + action:` resolves a menu URL via the presenter's record_alias and action contract — survives slug renames. · `docs/reference/menu.md#presenter-resolver` `docs/design/user-menu.md` `lib/lcp_ruby/metadata/menu_item_resolver.rb` `lib/lcp_ruby/metadata/menu_item.rb`
522
+ - **Rail-Collapsed Sidebar Flyout** — In collapsed-rail mode, clicking a group icon opens its children as an absolute-positioned flyout panel to the right of the rail. ESC and outside-click close. · `docs/reference/menu.md#rail-collapsed-flyouts` `docs/design/responsive-menu.md#102-rail-collapsed-group-flyout` `docs/design/responsive-menu.md` `app/assets/javascripts/lcp_ruby/controllers/sidebar_controller.js` `app/assets/stylesheets/lcp_ruby/application.css`
523
+ - **Responsive Sidebar (rail + off-canvas + cookie persistence)** — Two sidebar modes: rail (collapse to icon-only above breakpoint) and off_canvas (slide-in drawer below breakpoint). Rail state persists via a server-readable cookie for FOUC-free SSR. · `docs/reference/menu.md#sidebar-modes` `docs/design/responsive-menu.md` `docs/design/responsive-menu.md` `lib/lcp_ruby/metadata/responsive_policy.rb` `app/assets/javascripts/lcp_ruby/controllers/sidebar_controller.js` `app/assets/javascripts/lcp_ruby/controllers/responsive_sidebar_controller.js` `app/helpers/lcp_ruby/layout_helper.rb` `app/views/lcp_ruby/navigation/_sidebar.html.erb`
524
+ - **Responsive Top-Nav Modes (none / wrap / overflow_more / hamburger)** — Four modes for how the top nav adapts below a breakpoint. Default overflow_more @ 768px collapses items that don't fit into a *More* dropdown. hamburger mode hides the whole nav behind a drawer. · `docs/reference/menu.md#top-nav-modes` `docs/design/responsive-menu.md` `docs/design/responsive-menu.md` `lib/lcp_ruby/metadata/responsive_policy.rb` `lib/lcp_ruby/metadata/menu_definition.rb` `lib/lcp_ruby/schemas/menu.json` `app/assets/javascripts/lcp_ruby/controllers/responsive_top_nav_controller.js` `app/views/lcp_ruby/navigation/_top.html.erb`
525
+ - **Right-aligned Top Menu Items** — Declarative right alignment in top_menu via position: right. Complement to sidebar position: bottom. · `docs/guides/menu.md#right-aligned-top-bar-items` `docs/reference/menu.md#position` `docs/design/menu_position_right.md` `lib/lcp_ruby/metadata/menu_item.rb` `app/views/lcp_ruby/navigation/_top.html.erb` `app/views/lcp_ruby/navigation/_top_item.html.erb` `app/helpers/lcp_ruby/layout_helper.rb`
526
+ - **Sidebar Navigation** — Collapsible sidebar groups. menu.yml sidebar_menu:. position: bottom for pinned items. · `docs/guides/menu.md#step-4-switch-to-sidebar` `docs/guides/menu.md#step-5-combined-layout` `docs/reference/menu.md#menu-reference` `lib/lcp_ruby/metadata/menu_definition.rb` `app/views/lcp_ruby/navigation/_sidebar.html.erb` `app/views/lcp_ruby/navigation/_sidebar_item.html.erb` `app/views/lcp_ruby/navigation/_both_sidebar.html.erb`
527
+ - **Sidebar Toggle Marker (sidebar_toggle: true + auto-inject)** — A platform-owned menu item that opens the sidebar off-canvas drawer. Auto-injected into top_menu when below_breakpoint: off_canvas is active, unless explicit one is authored or auto_inject_toggle: false. · `docs/reference/menu.md#sidebar_toggle-marker` `docs/design/responsive-menu.md` `docs/design/responsive-menu.md` `lib/lcp_ruby/metadata/menu_item.rb` `app/helpers/lcp_ruby/layout_helper.rb` `app/views/lcp_ruby/navigation/_sidebar_toggle.html.erb` `app/views/lcp_ruby/navigation/_top_item.html.erb`
528
+ - **Touch-Friendly Dropdowns (lcp-dropdown primitive)** — Top-nav dropdowns open on click/tap/keyboard, not just hover. ESC closes, outside-click closes, ArrowDown opens + focuses first item. Hover still works on real mouse (guarded by @media (hover: hover)). · `docs/design/responsive-menu.md` `docs/design/responsive-menu.md` `app/assets/javascripts/lcp_ruby/controllers/dropdown_controller.js` `app/assets/javascripts/lcp_ruby/controllers/submenu_controller.js` `app/views/lcp_ruby/navigation/_top_item.html.erb`
529
+
530
+ ## Page Source
531
+
532
+ - **DB-Stored Page Definitions** — Runtime page creation (page_source: :model). DB pages override YAML/auto pages. Deactivation fallback. · `docs/reference/pages.md` `docs/design/composite_pages_v2.md` `lib/lcp_ruby/pages/`
533
+ - **Page Cache Invalidation** — Auto-clear page cache on save (after_commit). Pages::Registry.reload! + Resolver.clear!. · `docs/reference/pages.md` `docs/design/composite_pages_v2.md` `lib/lcp_ruby/pages/`
534
+ - **Page Config Model Contract** — Required contract: name (unique), definition (json), active (boolean). Generator: lcp_ruby:pages. · `docs/reference/pages.md` `docs/design/composite_pages_v2.md` `lib/lcp_ruby/pages/`
535
+ - **Page Definition Validation** — JSON validation on save: must have name, non-empty zones. Parsed through PageDefinition.from_hash. · `docs/reference/pages.md` `docs/design/composite_pages_v2.md` `lib/lcp_ruby/pages/` `lib/lcp_ruby/metadata/configuration_validator.rb`
536
+ - **Page Override Priority** — Priority order: DB pages > YAML pages > auto-generated. Deactivating DB page falls back to YAML/auto. · `docs/reference/pages.md` `docs/design/composite_pages_v2.md` `lib/lcp_ruby/pages/`
537
+
538
+ ## Pagination Footer
539
+
540
+ - **First/Last Page Links (pagination_ends)** — Show/hide First/Last links (pagination_ends true). Global config or per-presenter. CSS-driven visibility. · `docs/reference/presenters.md` `docs/design/pagination_footer.md` `docs/guides/presenters.md` `docs/design/pagination_footer.md#footer-bar-layout` `app/views/lcp_ruby/slots/index/_pagination_footer.html.erb`
541
+ - **Grouped Layout Record Count** — Shows `N groups` instead of `N records` for query_mode: :grouped. Separate i18n keys for grouped counts. · `docs/reference/presenters.md` `docs/design/pagination_footer.md` `docs/guides/presenters.md` `docs/design/pagination_footer.md#behavior-per-layout` `app/views/lcp_ruby/slots/index/_pagination_footer.html.erb`
542
+ - **Pagination Footer Bar** — Unified footer bar: per-page selector + record count + Kaminari links. per_page:, per_page_options:, show_record_count:. · `docs/reference/presenters.md` `docs/design/pagination_footer.md` `docs/guides/presenters.md` `docs/design/pagination_footer.md#feature-specification-pagination-footer` `app/views/lcp_ruby/slots/index/_pagination_footer.html.erb`
543
+ - **Pagination Styling** — Kaminari pagination CSS under .lcp-pagination-footer. Current page highlighted, hover states, consistent spacing. · `docs/reference/presenters.md` `docs/design/pagination_footer.md` `docs/guides/presenters.md` `docs/design/pagination_footer.md#pagination-styling` `app/views/lcp_ruby/slots/index/_pagination_footer.html.erb`
544
+ - **Record Count (show_record_count)** — Record count text in footer (show_record_count true|false). Adapts to layout: range for paged, total for tree. · `docs/reference/presenters.md` `docs/design/pagination_footer.md` `docs/guides/presenters.md` `docs/design/pagination_footer.md#record-count-text` `app/views/lcp_ruby/slots/index/_pagination_footer.html.erb`
545
+ - **Tree Layout Record Count** — Tree views show total count only, no page links or per-page selector. All records loaded without Kaminari. · `docs/reference/presenters.md` `docs/design/pagination_footer.md` `docs/guides/presenters.md` `docs/design/pagination_footer.md#behavior-per-layout` `app/views/lcp_ruby/slots/index/_pagination_footer.html.erb`
546
+
547
+ ## Permission Source
548
+
549
+ - **DB-Backed Permission Source** — Store permissions in DB (config.permission_source = :model). Runtime permission editing via UI. · `docs/reference/permission-source.md#permission-source-reference` `docs/reference/permission-source.md#configuration` `docs/guides/permission-source.md#quick-start` `lib/lcp_ruby/permissions/source_resolver.rb` `lib/lcp_ruby/permissions/registry.rb` `lib/lcp_ruby/permissions/setup.rb`
550
+ - **Permission Definition Contract** — Required interface for permission models (resource, role, rules). Permissions::Contract validates. · `docs/reference/permission-source.md#model-contract` `docs/reference/permission-source.md#json-definition-structure` `docs/guides/permission-source.md#json-definition-format` `lib/lcp_ruby/permissions/contract_validator.rb`
551
+ - **Permission Definition Validator** — Validates permission definitions at load time. Checks field names, operators, value types. · `docs/reference/permission-source.md#definition-validation` `docs/guides/permission-source.md#troubleshooting` `lib/lcp_ruby/permissions/definition_validator.rb` `lib/lcp_ruby/permissions/contract_validator.rb`
552
+ - **Permission Registry & Caching** — In-memory permission cache (Permissions::Registry.all, .for_role). Auto-invalidates on DB change. · `docs/reference/permission-source.md#registry-api` `docs/reference/permission-source.md#cache-invalidation` `lib/lcp_ruby/permissions/registry.rb` `lib/lcp_ruby/permissions/change_handler.rb`
553
+ - **Permission Source Generator** — Scaffold DB permission model (rails g lcp_ruby:permission_source). Creates migration, model, YAML. · `docs/reference/permission-source.md#generator` `docs/guides/permission-source.md#step-1-generate-permission-config-metadata` `lib/generators/lcp_ruby/permission_source_generator.rb` `lib/generators/lcp_ruby/templates/permission_source/model.rb` `lib/generators/lcp_ruby/templates/permission_source/presenter.rb`
554
+ - **Source Resolution Priority** — Merge order for multi-source permissions (YAML < DB < host). config.permission_source_priority. · `docs/reference/permission-source.md#source-priority` `docs/guides/permission-source.md#mixing-yaml-and-db-permissions` `lib/lcp_ruby/permissions/source_resolver.rb`
555
+
556
+ ## Permissions
557
+
558
+ - **Collection Conditions (has_many Quantifiers)** — Quantify over has_many (quantifier: any/all/none, conditions:). permissions/*.yml record_rules. · `docs/reference/condition-operators.md#collection-conditions` `docs/guides/conditional-rendering.md#collection-conditions` `docs/design/advanced_conditions.md#4-collection-conditions-has_many-quantifiers` `docs/design/unified_condition_operators.md#collection-conditions-has_many-quantifiers` `lib/lcp_ruby/condition_evaluator.rb` `lib/lcp_ruby/authorization/permission_evaluator.rb`
559
+ - **Compound Conditions (all / any / not)** — Combine permission conditions with boolean logic (all:, any:, not:). permissions/*.yml record_rules. · `docs/reference/condition-operators.md#compound-conditions` `docs/guides/conditional-rendering.md#compound-conditions` `docs/design/advanced_conditions.md#1-compound-conditions-all-any-not` `docs/design/unified_condition_operators.md#compound-conditions-allanynot` `lib/lcp_ruby/condition_evaluator.rb` `lib/lcp_ruby/authorization/permission_evaluator.rb`
560
+ - **Compound Record Rules** — Nest all:/any:/not: inside record_rules for complex boolean logic. permissions/*.yml record_rules. · `docs/reference/permissions.md#record-rules` `docs/reference/condition-operators.md#compound-conditions` `docs/guides/conditional-rendering.md#action-conditions` `docs/design/advanced_conditions.md#complex-record-rule-with-compound-conditions` `docs/design/record_rules_action_visibility.md#record-rules-action-visibility-design-document` `lib/lcp_ruby/authorization/permission_evaluator.rb` `lib/lcp_ruby/condition_evaluator.rb`
561
+ - **Dot-Path Fields in Conditions** — Traverse associations in conditions (field: `project.owner.email`). permissions/*.yml record_rules. · `docs/reference/condition-operators.md#dot-path-fields` `docs/guides/conditional-rendering.md#dot-path-fields` `docs/design/advanced_conditions.md#3-dot-path-fields-in-conditions` `docs/design/unified_condition_operators.md#dot-path-fields-in-conditions-and-eager-loading` `lib/lcp_ruby/condition_evaluator.rb` `lib/lcp_ruby/authorization/permission_evaluator.rb`
562
+ - **Dynamic Value References (current_user.<method>)** — Reference current user attrs in conditions (value: current_user.email). permissions/*.yml record_rules. · `docs/reference/condition-operators.md#current_user-attribute-of-the-authenticated-user` `docs/guides/conditional-rendering.md#current_user-attribute-of-the-authenticated-user` `docs/design/advanced_conditions.md#2-dynamic-value-references` `docs/design/unified_condition_operators.md#dynamic-value-references` `lib/lcp_ruby/condition_evaluator.rb` `lib/lcp_ruby/authorization/permission_evaluator.rb`
563
+ - **Dynamic Value References (date)** — Date-relative conditions (value: current_date or current_datetime). permissions/*.yml record_rules. · `docs/reference/condition-operators.md#date-dynamic-datetime` `docs/guides/conditional-rendering.md#date-dynamic-datetime` `docs/design/advanced_conditions.md#2-dynamic-value-references` `docs/design/unified_condition_operators.md#dynamic-value-references` `lib/lcp_ruby/condition_evaluator.rb`
564
+ - **Dynamic Value References (record.<field>)** — Compare two record fields in conditions (value: record.other_field). permissions/*.yml record_rules. · `docs/reference/condition-operators.md#field_ref-another-field-on-the-same-record` `docs/guides/conditional-rendering.md#field_ref-another-field-on-the-same-record` `docs/design/advanced_conditions.md#2-dynamic-value-references` `docs/design/unified_condition_operators.md#dynamic-value-references` `lib/lcp_ruby/condition_evaluator.rb`
565
+ - **Eager Loading Validation for Conditions** — Auto-validates eager loading for dot-path conditions. Warns on N+1 risks. PermissionEvaluator internals. · `docs/reference/condition-operators.md#condition-operators-reference` `docs/guides/conditional-rendering.md#conditional-rendering` `docs/design/advanced_conditions.md#eager-loading-validation` `docs/design/unified_condition_operators.md#dot-path-fields-in-conditions-and-eager-loading` `lib/lcp_ruby/metadata/configuration_validator.rb` `lib/lcp_ruby/presenter/includes_resolver.rb`
566
+ - **Field-Level Permissions** — Show/hide/readonly fields per role (fields: {name: {visible:, editable:}}). permissions/*.yml. · `docs/reference/permissions.md#field-overrides` `docs/reference/permissions.md#fields` `lib/lcp_ruby/authorization/permission_evaluator.rb`
567
+ - **Impersonation** — Act as another user/role for testing. config.enable_impersonation. permissions/*.yml impersonation: section. · `docs/guides/impersonation.md#impersonation-view-as-role-x` `docs/guides/impersonation.md#setup` `docs/guides/impersonation.md#security` `lib/lcp_ruby/authorization/impersonated_user.rb`
568
+ - **Inherited Record Permissions** — Declarative `inherits_from:` cascade — record visible iff parent visible (via belongs_to). Top-level key on permission YAML. · `docs/guides/inherited-permissions.md` `docs/reference/permissions.md#inherits_from` `docs/guides/hierarchical-authorization.md` `docs/design/hierarchical_record_permissions.md` `lib/lcp_ruby/metadata/permission_definition.rb` `lib/lcp_ruby/authorization/scope_builder.rb` `lib/lcp_ruby/authorization/permission_evaluator.rb` `lib/lcp_ruby/authorization/inherited_parent_validator.rb` `lib/lcp_ruby/authorization/association_lookup.rb` `lib/lcp_ruby/authorization/cache.rb` `lib/lcp_ruby/model_factory/inherited_parent_validator_applicator.rb`
569
+ - **Lookup Value Reference** — Reference another model value in conditions (value: {lookup: {model:, field:}}). permissions/*.yml. · `docs/reference/condition-operators.md#lookup-query-another-model` `docs/guides/conditional-rendering.md#lookup-query-another-model` `docs/design/advanced_conditions.md#match-against-a-codelist-value` `lib/lcp_ruby/condition_evaluator.rb`
570
+ - **Permission Coverage Merge with `_default`** — Per-model permission YAMLs coverage-merge with the `_default` entry by default. `extends:` keyword opts out (`"none"`) or declares intent explicitly (`"_default"`). permissions/*.yml top-level key. · `docs/guides/permissions.md` `docs/reference/permissions.md#extends` `docs/design/permissions_default_role_coverage.md` `lib/lcp_ruby/metadata/permission_merger.rb` `lib/lcp_ruby/metadata/permission_definition.rb` `lib/lcp_ruby/metadata/loader.rb` `lib/lcp_ruby/metadata/configuration_validator.rb` `lib/lcp_ruby/tasks/permission_resolve_formatter.rb` `lib/tasks/lcp_ruby.rake`
571
+ - **Permission Scopes** — Scope queries per role (scopes: {index: {where:}}). permissions/*.yml roles: section. · `docs/reference/permissions.md#scope` `docs/reference/permissions.md#scope-type-field_match` `docs/reference/permissions.md#scope-type-association` `docs/reference/permissions.md#scope-type-where` `docs/reference/permissions.md#scope-type-custom` `docs/design/scoped_permissions.md` `docs/design/unified_permission_scopes.md` `lib/lcp_ruby/authorization/scope_builder.rb` `lib/lcp_ruby/authorization/permission_evaluator.rb`
572
+ - **Record-Level Rules** — Row-level access rules (record_rules: [{field:, operator:, value:}]). permissions/*.yml per role. · `docs/reference/permissions.md#record-rules` `docs/reference/permissions.md#record-rule-attributes` `docs/reference/permissions.md#effect-attributes` `docs/design/record_rules_action_visibility.md#record-rules-action-visibility-design-document` `lib/lcp_ruby/authorization/permission_evaluator.rb` `lib/lcp_ruby/condition_evaluator.rb`
573
+ - **Role-Based CRUD** — CRUD permissions per role (crud: [index, show, ...]). permissions/*.yml roles: section. · `docs/reference/permissions.md#permissions-reference` `docs/reference/permissions.md#role-configuration` `docs/reference/permissions.md#crud` `lib/lcp_ruby/authorization/permission_evaluator.rb` `lib/lcp_ruby/authorization/policy_factory.rb`
574
+ - **String Operators (starts_with / ends_with / contains)** — String matching in conditions (operator: starts_with/ends_with/contains). permissions/*.yml record_rules. · `docs/reference/condition-operators.md#string-pattern-matching` `docs/reference/condition-operators.md#operator-type-compatibility` `docs/design/unified_condition_operators.md#additional-operators` `lib/lcp_ruby/condition_evaluator.rb`
575
+
576
+ ## Positioning
577
+
578
+ - **Basic Positioning** — Auto sequential position. positioning: true in model. Requires position integer field. Gap closing. · `docs/reference/models.md` `docs/reference/model-dsl.md` `docs/design/record_positioning.md` `docs/design/record_positioning.md#design-record-positioning` `docs/design/record_positioning.md#examples` `docs/design/record_positioning.md#simple-ordered-list` `lib/lcp_ruby/model_factory/positioning_applicator.rb`
579
+ - **Concurrent Edit Detection** — list_version SHA-256 hash. 409 Conflict on mismatch. Atomic reorder with version tracking. · `docs/reference/presenters.md` `docs/guides/presenters.md` `docs/design/record_positioning.md` `docs/design/record_positioning.md#concurrent-reordering` `lib/lcp_ruby/model_factory/positioning_applicator.rb`
580
+ - **Permission-Controlled Reordering** — Reorder requires update CRUD + position in writable fields. Two-level permission check. · `docs/reference/presenters.md` `docs/reference/permissions.md` `docs/design/record_positioning.md` `docs/design/record_positioning.md#permission-integration` `lib/lcp_ruby/model_factory/positioning_applicator.rb`
581
+ - **Position Auto-Management** — Auto bookkeeping: append on create, gap close on destroy, shift on reorder. positioning gem. · `docs/reference/models.md` `docs/reference/model-dsl.md` `docs/design/record_positioning.md` `docs/design/record_positioning.md#gem-choice-positioning` `docs/design/record_positioning.md#bulk-create-seeding-performance` `lib/lcp_ruby/model_factory/positioning_applicator.rb`
582
+ - **Positioning DSL** — DSL: positioning field:, scope:. Presenter: reorderable true. YAML: positioning: true. · `docs/reference/model-dsl.md` `docs/reference/models.md` `docs/design/record_positioning.md` `docs/design/record_positioning.md#model-yaml-new-top-level-positioning-key` `docs/design/record_positioning.md#model-dsl` `docs/design/record_positioning.md#dsl-equivalent` `lib/lcp_ruby/model_factory/positioning_applicator.rb`
583
+ - **Reorderable Index** — Drag-and-drop reordering. reorderable: true in presenter index block. Drag handles column. · `docs/reference/presenters.md` `docs/reference/presenter-dsl.md` `docs/guides/presenters.md` `docs/design/record_positioning.md` `docs/design/record_positioning.md#presenter-reorderable-true-on-index` `docs/design/record_positioning.md#frontend-index-table-drag-and-drop` `docs/design/record_positioning.md#controller-reorder-action` `lib/lcp_ruby/model_factory/positioning_applicator.rb`
584
+ - **Scoped Positioning** — Independent ordering per parent. positioning scope: :parent_id. Each scope has own sequence. · `docs/reference/models.md` `docs/reference/model-dsl.md` `docs/design/record_positioning.md` `docs/design/record_positioning.md#scoped-positioning` `docs/design/record_positioning.md#scope-change-via-normal-edit` `lib/lcp_ruby/model_factory/positioning_applicator.rb`
585
+
586
+ ## Presenter
587
+
588
+ - **404 Error Page** — Custom not-found page for missing records. presenters/*.yml error_pages: section. · `docs/reference/engine-configuration.md` `app/controllers/lcp_ruby/resources_controller.rb`
589
+ - **Association List — Link Through** — Link association list items to their records (link_through: true). presenters/*.yml show association. · `docs/reference/presenters.md#association-list-sections` `docs/reference/presenters.md#link-through-a-join-model-to-the-real-entity` `docs/reference/presenter-dsl.md#association_listtitle-association-display_template-nil-link-nil-link_through-nil-sort-nil-limit-nil-empty_message-nil-scope-nil-visible_when-nil-disable_when-nil` `docs/guides/presenters.md#linking-through-join-models` `lib/lcp_ruby/presenter/layout_builder.rb`
590
+ - **Auto-Search** — Search as you type without submit button (auto_search: true). presenters/*.yml index: search options. · `docs/reference/presenter-dsl.md#auto_searchvalue-true` `docs/reference/presenters.md#search-attributes` `docs/guides/presenters.md#type-aware-quick-search` `lib/lcp_ruby/search/quick_search.rb` `lib/lcp_ruby/controller/search.rb`
591
+ - **Canonical Presenter Selection** — Multi-presenter model link resolution via default: true (per-model canonical) and link_presenter: (per-link override). presenters/*.yml top-level + show.field / index.table_columns / show.association_list. · `docs/reference/presenters.md#multiple-presenters-per-model` `docs/reference/presenters.md#default` `docs/reference/presenter-dsl.md#default` `lib/lcp_ruby/presenter/enrichment.rb` `lib/lcp_ruby/metadata/configuration_validator.rb`
592
+ - **Column Configuration** — Table column control: width, sortable, link_to, pinned, summary. table_columns: in index. presenters/*.yml. · `docs/reference/presenters.md#table_columns` `docs/reference/presenters.md#column-attributes` `docs/reference/presenter-dsl.md#columnfield_name-options` `docs/guides/presenters.md#columns-sorting-and-pagination` `lib/lcp_ruby/presenter/column_set.rb`
593
+ - **Copy URL Button** — Copy record URL to clipboard button on show page. presenters/*.yml show: copy_url: true. · `docs/reference/presenters.md#copy_url` `docs/reference/presenter-dsl.md#copy_urlvalue` `app/views/lcp_ruby/slots/show/_copy_url.html.erb` `spec/integration/copy_url_spec.rb`
594
+ - **Copyable Fields** — Click-to-copy on field values (copyable: true). presenters/*.yml field display option. · `docs/reference/presenters.md#show-field-attributes` `app/helpers/lcp_ruby/display_helper.rb` `lib/lcp_ruby/schemas/presenter.json`
595
+ - **Empty Value Display** — Customize empty/nil display (empty_value: `---`). Global or per-field. presenters/*.yml display options. · `docs/reference/presenters.md#empty_value` `docs/reference/presenter-dsl.md#empty_value` `app/helpers/lcp_ruby/display_helper.rb`
596
+ - **Field/Column Link Through** — Link show fields and index columns to the associated record via link:/link_through:. presenters/*.yml show.field or index.table_columns. · `docs/reference/presenter-dsl.md#section-fields-show` `docs/reference/presenter-dsl.md#column-options` `docs/design/show_field_link_through.md` `lib/lcp_ruby/presenter/enrichment.rb` `lib/lcp_ruby/presenter/link_resolver.rb` `app/helpers/lcp_ruby/link_through_helper.rb`
597
+ - **Info Blocks** — In-form informational callouts. type: info with text: in form section fields. presenters/*.yml or DSL. · `docs/reference/presenters.md#info-pseudo-field` `docs/reference/presenter-dsl.md#infotext` `docs/design/composite_pages_v2.md` `lib/lcp_ruby/presenter/layout_builder.rb` `lib/lcp_ruby/schemas/presenter.json` `app/views/lcp_ruby/resources/_form_section.html.erb`
598
+ - **NULL Filter (Predefined Scope)** — Filter by NULL/NOT NULL via predefined scope (where: {field: nil}). presenters/*.yml filters. · `docs/reference/models.md#null-empty-value-scopes` `docs/reference/presenters.md#predefined-filter-attributes` `lib/lcp_ruby/model_factory/scope_applicator.rb` `lib/lcp_ruby/controller/search.rb`
599
+ - **Predefined Filters** — Scope-based filter tabs above index table. predefined_filters: in search: block. presenters/*.yml or DSL. · `docs/reference/presenters.md#predefined-filter-attributes` `docs/reference/presenter-dsl.md#filtername-label-default-false-scope-nil` `docs/guides/presenters.md#filter-presets` `docs/design/saved_filters.md#predefined-filters-vs-saved-filters-interaction` `lib/lcp_ruby/controller/search.rb`
600
+ - **Presenter Inheritance (DSL)** — Presenter inherits from another via inherits: key. Child overrides specific sections. presenters/*.rb DSL. · `docs/reference/presenter-dsl.md#inheritance` `docs/reference/presenter-dsl.md#inheritance-semantics` `docs/guides/presenters.md#dsl-inheritance` `docs/guides/presenters.md#inheritance-rules` `lib/lcp_ruby/dsl/presenter_builder.rb` `lib/lcp_ruby/dsl/dsl_loader.rb`
601
+ - **Redirect After CRUD** — Custom redirect after create/update/destroy (redirect_to:). presenters/*.yml actions config. · `docs/reference/presenters.md#redirect_after` `docs/reference/presenter-dsl.md#redirect_after` `docs/reference/presenters.md#interaction-with-redirect_after` `app/controllers/lcp_ruby/resources_controller.rb`
602
+ - **Row Click** — Clickable table rows navigating to show page. row_click: show in index: block. presenters/*.yml or DSL. · `docs/reference/presenters.md#row_click` `docs/reference/presenter-dsl.md#row_clickvalue` `lib/lcp_ruby/dsl/presenter_builder.rb` `lib/lcp_ruby/schemas/presenter.json` `app/views/lcp_ruby/resources/_table_index.html.erb`
603
+ - **Row Styling — Built-in CSS Classes** — Seven utility classes: lcp-row-danger/warning/success/info/muted/bold/strikethrough. CSS vars. · `docs/reference/presenters.md#built-in-utility-classes` `docs/reference/presenters.md#item_classes` `docs/design/row_styling.md#built-in-utility-css-classes` `lib/lcp_ruby/condition_evaluator.rb`
604
+ - **Row Styling — Rule Accumulation** — Multiple item_class rules accumulate. All matching CSS classes applied simultaneously. · `docs/reference/presenters.md#item_classes` `docs/guides/presenters.md#conditional-row-styling-item_classes` `docs/design/row_styling.md#evaluation-rules` `lib/lcp_ruby/condition_evaluator.rb`
605
+ - **Row Styling — Service Condition** — Complex row styling logic via service class (when: { service: :overdue_check }). Server-side eval. · `docs/reference/presenters.md#item_classes` `docs/guides/conditional-rendering.md#service-conditions` `docs/design/row_styling.md#condition-services` `lib/lcp_ruby/condition_evaluator.rb`
606
+ - **Row Styling — Tiles & Tree Support** — item_classes work across table, tiles, tree layouts. Same config, different element targets. · `docs/reference/presenters.md#cross-layout-support` `docs/reference/presenters.md#item_classes` `docs/design/row_styling.md#cross-view-support` `lib/lcp_ruby/condition_evaluator.rb`
607
+ - **Row Styling — eq Operator** — Conditional row CSS (item_class with eq operator). Match field value to apply class. presenter DSL. · `docs/reference/presenters.md#item_classes` `docs/reference/presenters.md#rule-attributes` `docs/design/row_styling.md#yaml-configuration` `lib/lcp_ruby/condition_evaluator.rb`
608
+ - **Row Styling — gt / lt Operators (Numeric)** — Numeric comparison for row styling (gt/gte/lt/lte). Works on integer, float, date, datetime. · `docs/reference/presenters.md#item_classes` `docs/guides/conditional-rendering.md#operator-reference` `docs/design/row_styling.md#evaluation-rules` `lib/lcp_ruby/condition_evaluator.rb`
609
+ - **Row Styling — in / not_in Operators** — Match field against value list (operator: :in/:not_in). Group multiple values under one style. · `docs/reference/presenters.md#item_classes` `docs/guides/conditional-rendering.md#operator-reference` `docs/design/row_styling.md#evaluation-rules` `lib/lcp_ruby/condition_evaluator.rb`
610
+ - **Row Styling — matches Operator (Regex)** — Regex match for row styling (matches/not_matches). String/text fields. 1s safety timeout. · `docs/reference/presenters.md#item_classes` `docs/guides/conditional-rendering.md#operator-reference` `docs/design/row_styling.md#evaluation-rules` `lib/lcp_ruby/condition_evaluator.rb`
611
+ - **Row Styling — present / blank Operators** — Unary operators for row styling (present/blank). Flag incomplete records. No value param needed. · `docs/reference/presenters.md#item_classes` `docs/guides/conditional-rendering.md#operator-reference` `docs/design/row_styling.md#evaluation-rules` `lib/lcp_ruby/condition_evaluator.rb`
612
+ - **Section Descriptions** — Descriptive text below section headings. description: key on sections in show/form. presenters/*.yml. · `docs/reference/presenters.md#section-attributes` `docs/reference/presenter-dsl.md#sectiontitle-columns-1-description-nil-responsive-nil-visible_when-nil-disable_when-nil-block` `lib/lcp_ruby/presenter/layout_builder.rb`
613
+ - **Show Section Disable (disable_when)** — Disable show-page sections by record values (disable_when:). Server-side evaluation. presenters/*.yml show sections. · `docs/reference/presenters.md#section-attributes` `docs/guides/conditional-rendering.md#form-section-disable_when` `docs/guides/conditional-rendering.md#disable-section-on-closed-records` `lib/lcp_ruby/condition_evaluator.rb`
614
+ - **Show Section Visibility (visible_when)** — Show/hide show-page sections by record values (visible_when:). Server-side evaluation. presenters/*.yml show sections. · `docs/reference/presenters.md#section-attributes` `docs/guides/conditional-rendering.md#section-level-conditions` `docs/guides/conditional-rendering.md#show-page-conditions` `lib/lcp_ruby/condition_evaluator.rb`
615
+ - **Sticky Table Header** — Keep table header visible on scroll (sticky_header: true). presenters/*.yml index: table options. · `docs/reference/presenters.md#table_columns` `app/views/lcp_ruby/resources/_table_index.html.erb`
616
+ - **View Descriptions** — Descriptive subtitle text on index/show/form views. description: key in view blocks. presenters/*.yml. · `docs/reference/presenters.md#description` `docs/reference/presenter-dsl.md#descriptiontext` `docs/design/composite_pages_v2.md` `lib/lcp_ruby/dsl/presenter_builder.rb` `lib/lcp_ruby/schemas/presenter.json` `app/views/lcp_ruby/resources/index.html.erb` `app/views/lcp_ruby/resources/show.html.erb` `app/views/lcp_ruby/resources/_form.html.erb`
617
+ - **View Switcher** — Multiple presenter views for same data (view_group:). views/*.yml primary: + views: array. · `docs/reference/view-groups.md#switcher` `docs/guides/view-groups.md#adding-multiple-views-for-a-model` `docs/design/view_switcher_context.md` `lib/lcp_ruby/metadata/view_group_definition.rb` `lib/lcp_ruby/dsl/view_group_builder.rb` `app/helpers/lcp_ruby/layout_helper.rb`
618
+ - **has_one Fields in Show View** — Dot-path fields for has_one in show (association.field). Requires includes: for eager loading. · `docs/reference/presenters.md#show-field-attributes` `docs/reference/presenter-dsl.md#section-fields-show` `docs/guides/presenters.md#sections-and-fields` `lib/lcp_ruby/presenter/field_value_resolver.rb`
619
+
620
+ ## Record Aliases
621
+
622
+ - **Record Alias Resolution Priority** — Resolution order: alias match (highest) > slug field > numeric ID (fallback). Aliases shadow slugs if names collide. · `docs/guides/record-aliases.md` `docs/design/record_aliases.md` `lib/lcp_ruby/controller/crud_helpers.rb`
623
+ - **Record Alias URL Preservation** — Alias-based URLs are preserved across show, edit, update, and zone navigation. /preferences/me/edit stays /preferences/me/edit. · `docs/guides/record-aliases.md` `docs/design/record_aliases.md` `lib/lcp_ruby/controller/path_helpers.rb` `lib/lcp_ruby/controller/crud_helpers.rb`
624
+ - **Record Alias: current_user Strategy** — record_alias :me, resolve: :current_user, field: :user — resolves alias to the record belonging to the logged-in user. · `docs/guides/record-aliases.md` `docs/reference/presenters.md` `docs/design/record_aliases.md` `lib/lcp_ruby/controller/crud_helpers.rb` `lib/lcp_ruby/record_aliases/setup.rb` `lib/lcp_ruby/metadata/presenter_definition.rb`
625
+ - **Record Alias: current_user on self (User model)** — record_alias :me, resolve: :current_user — no field:, resolves directly to the logged-in user's own row on the user model. · `docs/guides/record-aliases.md` `docs/reference/presenters.md` `docs/design/my_settings_on_user.md` `lib/lcp_ruby/controller/crud_helpers.rb` `lib/lcp_ruby/record_aliases/setup.rb` `lib/lcp_ruby/record_aliases/metadata_checker.rb`
626
+ - **Record Alias: field_on_user Strategy** — record_alias :my, resolve: :field_on_user, user_field: :team_id — resolves alias by reading a FK from current_user. · `docs/guides/record-aliases.md` `docs/reference/presenters.md` `docs/design/record_aliases.md` `lib/lcp_ruby/controller/crud_helpers.rb` `lib/lcp_ruby/record_aliases/setup.rb`
627
+ - **Record Alias: scope Strategy** — record_alias :latest, resolve: :scope, scope: :latest — resolves alias to the first record from a named scope. · `docs/guides/record-aliases.md` `docs/reference/presenters.md` `docs/design/record_aliases.md` `lib/lcp_ruby/controller/crud_helpers.rb` `lib/lcp_ruby/record_aliases/setup.rb`
628
+ - **Slug Field** — Human-readable URLs via slug_field on model. find_by(slug:) when param is non-numeric, to_param returns slug. · `docs/guides/record-aliases.md` `docs/reference/models.md` `docs/design/record_aliases.md` `lib/lcp_ruby/model_factory/builder.rb` `lib/lcp_ruby/controller/crud_helpers.rb` `lib/lcp_ruby/record_aliases/setup.rb`
629
+ - **Slug Field Reserved Segment Validation** — Auto-added exclusion validation prevents slug values that clash with routing segments (new, edit, actions, etc.). · `docs/guides/record-aliases.md` `docs/design/record_aliases.md` `lib/lcp_ruby/reserved_route_segments.rb` `lib/lcp_ruby/model_factory/builder.rb`
630
+
631
+ ## Role Source
632
+
633
+ - **Active/Inactive Roles** — Toggle roles on/off (active: boolean). Inactive roles excluded from resolution. role model field. · `docs/reference/role-source.md#model-contract` `docs/guides/role-source.md#activeinactive-roles` `lib/lcp_ruby/roles/registry.rb` `lib/lcp_ruby/roles/contract_validator.rb`
634
+ - **DB-Backed Role Source** — Store roles in DB (config.role_source = :model). Dynamic role management via UI. config/initializers/lcp_ruby.rb. · `docs/reference/role-source.md#role-source-reference` `docs/reference/role-source.md#configuration` `docs/guides/role-source.md#quick-start` `lib/lcp_ruby/roles/registry.rb` `lib/lcp_ruby/roles/setup.rb`
635
+ - **Role Model Contract** — Required interface for role models (name, slug, permissions). Roles::Contract validates compliance. · `docs/reference/role-source.md#model-contract` `docs/guides/role-source.md#custom-model-setup` `lib/lcp_ruby/roles/contract_validator.rb`
636
+ - **Role Model Generator** — Scaffold DB role model (rails g lcp_ruby:role_model). Creates migration, model, YAML, and seed data. · `docs/reference/role-source.md#generator` `docs/reference/role-source.md#generated-model-fields` `docs/guides/role-source.md#step-1-run-the-generator` `lib/generators/lcp_ruby/role_model_generator.rb` `lib/generators/lcp_ruby/templates/role_model/model.rb` `lib/generators/lcp_ruby/templates/role_model/presenter.rb`
637
+ - **Role Registry & Caching** — In-memory role cache (Roles::Registry.all, .find). Auto-invalidates on DB change. · `docs/reference/role-source.md#registry` `docs/reference/role-source.md#cache-invalidation` `docs/guides/role-source.md#cache-behavior` `lib/lcp_ruby/roles/registry.rb` `lib/lcp_ruby/roles/change_handler.rb`
638
+ - **Role Validation in Authorization** — PermissionEvaluator validates roles exist in registry before evaluating. Raises on unknown role. · `docs/reference/role-source.md#effect-on-authorization` `docs/reference/role-source.md#configuration-validation` `docs/reference/role-source.md#boot-sequence` `docs/guides/role-source.md#how-role-validation-works` `lib/lcp_ruby/roles/registry.rb` `lib/lcp_ruby/authorization/permission_evaluator.rb`
639
+
640
+ ## Scaffolding
641
+
642
+ - **lcp_ruby:ensure_tables + db Lifecycle Integration** — Rake task that materialises platform tables idempotently in topological order. db:prepare / db:setup enhanced; db:reset inherits via db:setup. · `docs/getting-started.md#resetting-the-database` `docs/reference/boot_lifecycle.md#database-lifecycle` `docs/design/boot_reload_lifecycle.md` `lib/tasks/lcp_ruby_db.rake` `lib/lcp_ruby/engine.rb`
643
+ - **lcp_ruby:entity generator** — One-shot scaffold of model + presenter + permissions + view group from a CLI field grammar. Covers v1 types/associations, v2 DB constraints + feature flags, v3 sections/renderers/color_map/link/polymorphic. · `docs/getting-started.md#scaffolding-new-entities` `docs/guides/menu.md#adding-entities-to-the-menu` `docs/design/entity_generator.md` `docs/design/entity_generator_menu_flag.md` `lib/generators/lcp_ruby/entity_generator.rb` `lib/generators/lcp_ruby/entity/` `lib/generators/lcp_ruby/generators/entity_menu_writer.rb` `lib/generators/lcp_ruby/templates/entity/`
644
+
645
+ ## Search
646
+
647
+ - **Advanced Filter Builder** — Visual filter UI with AND/OR. advanced_filter block. max_conditions:, filterable_fields:, presets. · `docs/reference/presenters.md` `docs/reference/condition-operators.md` `docs/guides/conditional-rendering.md` `docs/design/advanced_search.md` `docs/design/search_parameter_controls.md` `docs/design/saved_filters.md` `docs/design/advanced_search.md#design-advanced-search-filter-builder` `docs/design/advanced_search.md#10-visual-filter-builder-ui-design` `lib/lcp_ruby/search/filter_metadata_builder.rb` `lib/lcp_ruby/search/filter_param_builder.rb` `lib/lcp_ruby/search/query_builder.rb`
648
+ - **Association Select Parameter** — Dropdown for belongs_to. type: :association_select. Local or remote (search: true) mode. Tom Select. · `docs/reference/presenters.md` `docs/reference/condition-operators.md` `docs/guides/conditional-rendering.md` `docs/design/advanced_search.md` `docs/design/search_parameter_controls.md` `docs/design/saved_filters.md` `docs/design/search_parameter_controls.md` `docs/design/saved_filters.md#parameter-types` `lib/lcp_ruby/search/parameter_definition.rb` `lib/lcp_ruby/search/parameterized_scope_applicator.rb`
649
+ - **Boolean Select Parameter** — Three-option dropdown: All/Yes/No. type: :boolean_select. i18n labels. Omits param on All. · `docs/reference/presenters.md` `docs/reference/condition-operators.md` `docs/guides/conditional-rendering.md` `docs/design/advanced_search.md` `docs/design/search_parameter_controls.md` `docs/design/saved_filters.md` `docs/design/search_parameter_controls.md` `docs/design/saved_filters.md#parameter-types` `lib/lcp_ruby/search/parameter_definition.rb`
650
+ - **Cascading Field Picker** — Association drill-down in filter. max_association_depth:. Dot-path fields like department.name. · `docs/reference/presenters.md` `docs/reference/condition-operators.md` `docs/guides/conditional-rendering.md` `docs/design/advanced_search.md` `docs/design/search_parameter_controls.md` `docs/design/saved_filters.md` `docs/design/search_parameter_controls.md` `lib/lcp_ruby/search/parameter_definition.rb`
651
+ - **Date Range Parameter** — From/To date pickers. type: :date_range. Generates gteq/lteq Ransack params. Open-ended ranges. · `docs/reference/presenters.md` `docs/reference/condition-operators.md` `docs/guides/conditional-rendering.md` `docs/design/advanced_search.md` `docs/design/search_parameter_controls.md` `docs/design/saved_filters.md` `docs/design/search_parameter_controls.md` `docs/design/saved_filters.md#parameter-types` `lib/lcp_ruby/search/parameter_definition.rb` `lib/lcp_ruby/search/relative_date_expander.rb`
652
+ - **Enum Select Parameter** — Dropdown for enum fields. type: :enum_select. Auto-derived options or explicit options:. Tom Select. · `docs/reference/presenters.md` `docs/reference/condition-operators.md` `docs/guides/conditional-rendering.md` `docs/design/advanced_search.md` `docs/design/search_parameter_controls.md` `docs/design/saved_filters.md` `docs/design/search_parameter_controls.md` `docs/design/saved_filters.md#parameter-types` `lib/lcp_ruby/search/parameter_definition.rb`
653
+ - **Filter Presets** — Pre-configured filter combos. preset :name, conditions: [...] in advanced_filter block. One-click apply. · `docs/reference/presenters.md` `docs/reference/condition-operators.md` `docs/guides/conditional-rendering.md` `docs/design/advanced_search.md` `docs/design/search_parameter_controls.md` `docs/design/saved_filters.md` `docs/design/saved_filters.md#predefined-filters-vs-saved-filters-interaction` `docs/design/advanced_search.md#predefined-filter-buttons-filter` `lib/lcp_ruby/search/query_builder.rb`
654
+ - **Number Range Parameter** — Min/Max inputs for numeric fields. type: :number_range. Generates gteq/lteq Ransack params. · `docs/reference/presenters.md` `docs/reference/condition-operators.md` `docs/guides/conditional-rendering.md` `docs/design/advanced_search.md` `docs/design/search_parameter_controls.md` `docs/design/saved_filters.md` `docs/design/search_parameter_controls.md` `docs/design/saved_filters.md#parameter-types` `lib/lcp_ruby/search/parameter_definition.rb`
655
+ - **Parameter Include Blank** — Customize blank option: include_blank: string/false/nil. Default shows All. Rails convention. · `docs/reference/presenters.md` `docs/reference/condition-operators.md` `docs/guides/conditional-rendering.md` `docs/design/advanced_search.md` `docs/design/search_parameter_controls.md` `docs/design/saved_filters.md` `docs/design/search_parameter_controls.md` `lib/lcp_ruby/search/parameter_definition.rb`
656
+ - **Parameter Visibility (visible_when)** — Role-based parameter visibility. visible_when: {role: :admin}. Hidden params stripped from query. · `docs/reference/presenters.md` `docs/reference/condition-operators.md` `docs/guides/conditional-rendering.md` `docs/design/advanced_search.md` `docs/design/search_parameter_controls.md` `docs/design/saved_filters.md` `docs/design/search_parameter_controls.md` `lib/lcp_ruby/search/parameter_definition.rb` `lib/lcp_ruby/condition_evaluator.rb`
657
+ - **Parameterized Scopes** — Scopes with typed params. type: parameterized in model scopes. @scope_name(key: val) QL syntax. · `docs/reference/presenters.md` `docs/reference/condition-operators.md` `docs/guides/conditional-rendering.md` `docs/design/advanced_search.md` `docs/design/search_parameter_controls.md` `docs/design/saved_filters.md` `docs/design/saved_filters.md#parameterized-scopes` `docs/design/saved_filters.md#model-yaml-configuration` `docs/design/saved_filters.md#ruby-side` `lib/lcp_ruby/search/parameterized_scope_applicator.rb` `lib/lcp_ruby/search/parameter_definition.rb`
658
+ - **Query Language (QL)** — Text query syntax: field op value AND/OR. query_language: true. Round-trips with visual builder. · `docs/reference/presenters.md` `docs/reference/condition-operators.md` `docs/guides/conditional-rendering.md` `docs/design/advanced_search.md` `docs/design/search_parameter_controls.md` `docs/design/saved_filters.md` `docs/design/advanced_search.md#8-query-language-ql` `docs/design/saved_filters.md#ql-syntax-for-parameterized-scopes` `lib/lcp_ruby/search/query_language_parser.rb` `lib/lcp_ruby/search/query_language_serializer.rb`
659
+ - **Relative Date Operators** — Dynamic date operators: last_n_days, this_week/month/quarter/year. Date/datetime field filters. · `docs/reference/presenters.md` `docs/reference/condition-operators.md` `docs/guides/conditional-rendering.md` `docs/design/advanced_search.md` `docs/design/search_parameter_controls.md` `docs/design/saved_filters.md` `docs/design/advanced_search.md#relative-date-functions` `lib/lcp_ruby/search/relative_date_expander.rb`
660
+ - **Saved Filter Default** — Auto-apply filter on page load. default_filter: true. Priority: personal > group > role > global. · `docs/reference/presenters.md` `docs/reference/condition-operators.md` `docs/guides/conditional-rendering.md` `docs/design/advanced_search.md` `docs/design/search_parameter_controls.md` `docs/design/saved_filters.md` `docs/design/saved_filters.md#scenario-5-default-filter` `docs/design/saved_filters.md#default-filter-priority` `lib/lcp_ruby/saved_filters/resolver.rb`
661
+ - **Saved Filter Display Modes** — display: :inline (pinned buttons) or :dropdown (single menu). max_visible_pinned:. saved_filters block. · `docs/reference/presenters.md` `docs/reference/condition-operators.md` `docs/guides/conditional-rendering.md` `docs/design/advanced_search.md` `docs/design/search_parameter_controls.md` `docs/design/saved_filters.md` `docs/design/saved_filters.md#index-page-display` `docs/design/saved_filters.md#inline-mode-default` `docs/design/saved_filters.md#dropdown-mode` `docs/design/saved_filters.md#sidebar-mode` `lib/lcp_ruby/saved_filters/resolver.rb`
662
+ - **Saved Filter Pinning** — Prominent toolbar buttons. allow_pinning: true, max_visible_pinned: 5. Inline display mode. · `docs/reference/presenters.md` `docs/reference/condition-operators.md` `docs/guides/conditional-rendering.md` `docs/design/advanced_search.md` `docs/design/search_parameter_controls.md` `docs/design/saved_filters.md` `docs/design/saved_filters.md#saved-filter-data-model` `lib/lcp_ruby/saved_filters/resolver.rb`
663
+ - **Saved Filter Visibility** — Four levels: personal, role, group, global. visibility: key. Ownership rules enforce access. · `docs/reference/presenters.md` `docs/reference/condition-operators.md` `docs/guides/conditional-rendering.md` `docs/design/advanced_search.md` `docs/design/search_parameter_controls.md` `docs/design/saved_filters.md` `docs/design/saved_filters.md#saved-filter-permissions` `docs/design/saved_filters.md#scenario-2-role-shared-filter` `docs/design/saved_filters.md#scenario-3-global-filter` `docs/design/saved_filters.md#scenario-4-group-shared-filter` `lib/lcp_ruby/saved_filters/resolver.rb` `lib/lcp_ruby/saved_filters/contract_validator.rb`
664
+ - **Saved Filters** — User-persistent named filters. saved_filters block. Generator: lcp_ruby:saved_filters. CRUD + pinning. · `docs/reference/presenters.md` `docs/reference/condition-operators.md` `docs/guides/conditional-rendering.md` `docs/design/advanced_search.md` `docs/design/search_parameter_controls.md` `docs/design/saved_filters.md` `docs/design/saved_filters.md#feature-specification-saved-filters-parameterized-scopes` `docs/design/saved_filters.md#saved-filter-data-model` `docs/design/advanced_search.md#9-saved-filters-configuration-source-principle` `lib/lcp_ruby/saved_filters/` `lib/generators/lcp_ruby/saved_filters_generator.rb`
665
+ - **Search Parameter Controls** — Typed toolbar filters. parameter :name, type: enum_select/association_select/boolean_select/number_range/date_range. · `docs/reference/presenters.md` `docs/reference/condition-operators.md` `docs/guides/conditional-rendering.md` `docs/design/advanced_search.md` `docs/design/search_parameter_controls.md` `docs/design/saved_filters.md` `docs/design/search_parameter_controls.md` `docs/design/advanced_search.md#1-presenter-configuration-search-key-extension` `lib/lcp_ruby/search/parameter_definition.rb` `lib/lcp_ruby/search/param_sanitizer.rb`
666
+
667
+ ## Theming
668
+
669
+ - **Server-side preference binding** — LayoutHelper reads theme/density/border_radius from user.profile_data on every authenticated request; first paint is correct with no localStorage round-trip. · `docs/reference/engine-configuration.md` `docs/guides/theming.md` `docs/design/my_settings_on_user.md` `app/helpers/lcp_ruby/layout_helper.rb` `app/controllers/lcp_ruby/preferences_controller.rb`
670
+
671
+ ## Tiles
672
+
673
+ - **Card Actions** — Per-card action style (card.actions :dropdown|:inline|:none). Controls how row actions render on each card. · `docs/guides/tiles.md#tile-configuration-reference` `docs/design/tiles_view.md#tile-card-structure` `app/views/lcp_ruby/resources/_tiles_index.html.erb` `lib/lcp_ruby/presenter/layout_builder.rb`
674
+ - **Card Description** — Body text on card (card.description_field:). Clamped via max_lines: (default 3). CSS line-clamp truncation. · `docs/guides/tiles.md#tile-fields` `docs/design/tiles_view.md#tile-card-structure` `app/views/lcp_ruby/resources/_tiles_index.html.erb` `lib/lcp_ruby/presenter/layout_builder.rb`
675
+ - **Card Fields with Renderers** — Label-value pairs in card body (field :name, renderer:). All display renderers supported. Dot-paths too. partial: also supported (parity with table columns). · `docs/guides/tiles.md#tile-fields` `docs/design/tiles_view.md#tile-card-structure` `app/views/lcp_ruby/resources/_tiles_index.html.erb` `lib/lcp_ruby/presenter/layout_builder.rb`
676
+ - **Card Subtitle with Renderer** — Formatted subtitle below title (card.subtitle_field:). Supports renderer: :badge with color_map: options. · `docs/guides/tiles.md#tile-fields` `docs/design/tiles_view.md#tile-card-structure` `app/views/lcp_ruby/resources/_tiles_index.html.erb` `lib/lcp_ruby/presenter/layout_builder.rb`
677
+ - **Card Title Field** — Required card heading (card.title_field:). Combined with index-level row_click :show makes the title a clickable link. · `docs/guides/tiles.md#tile-fields` `docs/design/tiles_view.md#tile-card-structure` `app/views/lcp_ruby/resources/_tiles_index.html.erb` `lib/lcp_ruby/presenter/layout_builder.rb`
678
+ - **Dot-Path Fields in Cards** — Association traversal in card fields (field `assoc.attr`). Auto eager-loads belongs_to to prevent N+1. · `docs/guides/tiles.md#dot-path-fields` `docs/design/tiles_view.md#tile-field-resolution` `app/views/lcp_ruby/resources/_tiles_index.html.erb` `lib/lcp_ruby/presenter/layout_builder.rb`
679
+ - **Kanban Layout (Phase 1)** — Column-based pipeline view (layout: :kanban). Drag cards between columns via PATCH /:id/kanban_move. group_by → workflow / enum / belongs_to. · `docs/design/kanban_view.md` `docs/design/kanban_view.md#phase-1-mvp` `lib/lcp_ruby/kanban/default_provider.rb` `app/views/lcp_ruby/resources/_kanban_index.html.erb` `app/assets/javascripts/lcp_ruby/controllers/kanban_board_controller.js`
680
+ - **Per-Page Selector** — Records-per-page dropdown (per_page_options N, N, N). In pagination footer. Works on all layouts. · `docs/guides/tiles.md#per-page-selector` `docs/design/tiles_view.md#per-page-selector` `app/views/lcp_ruby/resources/_tiles_index.html.erb` `lib/lcp_ruby/presenter/layout_builder.rb`
681
+ - **Sort Dropdown** — Tile sort controls (sort_field :name, label:). Dropdown + direction toggle. Appears when any sort_field defined. · `docs/guides/tiles.md#sort-dropdown` `docs/design/tiles_view.md#sort-dropdown` `app/views/lcp_ruby/resources/_tiles_index.html.erb` `lib/lcp_ruby/presenter/layout_builder.rb`
682
+ - **Summary Bar** — Aggregate bar below tiles (summary { field :f, function: :sum }). 5 SQL fns: sum, avg, count, min, max. · `docs/guides/tiles.md#summary-bar` `docs/design/tiles_view.md#summary-bar` `app/views/lcp_ruby/resources/_tiles_index.html.erb` `lib/lcp_ruby/presenter/layout_builder.rb`
683
+ - **Tile Columns** — Cards per row (tile { columns N }). Default 3. Responsive breakpoints: 2 cols <1200px, 1 col <768px. · `docs/guides/tiles.md#tile-configuration-reference` `docs/design/tiles_view.md#tile-configuration-yaml` `app/views/lcp_ruby/resources/_tiles_index.html.erb` `lib/lcp_ruby/presenter/layout_builder.rb`
684
+ - **Tiles Layout** — Card grid index layout (layout: :tiles). card: block (zones) + tile: block (grid columns). title_field required. · `docs/guides/tiles.md#quick-setup` `docs/design/tiles_view.md#feature-specification-tiles-view-index-layout` `app/views/lcp_ruby/resources/_tiles_index.html.erb` `lib/lcp_ruby/presenter/layout_builder.rb`
685
+ - **Tiles with Inheritance** — Reuse parent presenter via inherits:. Child redefines only index block for tiles layout. Shares show/form. · `docs/guides/tiles.md#inheritance` `docs/design/tiles_view.md#tile-configuration-yaml` `app/views/lcp_ruby/resources/_tiles_index.html.erb` `lib/lcp_ruby/presenter/layout_builder.rb`
686
+ - **Tiles with Predefined Filters** — Filter buttons on tile grid (filter :name, scope:). Inherited from parent presenter when using inherits:. · `docs/guides/tiles.md#combining-with-other-features` `docs/design/tiles_view.md#interaction-with-existing-features` `app/views/lcp_ruby/resources/_tiles_index.html.erb` `lib/lcp_ruby/presenter/layout_builder.rb`
687
+ - **Tiles with View Groups** — View switcher integration. Add tiles presenter to view_group YAML. Preserves search/filter context on switch. · `docs/guides/tiles.md#combining-with-other-features` `docs/design/tiles_view.md#view-group-integration` `app/views/lcp_ruby/resources/_tiles_index.html.erb` `lib/lcp_ruby/presenter/layout_builder.rb`
688
+
689
+ ## Types
690
+
691
+ - **Built-in Business Types** — Four built-in types: email, phone, url, color. Format validation + specialized renderers (mailto/tel/link). · `docs/reference/types.md` `docs/guides/custom-types.md` `lib/lcp_ruby/types/`
692
+ - **Custom Type Definition (DSL)** — Ruby DSL for custom types (define_type block). Same attributes as YAML: base_type, transforms, etc. · `docs/reference/types.md` `docs/guides/custom-types.md` `lib/lcp_ruby/types/` `lib/lcp_ruby/dsl/`
693
+ - **Custom Type Definition (YAML)** — Reusable field type bundle (config/lcp_ruby/types/*.yml). base_type, validations, renderer, input_type. · `docs/reference/types.md` `docs/guides/custom-types.md` `lib/lcp_ruby/types/` `lib/lcp_ruby/metadata/`
694
+ - **Macro + Type Reserved-Name Detection** — Validator + generator preflight reject field names that shadow methods generated by AR's `enum` macro or by tree/positioning/workflow macros (e.g. `field :value, :enum` clashes with `Klass.values`; `field :ancestors` on a tree model clashes with the generated `record.ancestors`). · `docs/reference/types.md#reserved_clashes` `docs/reference/models.md` `docs/design/type_system_defaults.md` `lib/lcp_ruby/metadata/reserved_names.rb` `lib/lcp_ruby/metadata/configuration_validator.rb` `lib/generators/lcp_ruby/entity_generator.rb`
695
+ - **Renderer-Name as Type-Name Synonym (C7 fix)** — Pass a type name where a renderer name is expected (e.g. `renderer: :enum` resolves to `:badge`); runtime registry falls through to the type registry. · `docs/reference/presenters.md#aliases` `docs/reference/model-dsl.md` `docs/design/type_system_defaults.md` `lib/lcp_ruby/display/renderer_registry.rb` `lib/lcp_ruby/types/type_registry.rb`
696
+ - **Row-Friendliness Warning + display_in_index Opt-In** — Validator warns when an index column references a row-unfriendly type (`:text`, `:rich_text`, `:attachment`, `:json`, `:array`, `:file`); silenced by explicit `renderer:`, `partial:`, or `display_in_index: true` opt-in. · `docs/reference/types.md#default_index_visible` `docs/reference/presenters.md` `docs/reference/presenter-dsl.md` `docs/design/type_system_defaults.md` `lib/lcp_ruby/metadata/configuration_validator.rb` `lib/lcp_ruby/types/type_registry.rb`
697
+ - **Type-Driven Renderer Defaults** — With `runtime_type_renderers` flag on, presenter columns whose `renderer:` is absent get the type's default renderer at column-set build time (boolean → boolean_icon, enum → badge, text → truncate). · `docs/reference/engine-configuration.md#runtime_type_renderers` `docs/reference/presenters.md#type-driven-renderer-defaults-runtime_type_renderers` `docs/reference/types.md#renderer` `docs/design/type_system_defaults.md` `lib/lcp_ruby/presenter/column_set.rb` `lib/lcp_ruby/types/type_registry.rb`
698
+ - **Type-Driven null:false Validators** — Field declared `null: false` auto-applies the type's `null_false_validation` rule at runtime (boolean → inclusion, everything else → presence; custom types can compose multiple rules per type). · `docs/reference/types.md#null_false_validation` `docs/reference/model-dsl.md` `docs/design/type_system_defaults.md` `lib/lcp_ruby/model_factory/validation_applicator.rb` `lib/lcp_ruby/types/type_registry.rb`
699
+
700
+ ## Virtual Fields
701
+
702
+ - **Backward Compatibility (aggregates key)** — YAML alias: aggregates -> virtual_columns, sql -> expression. Old keys still work. · `docs/guides/virtual-columns.md#backward-compatibility` `docs/design/virtual_columns.md` `lib/lcp_ruby/virtual_columns/collector.rb` `lib/lcp_ruby/model_factory/virtual_column_applicator.rb`
703
+ - **Declarative Aggregates** — Shorthand aggregate DSL. function: count/sum/avg/min/max. association:, where:, distinct:, default:. · `docs/guides/virtual-columns.md#1-declarative-aggregates` `docs/guides/virtual-columns.md#where-conditions-declarative-aggregates` `docs/design/virtual_columns.md` `lib/lcp_ruby/virtual_columns/collector.rb` `lib/lcp_ruby/virtual_columns/builder.rb` `lib/lcp_ruby/model_factory/virtual_column_applicator.rb`
704
+ - **Expression Column (Boolean)** — Raw SQL in SELECT. expression: with EXISTS/CASE. %{table} placeholder. virtual_column DSL. · `docs/guides/virtual-columns.md#2-expression-columns` `docs/guides/virtual-columns.md#null-safety-for-boolean-expressions` `docs/design/virtual_columns.md` `lib/lcp_ruby/virtual_columns/builder.rb` `lib/lcp_ruby/model_factory/virtual_column_applicator.rb`
705
+ - **Expression Column (Derived Value)** — Inline SQL derived value. CASE expression for division. expression: key. virtual_column DSL. · `docs/guides/virtual-columns.md#2-expression-columns` `docs/design/virtual_columns.md` `lib/lcp_ruby/virtual_columns/builder.rb` `lib/lcp_ruby/model_factory/virtual_column_applicator.rb`
706
+ - **Expression with Auto-Include** — auto_include: true for always-available columns. Used by item_classes. default: for COALESCE. · `docs/guides/virtual-columns.md#auto-include` `docs/design/virtual_columns.md` `lib/lcp_ruby/virtual_columns/builder.rb` `lib/lcp_ruby/model_factory/virtual_column_applicator.rb`
707
+ - **External Source (Computed Field)** — source: :external. Host defines getter/setter via on_model_ready. Read-only computed values. _(beta)_ · `docs/guides/computed-fields.md#computed-fields-guide` `docs/guides/computed-fields.md#service-syntax-custom-logic` `docs/guides/computed-fields.md#writing-a-computed-service` `docs/design/fields_accessors.md#design-external-field-accessors` `lib/lcp_ruby/services/registry.rb` `lib/lcp_ruby/model_factory/service_accessor_applicator.rb`
708
+ - **External Source (Derived Field)** — External field deriving from other virtual fields. Display-only. on_model_ready define_method. _(beta)_ · `docs/guides/computed-fields.md#computed-fields-guide` `docs/guides/computed-fields.md#derived-from-associations` `docs/design/fields_accessors.md#design-external-field-accessors` `docs/design/fields_accessors.md#form-a-source-external` `lib/lcp_ruby/model_factory/service_accessor_applicator.rb` `lib/lcp_ruby/services/registry.rb`
709
+ - **JOIN Deduplication** — Multiple columns sharing same JOIN. Builder deduplicates identical join: clauses. Single SQL JOIN. · `docs/guides/virtual-columns.md#3-expression-join-columns` `docs/design/virtual_columns.md` `docs/design/advanced_search.md#duplicate-rows-from-has_many-joins` `lib/lcp_ruby/virtual_columns/builder.rb` `lib/lcp_ruby/model_factory/virtual_column_applicator.rb`
710
+ - **JOIN-based Column** — Value from related table. expression: + join: LEFT JOIN. %{table} placeholder. virtual_column DSL. · `docs/guides/virtual-columns.md#3-expression-join-columns` `docs/design/virtual_columns.md` `lib/lcp_ruby/virtual_columns/builder.rb` `lib/lcp_ruby/model_factory/virtual_column_applicator.rb`
711
+ - **JSON Field Accessor (Boolean)** — Boolean in JSON column. Checkbox input. source: {service: json_field, options: {column:, key:}}. _(beta)_ · `docs/design/fields_accessors.md` `docs/guides/virtual-columns.md` `docs/design/fields_accessors.md#built-in-json_field-accessor` `docs/design/fields_accessors.md#json-column-with-virtual-editors` `lib/lcp_ruby/services/accessors/json_field.rb` `lib/lcp_ruby/model_factory/service_accessor_applicator.rb`
712
+ - **JSON Field Accessor (Integer with Validation)** — Integer in JSON with numericality validation. Errors on virtual field name, not JSON column. _(beta)_ · `docs/design/fields_accessors.md` `docs/guides/virtual-columns.md` `docs/design/fields_accessors.md#built-in-json_field-accessor` `docs/design/fields_accessors.md#json-column-with-virtual-editors` `lib/lcp_ruby/services/accessors/json_field.rb` `lib/lcp_ruby/model_factory/service_accessor_applicator.rb`
713
+ - **JSON Field Accessor (String)** — json_field service: reads/writes JSON column key. source: {service: json_field, options: {column:, key:}}. _(beta)_ · `docs/design/fields_accessors.md` `docs/guides/virtual-columns.md` `docs/design/fields_accessors.md#built-in-json_field-accessor` `docs/design/fields_accessors.md#json-column-with-virtual-editors` `lib/lcp_ruby/services/accessors/json_field.rb` `lib/lcp_ruby/model_factory/service_accessor_applicator.rb`
714
+ - **Multiple Virtual Fields from One JSON Column** — Many typed fields sharing one JSON column. Each targets different key. Single properties column. _(beta)_ · `docs/design/fields_accessors.md` `docs/guides/virtual-columns.md` `docs/design/fields_accessors.md#json-column-with-virtual-editors` `lib/lcp_ruby/services/accessors/json_field.rb` `lib/lcp_ruby/model_factory/service_accessor_applicator.rb`
715
+ - **Row Styling with Virtual Columns** — item_classes using virtual columns. auto_include: true columns available. Multiple rules stack. · `docs/guides/virtual-columns.md#conditional-rendering-with-virtual-columns` `docs/guides/virtual-columns.md#row-styling-based-on-virtual-column` `docs/design/virtual_columns.md` `lib/lcp_ruby/virtual_columns/builder.rb`
716
+ - **Service Virtual Column** — Ruby service class. service: key. self.call + optional self.sql_expression. app/lcp_services/. · `docs/guides/virtual-columns.md#4-service-columns` `docs/guides/virtual-columns.md#service-with-arel-db-portability` `docs/design/virtual_columns.md` `lib/lcp_ruby/virtual_columns/builder.rb` `lib/lcp_ruby/model_factory/virtual_column_applicator.rb`
717
+ - **Sorting by Virtual Columns** — sortable: true on virtual columns. SQL ORDER BY for expressions/JOINs. sql_expression for services. · `docs/guides/virtual-columns.md#displaying-virtual-columns` `docs/guides/virtual-columns.md#index-page-table-columns` `docs/design/virtual_columns.md` `lib/lcp_ruby/virtual_columns/builder.rb` `lib/lcp_ruby/model_factory/virtual_column_applicator.rb`
718
+ - **User profile as preference store** — user.profile_data + service: json_field — expose per-user preferences as first-class presenter fields without a satellite table. · `docs/reference/engine-configuration.md` `docs/reference/presenters.md` `docs/design/my_settings_on_user.md` `lib/lcp_ruby/services/accessors/json_field.rb` `lib/lcp_ruby/model_factory/service_accessor_applicator.rb` `lib/lcp_ruby/model_factory/enum_applicator.rb`
719
+ - **Virtual Columns Overview** — Query-time computed values via SQL. aggregate/expression/join/window/service. virtual_column DSL. · `docs/guides/virtual-columns.md#virtual-columns-guide` `docs/guides/virtual-columns.md#how-it-works` `docs/guides/virtual-columns.md#four-virtual-column-types` `docs/design/virtual_columns.md` `lib/lcp_ruby/virtual_columns/` `lib/lcp_ruby/model_factory/virtual_column_applicator.rb`
720
+ - **Virtual Enum (Inclusion Validation)** — Enum without DB column. Auto inclusion validation. values: + json_field source. Select input + badge. _(beta)_ · `docs/guides/virtual-columns.md#virtual-columns-guide` `docs/design/fields_accessors.md#design-external-field-accessors` `lib/lcp_ruby/services/accessors/json_field.rb` `lib/lcp_ruby/model_factory/service_accessor_applicator.rb`
721
+ - **Virtual Field with Default** — Static defaults on virtual fields. default: value applied on create. Works with json_field source. _(beta)_ · `docs/guides/virtual-columns.md#virtual-columns-guide` `docs/design/fields_accessors.md#design-external-field-accessors` `lib/lcp_ruby/model_factory/service_accessor_applicator.rb` `lib/lcp_ruby/services/built_in_defaults.rb`
722
+ - **Virtual Fields Overview** — No-column fields. source: {service: json_field} or source: :external. Stored in JSON or computed. _(beta)_ · `docs/guides/virtual-columns.md#virtual-columns-guide` `docs/guides/computed-fields.md#computed-fields-guide` `docs/guides/virtual-columns.md#virtual-columns-vs-computed-fields` `docs/guides/computed-fields.md#computed-fields-vs-virtual-columns` `docs/design/virtual_columns.md` `docs/design/fields_accessors.md#design-external-field-accessors` `lib/lcp_ruby/virtual_columns/` `lib/lcp_ruby/model_factory/virtual_column_applicator.rb` `lib/lcp_ruby/model_factory/service_accessor_applicator.rb`
723
+ - **Window Function Column** — SQL window functions: ROW_NUMBER, RANK. PARTITION BY + ORDER BY. expression: in virtual_column. · `docs/guides/virtual-columns.md#advanced-patterns` `docs/guides/virtual-columns.md#window-functions` `docs/design/virtual_columns.md` `lib/lcp_ruby/virtual_columns/builder.rb` `lib/lcp_ruby/model_factory/virtual_column_applicator.rb`
724
+
725
+ ## Workflow
726
+
727
+ - **Approval Bypass Condition** — Auto-approve matching records (bypass_when:). Standard condition operators. Skips all steps. · `docs/reference/workflow-approvals.md` `docs/reference/workflow.md#approvals` `docs/design/workflow_approvals.md` `lib/lcp_ruby/workflow/approval/`
728
+ - **Approval Resolution Transitions** — Auto-fire system transitions on resolution (resolution: { approved/rejected/returned: transition }). · `docs/reference/workflow-approvals.md` `docs/reference/workflow.md#approvals` `docs/design/workflow_approvals.md` `lib/lcp_ruby/workflow/approval/`
729
+ - **Approval Status Widget** — Show approval progress (widget type: approval_status). Steps, tasks, action buttons, comments. · `docs/reference/workflow-approvals.md` `docs/reference/workflow.md#approvals` `docs/design/workflow_approvals.md` `lib/lcp_ruby/workflow/approval/`
730
+ - **Approval Task Actions (Controller)** — POST endpoints: approve, reject, return_task, claim, delegate. TaskManager backend. · `docs/reference/workflow-approvals.md` `docs/reference/workflow.md#approvals` `docs/design/workflow_approvals.md` `lib/lcp_ruby/workflow/approval/` `lib/lcp_ruby/controller/`
731
+ - **Approval Task Delegation** — Delegate task to another user (allow_delegation: true). Configurable max_delegation_depth. · `docs/reference/workflow-approvals.md` `docs/reference/workflow.md#approvals` `docs/design/workflow_approvals.md` `lib/lcp_ruby/workflow/approval/`
732
+ - **Auto-Set Fields (set_fields)** — Auto-populate fields on transition (set_fields:). Supports :now, :today, current_user.id, literals. · `docs/reference/workflow.md#set_fields-value-expressions` `docs/guides/workflow.md` `docs/design/workflow_state_machine.md` `lib/lcp_ruby/workflow/value_resolver.rb` `lib/lcp_ruby/workflow/transition_executor.rb`
733
+ - **Clear Fields (value: null)** — Reset fields to nil on transition (set_fields: { field: :null }). For rework/reset flows. · `docs/reference/workflow.md#set_fields-value-expressions` `docs/guides/workflow.md` `docs/design/workflow_state_machine.md` `lib/lcp_ruby/workflow/value_resolver.rb`
734
+ - **Confirmation Dialogs** — Pre-submit confirmation (confirm: true, confirm_message:). data-turbo-confirm or window.confirm. · `docs/guides/action-buttons.md` `docs/reference/workflow.md` `docs/guides/workflow.md#confirmation-dialogs` `docs/design/form_submit_actions.md` `docs/design/workflow_state_machine.md` `lib/lcp_ruby/controller/` `lib/lcp_ruby/workflow/`
735
+ - **Direct Enum Update Blocking** — Blocks direct field changes on workflow field. Only transitions can change state. before_save callback. · `docs/reference/workflow.md#direct-enum-update-blocking` `docs/guides/workflow.md` `docs/design/workflow_state_machine.md` `lib/lcp_ruby/workflow/`
736
+ - **Dual-Use Triggers (trigger: both)** — Transition visible as UI button AND callable programmatically (trigger: :both). · `docs/reference/workflow.md#trigger-values` `docs/guides/workflow.md` `docs/design/workflow_state_machine.md` `lib/lcp_ruby/workflow/transition_definition.rb`
737
+ - **Field Copy (field_ref)** — Copy field values on transition (field_ref:). Snapshot of source field at transition time. · `docs/reference/workflow.md#set_fields-value-expressions` `docs/guides/workflow.md` `docs/design/workflow_state_machine.md` `lib/lcp_ruby/workflow/value_resolver.rb`
738
+ - **Field-Based Approvers** — Resolve approvers from record field (type: `field`, field: `reviewer_id`). Read at creation time. · `docs/reference/workflow-approvals.md` `docs/reference/workflow.md#approvals` `docs/design/workflow_approvals.md` `lib/lcp_ruby/workflow/approval/`
739
+ - **Multi-Step Approval Engine** — Multi-step approval on workflow state (approval block). Sequential/parallel steps, typed approvers. · `docs/reference/workflow-approvals.md` `docs/guides/workflow.md#approval-engine` `docs/design/workflow_approvals.md` `lib/lcp_ruby/workflow/approval/`
740
+ - **Multiple Source States** — Single transition from multiple states (from: [:draft, :returned]). Shared guard/set_fields config. · `docs/reference/workflow.md#transition-keys` `docs/guides/workflow.md` `docs/design/workflow_state_machine.md` `lib/lcp_ruby/workflow/transition_definition.rb`
741
+ - **Presenter Transition Overrides** — Show/hide transition buttons per presenter. Same workflow, different UI per user role view. · `docs/reference/workflow.md#presenter-integration` `docs/guides/workflow.md` `docs/design/workflow_state_machine.md` `lib/lcp_ruby/workflow/` `lib/lcp_ruby/presenter/`
742
+ - **Readonly Fields per State** — Lock fields by state (readonly_fields: [:title] or :all). Server-enforced + form disabled rendering. · `docs/reference/workflow.md#readonly_fields` `docs/guides/workflow.md#locking-fields-per-state` `docs/design/workflow_state_machine.md` `lib/lcp_ruby/workflow/state_definition.rb`
743
+ - **Required Comments** — Require comment before transition (require_comment: true). Stored in workflow audit log. · `docs/reference/workflow.md#transition-keys` `docs/guides/workflow.md#requiring-comments` `docs/design/workflow_state_machine.md` `lib/lcp_ruby/workflow/transition_definition.rb` `lib/lcp_ruby/workflow/transition_executor.rb`
744
+ - **Required Reject Comment** — Force comment on rejection (require_reject_comment: true). Stored on task, shown in widget. · `docs/reference/workflow-approvals.md` `docs/reference/workflow.md#approvals` `docs/design/workflow_approvals.md` `lib/lcp_ruby/workflow/approval/`
745
+ - **Rework Policy (Reset All)** — Reset approval on rework (rework_policy: { reset: `all` }). Creates new request, increments count. · `docs/reference/workflow-approvals.md` `docs/design/workflow_approvals.md` `lib/lcp_ruby/workflow/approval/`
746
+ - **Role-Based Approvers** — Assign tasks to role members (type: `role`, role: `admin`). All matching users get tasks. · `docs/reference/workflow-approvals.md` `docs/guides/workflow.md#approval-engine` `docs/design/workflow_approvals.md` `lib/lcp_ruby/workflow/approval/`
747
+ - **Sequential Approval Strategy** — Steps execute in order (strategy :sequential). Step N+1 activates after step N completes. · `docs/reference/workflow-approvals.md` `docs/design/workflow_approvals.md` `lib/lcp_ruby/workflow/approval/`
748
+ - **Short-Circuit Rejection** — Stop approval on first reject (short_circuit: true, on_reject: `any`). Skips remaining steps. · `docs/reference/workflow-approvals.md` `docs/design/workflow_approvals.md` `lib/lcp_ruby/workflow/approval/`
749
+ - **State Categories** — Semantic categories on states (category: :draft/:terminal/etc). For UI grouping and dashboard filters. · `docs/reference/workflow.md#state-categories` `docs/guides/workflow.md` `docs/design/workflow_state_machine.md` `lib/lcp_ruby/workflow/state_definition.rb`
750
+ - **System Triggers** — Hidden transitions (trigger: :system). For approval engines, background jobs, external integrations. · `docs/reference/workflow.md#trigger-values` `docs/guides/workflow.md#system-triggers` `docs/design/workflow_state_machine.md` `lib/lcp_ruby/workflow/transition_definition.rb` `lib/lcp_ruby/workflow/transition_executor.rb`
751
+ - **Timeline States** — Ordered state subset for timeline (timeline_states:). Off-path states shown as badges. · `docs/reference/workflow.md#timeline_states` `docs/guides/workflow.md#show-page-timeline` `docs/design/workflow_renderers.md` `docs/design/workflow_state_machine.md` `lib/lcp_ruby/workflow/`
752
+ - **Transition Guards** — Guard conditions on transitions (guard: { all/any/not }). Same 15 operators as visible_when. · `docs/reference/workflow.md#guard-conditions` `docs/guides/workflow.md#guard-conditions` `docs/design/workflow_state_machine.md` `lib/lcp_ruby/workflow/transition_executor.rb` `lib/lcp_ruby/condition_evaluator.rb`
753
+ - **Transition Roles** — Per-transition role restrictions (roles: [:admin]). Intersection with CRUD update permission. · `docs/reference/workflow.md#transition-keys` `docs/guides/workflow.md` `docs/design/workflow_state_machine.md` `lib/lcp_ruby/workflow/transition_definition.rb`
754
+ - **Wildcard Source State (from: "*")** — Transition from any state (from: `*`). Expanded to all state names at load time. Admin emergency use. · `docs/reference/workflow.md#transition-keys` `docs/guides/workflow.md` `docs/design/workflow_state_machine.md` `lib/lcp_ruby/workflow/`
755
+ - **Workflow Audit Log** — Transition history (audit_log: true). Records who, from/to state, comment, metadata, user snapshot. · `docs/reference/workflow.md#audit-log` `docs/guides/workflow.md#step-2-set-up-audit-logging` `docs/design/workflow_state_machine.md` `lib/lcp_ruby/workflow/audit_writer.rb` `lib/lcp_ruby/workflow/audit_registry.rb`
756
+ - **Workflow Badge Renderer** — Colored badge display (workflow_badge renderer). Colors from state definition. Auto-detected on index. · `docs/reference/workflow.md#renderer-integration` `docs/guides/workflow.md#index-page-badge` `docs/design/workflow_renderers.md` `lib/lcp_ruby/workflow/` `lib/lcp_ruby/display/`
757
+ - **Workflow DSL** — Ruby DSL alternative to YAML (define_workflow block). Same features: states, transitions, guards. · `docs/reference/workflow.md#dsl-format` `docs/guides/workflow.md#using-the-dsl` `docs/design/workflow_state_machine.md` `lib/lcp_ruby/workflow/` `lib/lcp_ruby/dsl/`
758
+ - **Workflow Events (on_entry / on_exit)** — Events fired on state enter/exit (on_entry:, on_exit:). Standard event handler dispatch. · `docs/reference/workflow.md` `docs/guides/workflow.md#writing-event-handlers` `docs/design/workflow_state_machine.md` `lib/lcp_ruby/workflow/` `lib/lcp_ruby/events/`
759
+ - **Workflow Graph (Mermaid Diagram)** — Mermaid state diagram widget (workflow_graph). Shows states, transitions, guards, roles, audit steps. · `docs/reference/workflow.md` `docs/guides/workflow.md#composite-page-workflow-graph` `docs/design/workflow_diagram_dialog.md` `docs/design/workflow_state_machine.md` `lib/lcp_ruby/workflow/mermaid_builder.rb`
760
+ - **Workflow Renderer Auto-Detection** — Auto-injects workflow_badge on index, workflow_timeline on show. No manual renderer: config needed. · `docs/reference/workflow.md#renderer-integration` `docs/guides/workflow.md#visualizing-workflow-status` `docs/design/workflow_renderers.md` `lib/lcp_ruby/workflow/` `lib/lcp_ruby/display/`
761
+ - **Workflow State Machine** — Metadata-driven state machine (workflow: block). States, transitions, guards. models/*.yml or workflow/*.yml. · `docs/reference/workflow.md#workflow-reference` `docs/guides/workflow.md` `docs/design/workflow_state_machine.md` `lib/lcp_ruby/workflow/state_machine.rb` `lib/lcp_ruby/workflow/`
762
+ - **Workflow Timeline Renderer** — Horizontal step indicator on show page (workflow_timeline). Completed/current/future steps. · `docs/reference/workflow.md#renderer-integration` `docs/guides/workflow.md#show-page-timeline` `docs/design/workflow_renderers.md` `lib/lcp_ruby/workflow/` `lib/lcp_ruby/display/`
763
+ - **Workflow Versioning** — Per-record version freeze (workflow_version field). Records keep original workflow definition. · `docs/reference/workflow.md` `docs/guides/workflow.md` `docs/design/workflow_state_machine.md` `lib/lcp_ruby/workflow/`