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,1187 @@
1
+ # Getting Started
2
+
3
+ This guide walks you through building a two-model TODO application with LCP Ruby — from installation to custom actions and event handlers. By the end, you'll have task lists and tasks with associations, search filters, a custom action, and an event handler.
4
+
5
+ All examples use the **Ruby DSL** as the primary format. YAML equivalents are provided in collapsible blocks.
6
+
7
+ ## Prerequisites
8
+
9
+ | Requirement | Version |
10
+ |-------------|---------|
11
+ | Ruby | >= 3.1 |
12
+ | Rails | >= 8.1 (for `lcp new`) or >= 7.1 (manual setup) |
13
+ | Database | SQLite (development), PostgreSQL (production recommended) |
14
+
15
+ LCP Ruby works with any Rails-supported database. SQLite is fine for development and this tutorial.
16
+
17
+ ## Quick Start with `lcp new`
18
+
19
+ The fastest way to create a new LCP Ruby application:
20
+
21
+ ```bash
22
+ lcp new my_app
23
+ ```
24
+
25
+ This launches an interactive wizard that asks about:
26
+ - **Database** — sqlite3, postgresql, or mysql2
27
+ - **Metadata format** — Ruby DSL (default) or YAML
28
+ - **Feature preset** — minimal, standard, full, or custom (choose individual features)
29
+
30
+ Feature presets:
31
+ | Preset | Includes |
32
+ |--------|----------|
33
+ | **minimal** | Core platform only (sample model + presenter + permissions) |
34
+ | **standard** | Core + authentication + auditing + saved filters + export + import |
35
+ | **full** | All 17 feature generators |
36
+ | **custom** | Interactive selection of individual features |
37
+
38
+ After the wizard, `lcp new` runs `rails new` with the right configuration, installs LCP Ruby, runs selected feature generators, and prepares the database. Then:
39
+
40
+ ```bash
41
+ cd my_app
42
+ rails s
43
+ ```
44
+
45
+ Visit `http://localhost:3000/items` to see the sample application.
46
+
47
+ To skip the interactive wizard and use defaults (sqlite3, DSL, minimal):
48
+
49
+ ```bash
50
+ lcp new my_app --skip-interactive
51
+ ```
52
+
53
+ CLI options: `--database=postgresql`, `--format=yaml`, `--preset=standard`, `--timezone=Europe/Prague`, `--locale=cs` (single-locale) or `--locale=cs,en,de` (multi-locale — first listed is `default_locale`), `--menu-layout=both|top|sidebar`, `--skip-action-text` (omits Trix WYSIWYG; `:rich_text` fields will render as plain textareas).
54
+
55
+ For locale-specific guidance — engine UI translation, fallbacks, `available_locales` ↔ `Accept-Language` interaction, migration from pre-v1 generators — see [guides/adding-locale.md](guides/adding-locale.md).
56
+
57
+ If `lcp new` reports that some feature generators failed (e.g. the
58
+ preset asked for a feature whose prerequisites couldn't be installed),
59
+ the command exits non-zero. Use `--allow-partial` to override and
60
+ continue, then run `bundle exec rake lcp_ruby:doctor` from the new
61
+ app to see exactly what is broken and how to fix it. See
62
+ [reference/doctor.md](reference/doctor.md) for the full diagnostic.
63
+
64
+ `lcp new` also installs [Claude Code skills](#claude-code-skills-ai-assisted-development) into `.claude/skills/` automatically — see the dedicated section below.
65
+
66
+ ### Installing from a local checkout
67
+
68
+ If `lcp_ruby` is not yet on RubyGems (pre-release, internal fork), point the generator at a local gem path:
69
+
70
+ ```bash
71
+ lcp new my_app --gem-source=path:/abs/path/to/lcp-ruby
72
+ ```
73
+
74
+ When you run `lcp` directly from a local clone (`bundle exec exe/lcp …`), the CLI auto-detects the checkout and uses `path:` automatically — you don't need the flag. The flag is only required when the binary is installed elsewhere (gem index, `gem install`, copied binary). The default when no checkout is detected is `rubygems`, which fails until the gem is published.
75
+
76
+ ## Manual Installation (existing Rails app)
77
+
78
+ If you have an existing Rails application, use the install generator instead:
79
+
80
+ ```bash
81
+ # Add to Gemfile
82
+ gem "lcp"
83
+
84
+ # Install
85
+ bundle install
86
+ rails generate lcp_ruby:install
87
+ ```
88
+
89
+ The generator sets up everything: `require "lcp_ruby"` in `application.rb`, engine mount in routes, directory structure, sample model, initializer, and a `current_user` stub.
90
+
91
+ ### Scaffolding new entities
92
+
93
+ ```bash
94
+ # Minimal scaffold — model + presenter + permissions + view group, top-level menu entry
95
+ rails generate lcp_ruby:entity Customer name:string! email:email!:uniq phone:phone \
96
+ --label-method=name --menu=ROOT --menu-icon=users
97
+
98
+ # Richer entity (v2/v3 grammar) — DB constraints, sections, renderers, link, search, color_map
99
+ rails generate lcp_ruby:entity Order \
100
+ 'number:string!:uniq' \
101
+ 'customer:belongs_to{required}' \
102
+ 'status:enum{draft|confirmed|shipped|delivered}!{default:draft}{color_map}' \
103
+ 'total:decimal!{renderer:currency}' \
104
+ --label-method=number \
105
+ --display-template='Order {number}' \
106
+ --searchable-fields=number \
107
+ --menu=Sales # auto-creates "Sales" dropdown if it doesn't yet exist
108
+ ```
109
+
110
+ `lcp_ruby:entity` creates `models/<name>.rb`, `presenters/<plural>.rb`, `permissions/<name>.yml`, `views/<name>.yml` atomically and (when `--menu=...` is passed) inserts the matching `- view_group: <name>` line into `config/lcp_ruby/menu.yml` above the seeded `# lcp:menu <section>` marker. Field grammar covers all built-in types, inline enum values (`enum{a|b|c}`), DB modifiers (`!`, `:uniq`, `:index`, `{default:X}`), associations (`belongs_to`, `has_many`), and v3 presenter modifiers (`{section:NAME}`, `{renderer:NAME}`, `{color_map}`, `{link}`, `{polymorphic}`, `:hidden`, `:search`). Feature flags: `--soft-delete`, `--auditing`, `--custom-fields`, `--positioning`, `--tree`, `--form-layout=tabs`, `--index-fields=a,b,c`, `--menu=[<section>:]ROOT|<Label>[:bottom|:right]`, `--menu-icon=<lucide>`. **Bash users:** single-quote any field token whose braces contain a comma — bash brace-expands `{a,b}` patterns. See [the design spec](design/entity_generator.md) for full grammar and worked examples; the `--menu=...` placement grammar is documented in [`guides/menu.md`](guides/menu.md#adding-entities-to-the-menu).
111
+
112
+ ### Adding features
113
+
114
+ Run any of the feature generators after install:
115
+
116
+ ```bash
117
+ rails generate lcp_ruby:install_auth # Devise authentication
118
+ rails generate lcp_ruby:api_tokens # Personal Access Tokens (bearer auth)
119
+ rails generate lcp_ruby:auditing # Audit trail
120
+ rails generate lcp_ruby:export # Data export
121
+ rails generate lcp_ruby:import # Data import
122
+ rails generate lcp_ruby:custom_fields # Runtime field definitions
123
+ rails generate lcp_ruby:saved_filters # Saved search filters
124
+ rails generate lcp_ruby:monitoring # Error dashboard
125
+ rails generate lcp_ruby:batch_operations # Bulk operations
126
+ rails generate lcp_ruby:background_jobs # Job tracking
127
+ rails generate lcp_ruby:pages # DB-backed pages
128
+ rails generate lcp_ruby:groups # User groups
129
+ rails generate lcp_ruby:role_model # DB-backed roles
130
+ rails generate lcp_ruby:permission_source # Dynamic permissions
131
+ rails generate lcp_ruby:workflow_definition # Workflows
132
+ rails generate lcp_ruby:workflow_approvals # Approval processes
133
+ rails generate lcp_ruby:workflow_audit_log # Workflow audit
134
+ rails generate lcp_ruby:gapfree_sequences # Sequential numbering
135
+ rails generate lcp_ruby:entity # Scaffold a new entity (see "Scaffolding new entities" above)
136
+ ```
137
+
138
+ All generators support `--format=dsl` (default) or `--format=yaml`.
139
+
140
+ Each generator declares its prerequisites (e.g. `lcp_ruby:import`
141
+ requires `lcp_ruby:background_jobs` for the FK target; `lcp_ruby:api_tokens`
142
+ requires `lcp_ruby:install_auth` for the user model). If a prereq is
143
+ missing, the generator aborts up-front with a structured
144
+ `Missing prerequisite feature(s): …` message naming what to run first.
145
+ Run `bundle exec rake lcp_ruby:doctor` to see the full feature
146
+ dependency graph.
147
+
148
+ ## Claude Code Skills (AI-Assisted Development)
149
+
150
+ LCP Ruby ships a set of [Claude Code](https://claude.ai/code) skills (`lcp-model`, `lcp-presenter`, `lcp-permissions`, `lcp-workflow`, `lcp-custom-field`, `lcp-host-binding`) that auto-trigger when you're authoring the corresponding YAML/DSL configuration. Each skill briefs Claude on the 80/20 syntax + decision points + pitfalls and points at the relevant reference doc for the rest. The result: less time grepping for "how do I declare a `belongs_to` with a business-key join?" and fewer round-trips on common authoring tasks.
151
+
152
+ **Auto-installed by `lcp new`** — you don't need to do anything. The skills land in `.claude/skills/` of the new app. Open the project in Claude Code (CLI, VS Code, or any other client) and skills activate automatically based on context.
153
+
154
+ **Manual install / refresh after gem upgrade:**
155
+
156
+ ```bash
157
+ rails generate lcp_ruby:claude_skills
158
+ ```
159
+
160
+ This copies `.claude/skills/lcp-*/` from the gem path into the host application, overwriting the existing copies (use `--force=false` to skip existing files). Re-run after `bundle update lcp_ruby` to pick up skills updated for the new gem version — keeps Claude's instructions in sync with the DSL/schema changes you just bundled.
161
+
162
+ **Verify**: list installed skills via `/skills` inside Claude Code, or `ls .claude/skills/` on disk.
163
+
164
+ **For host-app developers**: commit `.claude/skills/lcp-*` to git so the whole team benefits. (`.claude/settings.local.json` is per-user and stays gitignored.)
165
+
166
+ **For platform contributors** (working on `lcp_ruby` itself): the canonical skill files live in `.claude/skills/` of the gem repo and are loaded automatically when you open the gem in Claude Code. The generator copies these same files — single source of truth.
167
+
168
+ ## Installation (step-by-step)
169
+
170
+ For full control over the setup, or if the generator doesn't suit your project structure, follow these manual steps.
171
+
172
+ Add LCP Ruby to your Gemfile:
173
+
174
+ ```ruby
175
+ gem "lcp"
176
+ ```
177
+
178
+ ### Asset Pipeline (Sprockets)
179
+
180
+ LCP Ruby bundles its JavaScript and CSS via Sprockets. If your host app uses **Propshaft** (the Rails 8 default), you must also add `sprockets-rails` — otherwise the engine's JS (Stimulus controllers, row-click navigation, advanced filters, form handling) will not load:
181
+
182
+ ```ruby
183
+ gem "sprockets-rails"
184
+ ```
185
+
186
+ Then create `app/assets/config/manifest.js` to link the engine assets:
187
+
188
+ ```js
189
+ //= link lcp_ruby/application.js
190
+ //= link lcp_ruby/application.css
191
+ //= link lcp_ruby/tom-select.css
192
+ //= link lcp_ruby/tom-select.complete.min.js
193
+ ```
194
+
195
+ > **Note:** If your host app already uses Sprockets, skip this step — the engine assets are picked up automatically.
196
+
197
+ Run `bundle install`.
198
+
199
+ Mount the engine in `config/routes.rb`:
200
+
201
+ ```ruby
202
+ Rails.application.routes.draw do
203
+ mount LcpRuby::Engine => "/"
204
+ end
205
+ ```
206
+
207
+ > **Tip:** If you want `http://localhost:3000/` to redirect to your first model's index, add a root route pointing to the engine's slug (e.g., `root to: redirect("/task_lists")`).
208
+
209
+ ## Configuration
210
+
211
+ Create an initializer at `config/initializers/lcp_ruby.rb`:
212
+
213
+ ```ruby
214
+ LcpRuby.configure do |config|
215
+ config.authentication = :none
216
+ end
217
+ ```
218
+
219
+ This is the minimal configuration for a quickstart. All other options have sensible defaults.
220
+
221
+ ### Authentication Modes
222
+
223
+ | Mode | Use Case | `current_user` |
224
+ |------|----------|----------------|
225
+ | `:none` | Quickstart / prototyping | Not required |
226
+ | `:external` | Existing app with its own auth (Devise, etc.) | Provided by host app |
227
+ | `:built_in` | Standalone app without existing auth | Managed by LCP Ruby |
228
+
229
+ The default is `:external`. This tutorial uses `:none` so you can skip authentication setup entirely. See [Authentication Setup](#authentication-setup) below when you're ready to add auth.
230
+
231
+ See [Engine Configuration](reference/engine-configuration.md) for all available options.
232
+
233
+ ## Directory Structure
234
+
235
+ Create the metadata directories:
236
+
237
+ ```
238
+ config/lcp_ruby/
239
+ types/ # Custom business type definitions (optional)
240
+ models/ # Model definitions — .rb (DSL) or .yml (YAML)
241
+ presenters/ # UI definitions — .rb (DSL) or .yml (YAML)
242
+ permissions/ # Role-based access control — .yml only
243
+ views/ # View group definitions (optional — auto-created for single-presenter models)
244
+ ```
245
+
246
+ Both `.rb` (DSL) and `.yml` (YAML) files are supported for models and presenters. Each model/presenter name must be unique across all files — defining the same name in both formats raises `MetadataError`.
247
+
248
+ > **Note:** Permissions are YAML-only. There is no DSL loader for permission files.
249
+
250
+ Metadata auto-loads on Rails boot via the `lcp_ruby.load_metadata` initializer.
251
+
252
+ > **Note:** If you plan to use host app extensions (computed services, custom actions, event handlers, condition services), you must exclude their directories from Zeitwerk autoloading. See [Extensibility Guide — Auto-Discovery Setup](guides/extensibility.md#auto-discovery-setup) for details.
253
+
254
+ ## Authentication Setup
255
+
256
+ > **Skip this section** if you're using `authentication: :none` (as in this tutorial).
257
+
258
+ When using `authentication: :external`, your host app must provide a `current_user` object. The user model must implement the method configured by `role_method` (default: `lcp_role`), returning an **array of role name strings**:
259
+
260
+ ```ruby
261
+ class User < ApplicationRecord
262
+ def lcp_role
263
+ roles.pluck(:name) # => ["admin", "sales_rep"]
264
+ end
265
+ end
266
+ ```
267
+
268
+ Your `ApplicationController` must provide `current_user` (typically via Devise, Sorcery, or a custom session-based auth):
269
+
270
+ ```ruby
271
+ class ApplicationController < ActionController::Base
272
+ before_action :authenticate_user!
273
+
274
+ def current_user
275
+ @current_user ||= User.find_by(id: session[:user_id])
276
+ end
277
+ helper_method :current_user
278
+ end
279
+ ```
280
+
281
+ The role strings must match the role names defined in your [permissions YAML](reference/permissions.md).
282
+
283
+ ### Built-in Authentication
284
+
285
+ When using `authentication: :built_in`, LCP Ruby manages users internally via `LcpRuby::User`. Run the generator to set up the auth tables and routes:
286
+
287
+ ```bash
288
+ rails g lcp_ruby:install_auth
289
+ ```
290
+
291
+ This adds Devise-based authentication with login/logout/password reset. The generator's post-install message lists the actual URLs.
292
+
293
+ **Devise routes.** The engine mounts Devise under `path: "auth"` with custom path names — these are the URLs Devise users see, **not** the conventional `/users/sign_in`:
294
+
295
+ | Path | What |
296
+ |---|---|
297
+ | `GET /auth/login` | Sign-in form |
298
+ | `DELETE /auth/logout` (also `GET /auth/logout`) | Sign-out |
299
+ | `GET /auth/register` | Sign-up (if Devise registrations are enabled) |
300
+ | `GET /auth/password/new` | Password reset |
301
+
302
+ When the engine is mounted at a non-root path (e.g. `mount LcpRuby::Engine => "/admin"`), prefix accordingly: `/admin/auth/login`.
303
+
304
+ To create initial users, add them in `db/seeds.rb`:
305
+
306
+ ```ruby
307
+ LcpRuby::User.find_or_create_by!(email: "admin@example.com") do |u|
308
+ u.name = "Admin User"
309
+ u.password = "password123"
310
+ u.lcp_role = ["admin"]
311
+ u.active = true
312
+ end
313
+ ```
314
+
315
+ Key attributes:
316
+ - **`email`** (string, required) — login identifier
317
+ - **`name`** (string) — display name
318
+ - **`password`** (string) — minimum 6 characters; `password_confirmation` is optional in seeds
319
+ - **`lcp_role`** (JSON array of strings) — role names matching your permissions YAML, e.g. `["admin"]`, `["viewer", "editor"]`
320
+ - **`active`** (boolean) — must be `true` for the user to log in; inactive users are rejected at sign-in
321
+ - **`profile_data`** (JSON hash, default `{}`) — extensible storage for custom per-user data (preferences, settings, app-specific fields). Access via `user.profile` which returns a hash with indifferent access
322
+
323
+ #### Storing custom data in `profile_data`
324
+
325
+ The `profile_data` JSON column is the recommended way to store per-user preferences or application-specific data without creating a separate model:
326
+
327
+ ```ruby
328
+ # Writing
329
+ user.update!(profile_data: { "locale" => "cs", "timezone" => "Europe/Prague", "theme" => "dark" })
330
+
331
+ # Reading (returns HashWithIndifferentAccess)
332
+ user.profile[:locale] # => "cs"
333
+ user.profile["timezone"] # => "Europe/Prague"
334
+
335
+ # Merging new keys without overwriting existing ones
336
+ user.update!(profile_data: user.profile.merge("items_per_page" => 50))
337
+ ```
338
+
339
+ For external auth (`:external`), add a `profile_data` JSON column to your own user model if you want the same pattern, or implement custom accessors.
340
+
341
+ The platform itself reads a small set of well-known keys from `profile_data` on every authenticated request (`theme`, `density`, `border_radius`, `locale`). Any writer — a presenter bound to the user model, the `PreferencesController`, a console `update!` — takes effect on the next render. See the [platform-read keys table](reference/engine-configuration.md#keys-the-platform-reads-from-profile_data) in the engine configuration reference, and the showcase `my_settings` presenter for a reference implementation built on `service: json_field` virtual fields.
342
+
343
+ Then run `rails db:seed` to create the users.
344
+
345
+ > **Note:** The `config.authentication = :built_in` line must appear in `config/initializers/lcp_ruby.rb`. If the generator inserts a duplicate line, remove the old one manually.
346
+
347
+ ### OIDC Single Sign-On
348
+
349
+ For Microsoft Entra ID, Google Workspace, Okta, Keycloak, or any OIDC-compliant
350
+ identity provider:
351
+
352
+ ```bash
353
+ rails g lcp_ruby:install_auth --mode=oidc --provider=entra --with-built-in
354
+ ```
355
+
356
+ This scaffolds `config/lcp_ruby/auth.yml` from a per-provider template
357
+ (available: `entra`, `google`, `okta`, `keycloak`, `generic`), adds the
358
+ required DB columns, and writes the host config (`host_url`, `mount_path`)
359
+ into the initializer. `--with-built-in` keeps a Devise password form on the
360
+ login page as a break-glass fallback.
361
+
362
+ See [OIDC Setup](guides/oidc-setup.md) for the full walkthrough — IdP App
363
+ registration, ENV variable options, role mapping, and troubleshooting — and
364
+ [OIDC Reference](reference/oidc.md) for the complete `auth.yml` schema.
365
+
366
+ ## Your First Model: Task List
367
+
368
+ Create `config/lcp_ruby/models/task_list.rb`:
369
+
370
+ ```ruby
371
+ define_model :task_list do
372
+ label "Task List"
373
+ label_plural "Task Lists"
374
+
375
+ field :title, :string, label: "Title" do
376
+ validates :presence
377
+ validates :length, minimum: 3, maximum: 255
378
+ end
379
+
380
+ field :description, :text, label: "Description"
381
+
382
+ timestamps true
383
+ label_method :title
384
+ end
385
+ ```
386
+
387
+ This creates a `task_lists` database table with `title` and `description` columns, plus `created_at`/`updated_at` timestamps.
388
+
389
+ Key concepts:
390
+ - **`field`** — defines a database column with a name and type
391
+ - **`validates`** — adds ActiveRecord validations (inside a field block, the field context is implicit)
392
+ - **`timestamps`** — adds `created_at` and `updated_at` columns
393
+ - **`label_method`** — the method called on records to generate display text (e.g., in association select dropdowns)
394
+
395
+ <details>
396
+ <summary>YAML equivalent</summary>
397
+
398
+ ```yaml
399
+ # config/lcp_ruby/models/task_list.yml
400
+ model:
401
+ name: task_list
402
+ label: "Task List"
403
+ label_plural: "Task Lists"
404
+
405
+ fields:
406
+ - name: title
407
+ type: string
408
+ label: "Title"
409
+ validations:
410
+ - type: presence
411
+ - type: length
412
+ options: { minimum: 3, maximum: 255 }
413
+
414
+ - name: description
415
+ type: text
416
+ label: "Description"
417
+
418
+ options:
419
+ timestamps: true
420
+ label_method: title
421
+ ```
422
+ </details>
423
+
424
+ See [Models Reference](reference/models.md) for all field types, validations, associations, and more. See [Model DSL Reference](reference/model-dsl.md) for the full DSL syntax.
425
+
426
+ ## Your First Presenter: Task List
427
+
428
+ Create `config/lcp_ruby/presenters/task_list.rb`:
429
+
430
+ ```ruby
431
+ define_presenter :task_list do
432
+ model :task_list
433
+ label "Task Lists"
434
+ slug "task_lists"
435
+ icon "list"
436
+
437
+ index do
438
+ default_sort :created_at, :desc
439
+ per_page 25
440
+ empty_message "No task lists yet. Create your first list to get started."
441
+ column :title, link_to: :show, sortable: true
442
+ column :description
443
+ end
444
+
445
+ show do
446
+ section "List Details" do
447
+ field :title, renderer: :heading
448
+ field :description
449
+ end
450
+ end
451
+
452
+ form do
453
+ section "List Details" do
454
+ field :title, placeholder: "My shopping list...", autofocus: true
455
+ field :description, input_type: :textarea, placeholder: "Optional description..."
456
+ end
457
+ end
458
+
459
+ search do
460
+ searchable_fields :title, :description
461
+ placeholder "Search lists..."
462
+ end
463
+
464
+ action :create, type: :built_in, on: :collection, label: "New List", icon: "plus"
465
+ action :show, type: :built_in, on: :single, icon: "eye"
466
+ action :edit, type: :built_in, on: :single, icon: "pencil"
467
+ action :destroy, type: :built_in, on: :single, icon: "trash", confirm: true, style: :danger
468
+ end
469
+ ```
470
+
471
+ Key concepts:
472
+ - **`index`** — configures the list/table view (columns, sorting, pagination, empty state)
473
+ - **`show`** — configures the detail view with sections and renderers
474
+ - **`form`** — configures create/edit forms with input types and placeholders
475
+ - **`search`** — enables text search across specified fields
476
+ - **`action`** — defines UI buttons (built-in CRUD or custom business logic)
477
+
478
+ <details>
479
+ <summary>YAML equivalent</summary>
480
+
481
+ ```yaml
482
+ # config/lcp_ruby/presenters/task_list.yml
483
+ presenter:
484
+ name: task_list
485
+ model: task_list
486
+ label: "Task Lists"
487
+ slug: task_lists
488
+ icon: list
489
+
490
+ index:
491
+ default_sort: { field: created_at, direction: desc }
492
+ per_page: 25
493
+ empty_message: "No task lists yet. Create your first list to get started."
494
+ table_columns:
495
+ - { field: title, link_to: show, sortable: true }
496
+ - { field: description }
497
+
498
+ show:
499
+ layout:
500
+ - section: "List Details"
501
+ fields:
502
+ - { field: title, renderer: heading }
503
+ - { field: description }
504
+
505
+ form:
506
+ sections:
507
+ - title: "List Details"
508
+ fields:
509
+ - { field: title, placeholder: "My shopping list...", autofocus: true }
510
+ - { field: description, input_type: textarea, placeholder: "Optional description..." }
511
+
512
+ search:
513
+ enabled: true
514
+ searchable_fields: [title, description]
515
+ placeholder: "Search lists..."
516
+
517
+ actions:
518
+ collection:
519
+ - { name: create, type: built_in, label: "New List", icon: plus }
520
+ single:
521
+ - { name: show, type: built_in, icon: eye }
522
+ - { name: edit, type: built_in, icon: pencil }
523
+ - { name: destroy, type: built_in, icon: trash, confirm: true, style: danger }
524
+ ```
525
+ </details>
526
+
527
+ See [Presenters Reference](reference/presenters.md) for all options. See [Presenter DSL Reference](reference/presenter-dsl.md) for the full DSL syntax.
528
+
529
+ ## Your First Permissions: Task List
530
+
531
+ Create `config/lcp_ruby/permissions/task_list.yml`:
532
+
533
+ ```yaml
534
+ permissions:
535
+ model: task_list
536
+
537
+ roles:
538
+ admin:
539
+ crud: [index, show, create, update, destroy]
540
+ fields: { readable: all, writable: all }
541
+ actions: all
542
+ scope: all
543
+ presenters: all
544
+
545
+ viewer:
546
+ crud: [index, show]
547
+ fields: { readable: all, writable: [] }
548
+ actions: { allowed: [] }
549
+ scope: all
550
+ presenters: all
551
+
552
+ default_role: admin
553
+ ```
554
+
555
+ Key concepts:
556
+ - **`roles`** — each key is a role name matched against `current_user.lcp_role`
557
+ - **`crud`** — which operations the role can perform (`index`, `show`, `create`, `update`, `destroy`)
558
+ - **`fields`** — which fields the role can read and write (`all` or an explicit list)
559
+ - **`default_role`** — assigned when the user has no matching role (set to `admin` here since we're using `authentication: :none`)
560
+
561
+ > **Warning:** We use `default_role: admin` only because this tutorial runs without authentication. When you switch to `authentication: :external` or `:built_in`, change `default_role` to a restrictive role like `viewer` so unauthenticated or unknown users don't get full access.
562
+
563
+ > **Tip:** You can create `config/lcp_ruby/permissions/_default.yml` with `model: _default` to provide fallback permissions for all models that don't have their own permission file.
564
+
565
+ See [Permissions Reference](reference/permissions.md) for field overrides, record rules, and scope types.
566
+
567
+ ## Run and Verify
568
+
569
+ ```bash
570
+ bundle exec rails db:prepare
571
+ bundle exec rails server
572
+ ```
573
+
574
+ Visit `http://localhost:3000/task_lists`. You should see:
575
+
576
+ 1. **Empty state** — the message "No task lists yet. Create your first list to get started."
577
+ 2. **"New List" button** — click it to open the create form
578
+ 3. **Form** — `title` field with placeholder text and autofocus, `description` textarea
579
+ 4. **After saving** — redirects to the show page with your list details
580
+ 5. **Navigation menu** — "Task Lists" link in the top navigation
581
+
582
+ Try creating a list, editing it, and searching for it by title.
583
+
584
+ ## Second Model with Association: Task
585
+
586
+ Now add a `task` model that belongs to a task list.
587
+
588
+ ### Update the Task List Model
589
+
590
+ First, update `config/lcp_ruby/models/task_list.rb` to add a `has_many` association:
591
+
592
+ ```ruby
593
+ define_model :task_list do
594
+ label "Task List"
595
+ label_plural "Task Lists"
596
+
597
+ field :title, :string, label: "Title" do
598
+ validates :presence
599
+ validates :length, minimum: 3, maximum: 255
600
+ end
601
+
602
+ field :description, :text, label: "Description"
603
+
604
+ has_many :tasks, model: :task, dependent: :destroy
605
+
606
+ timestamps true
607
+ label_method :title
608
+ end
609
+ ```
610
+
611
+ ### Update the Task List Presenter
612
+
613
+ Now that task_list has tasks, update the show section in `config/lcp_ruby/presenters/task_list.rb` to display them:
614
+
615
+ ```ruby
616
+ show do
617
+ section "List Details" do
618
+ field :title, renderer: :heading
619
+ field :description
620
+ end
621
+
622
+ association_list "Tasks", association: :tasks
623
+ end
624
+ ```
625
+
626
+ The `association_list` renders a list of associated records below the detail section. This is auto-detected for eager loading — no manual `includes` needed.
627
+
628
+ <details>
629
+ <summary>YAML equivalent — updated show section</summary>
630
+
631
+ ```yaml
632
+ show:
633
+ layout:
634
+ - section: "List Details"
635
+ fields:
636
+ - { field: title, renderer: heading }
637
+ - { field: description }
638
+ - section: "Tasks"
639
+ type: association_list
640
+ association: tasks
641
+ ```
642
+ </details>
643
+
644
+ ### Create the Task Model
645
+
646
+ Create `config/lcp_ruby/models/task.rb`:
647
+
648
+ ```ruby
649
+ define_model :task do
650
+ label "Task"
651
+ label_plural "Tasks"
652
+
653
+ field :title, :string, label: "Title" do
654
+ validates :presence
655
+ end
656
+
657
+ field :status, :enum, label: "Status", default: "pending",
658
+ values: { pending: "Pending", in_progress: "In Progress", completed: "Completed" }
659
+
660
+ field :due_date, :date, label: "Due Date"
661
+
662
+ field :notes, :text, label: "Notes"
663
+
664
+ belongs_to :task_list, model: :task_list, required: true
665
+
666
+ scope :active, where_not: { status: "completed" }
667
+ scope :completed, where: { status: "completed" }
668
+
669
+ on_field_change :on_status_change, field: :status
670
+
671
+ timestamps true
672
+ label_method :title
673
+ end
674
+ ```
675
+
676
+ Key concepts:
677
+ - **`belongs_to`** — creates a foreign key (`task_list_id`) linking each task to a task list
678
+ - **`has_many`** — on the parent model, declares the inverse relationship (with `dependent: :destroy` to cascade deletes)
679
+ - **`:enum`** with **`values:`** — a string field constrained to a set of labeled values, rendered as a `<select>` by default
680
+ - **`scope`** — named query filters (used by presenter filter tabs)
681
+ - **`on_field_change`** — declares a field change event that triggers when `status` changes (handler created [later](#adding-an-event-handler))
682
+
683
+ <details>
684
+ <summary>YAML equivalent — task_list.yml (updated)</summary>
685
+
686
+ ```yaml
687
+ # config/lcp_ruby/models/task_list.yml
688
+ model:
689
+ name: task_list
690
+ label: "Task List"
691
+ label_plural: "Task Lists"
692
+
693
+ fields:
694
+ - name: title
695
+ type: string
696
+ label: "Title"
697
+ validations:
698
+ - type: presence
699
+ - type: length
700
+ options: { minimum: 3, maximum: 255 }
701
+
702
+ - name: description
703
+ type: text
704
+ label: "Description"
705
+
706
+ associations:
707
+ - type: has_many
708
+ name: tasks
709
+ target_model: task
710
+ dependent: destroy
711
+
712
+ options:
713
+ timestamps: true
714
+ label_method: title
715
+ ```
716
+ </details>
717
+
718
+ <details>
719
+ <summary>YAML equivalent — task.yml</summary>
720
+
721
+ ```yaml
722
+ # config/lcp_ruby/models/task.yml
723
+ model:
724
+ name: task
725
+ label: "Task"
726
+ label_plural: "Tasks"
727
+
728
+ fields:
729
+ - name: title
730
+ type: string
731
+ label: "Title"
732
+ validations:
733
+ - type: presence
734
+
735
+ - name: status
736
+ type: enum
737
+ label: "Status"
738
+ default: "pending"
739
+ enum_values:
740
+ - { value: pending, label: "Pending" }
741
+ - { value: in_progress, label: "In Progress" }
742
+ - { value: completed, label: "Completed" }
743
+
744
+ - name: due_date
745
+ type: date
746
+ label: "Due Date"
747
+
748
+ - name: notes
749
+ type: text
750
+ label: "Notes"
751
+
752
+ associations:
753
+ - type: belongs_to
754
+ name: task_list
755
+ target_model: task_list
756
+ required: true
757
+
758
+ scopes:
759
+ - name: active
760
+ where_not: { status: "completed" }
761
+ - name: completed
762
+ where: { status: "completed" }
763
+
764
+ events:
765
+ - name: on_status_change
766
+ type: field_change
767
+ field: status
768
+
769
+ options:
770
+ timestamps: true
771
+ label_method: title
772
+ ```
773
+ </details>
774
+
775
+ ## Second Presenter: Task
776
+
777
+ Create `config/lcp_ruby/presenters/task.rb`:
778
+
779
+ ```ruby
780
+ define_presenter :task do
781
+ model :task
782
+ label "Tasks"
783
+ slug "tasks"
784
+ icon "check-square"
785
+
786
+ index do
787
+ default_sort :created_at, :desc
788
+ per_page 25
789
+ empty_message "No tasks yet. Create your first task to get started."
790
+ column :title, link_to: :show, sortable: true
791
+ column "task_list.title", label: "List", sortable: true
792
+ column :status, renderer: :badge, sortable: true
793
+ column :due_date, sortable: true
794
+ end
795
+
796
+ show do
797
+ section "Task Details", columns: 2 do
798
+ field :title, renderer: :heading
799
+ field :status, renderer: :badge
800
+ field "task_list.title", label: "List"
801
+ field :due_date
802
+ field :notes
803
+ end
804
+ end
805
+
806
+ form do
807
+ section "Task Details", columns: 2 do
808
+ field :title, placeholder: "What needs to be done?", autofocus: true
809
+ field :task_list_id, input_type: :association_select
810
+ field :status, input_type: :select
811
+ field :due_date, input_type: :date
812
+ end
813
+
814
+ section "Notes" do
815
+ field :notes, input_type: :textarea, placeholder: "Additional details..."
816
+ end
817
+ end
818
+
819
+ search do
820
+ searchable_fields :title
821
+ placeholder "Search tasks..."
822
+ filter :all, label: "All", default: true
823
+ filter :active, label: "Active", scope: :active
824
+ filter :completed, label: "Completed", scope: :completed
825
+ end
826
+
827
+ action :create, type: :built_in, on: :collection, label: "New Task", icon: "plus"
828
+ action :show, type: :built_in, on: :single, icon: "eye"
829
+ action :edit, type: :built_in, on: :single, icon: "pencil"
830
+ action :destroy, type: :built_in, on: :single, icon: "trash", confirm: true, style: :danger
831
+ end
832
+ ```
833
+
834
+ Key concepts:
835
+ - **`"task_list.title"`** — dot-notation traverses the `belongs_to` association to display the related list's title
836
+ - **`label: "List"`** — overrides the auto-generated column header for dot-notation fields
837
+ - **`input_type: :association_select`** — renders a `<select>` dropdown populated from the target model's records (uses `label_method` for display text)
838
+ - **`renderer: :badge`** — renders enum values as colored badges
839
+ - **`filter`** — creates tabbed filters that apply named scopes from the model
840
+
841
+ <details>
842
+ <summary>YAML equivalent</summary>
843
+
844
+ ```yaml
845
+ # config/lcp_ruby/presenters/task.yml
846
+ presenter:
847
+ name: task
848
+ model: task
849
+ label: "Tasks"
850
+ slug: tasks
851
+ icon: check-square
852
+
853
+ index:
854
+ default_sort: { field: created_at, direction: desc }
855
+ per_page: 25
856
+ empty_message: "No tasks yet. Create your first task to get started."
857
+ table_columns:
858
+ - { field: title, link_to: show, sortable: true }
859
+ - { field: "task_list.title", label: "List", sortable: true }
860
+ - { field: status, renderer: badge, sortable: true }
861
+ - { field: due_date, sortable: true }
862
+
863
+ show:
864
+ layout:
865
+ - section: "Task Details"
866
+ columns: 2
867
+ fields:
868
+ - { field: title, renderer: heading }
869
+ - { field: status, renderer: badge }
870
+ - { field: "task_list.title", label: "List" }
871
+ - { field: due_date }
872
+ - { field: notes }
873
+
874
+ form:
875
+ sections:
876
+ - title: "Task Details"
877
+ columns: 2
878
+ fields:
879
+ - { field: title, placeholder: "What needs to be done?", autofocus: true }
880
+ - { field: task_list_id, input_type: association_select }
881
+ - { field: status, input_type: select }
882
+ - { field: due_date, input_type: date }
883
+ - title: "Notes"
884
+ fields:
885
+ - { field: notes, input_type: textarea, placeholder: "Additional details..." }
886
+
887
+ search:
888
+ enabled: true
889
+ searchable_fields: [title]
890
+ placeholder: "Search tasks..."
891
+ predefined_filters:
892
+ - { name: all, label: "All", default: true }
893
+ - { name: active, label: "Active", scope: active }
894
+ - { name: completed, label: "Completed", scope: completed }
895
+
896
+ actions:
897
+ collection:
898
+ - { name: create, type: built_in, label: "New Task", icon: plus }
899
+ single:
900
+ - { name: show, type: built_in, icon: eye }
901
+ - { name: edit, type: built_in, icon: pencil }
902
+ - { name: destroy, type: built_in, icon: trash, confirm: true, style: danger }
903
+ ```
904
+ </details>
905
+
906
+ ## Second Permissions: Task
907
+
908
+ Create `config/lcp_ruby/permissions/task.yml`:
909
+
910
+ ```yaml
911
+ permissions:
912
+ model: task
913
+
914
+ roles:
915
+ admin:
916
+ crud: [index, show, create, update, destroy]
917
+ fields: { readable: all, writable: all }
918
+ actions: all
919
+ scope: all
920
+ presenters: all
921
+
922
+ viewer:
923
+ crud: [index, show]
924
+ fields: { readable: all, writable: [] }
925
+ actions: { allowed: [] }
926
+ scope: all
927
+ presenters: all
928
+
929
+ default_role: admin
930
+ ```
931
+
932
+ ## Run and Verify: Associations
933
+
934
+ Restart the server (the database tables are created on boot when `auto_migrate` is enabled):
935
+
936
+ ```bash
937
+ bundle exec rails server
938
+ ```
939
+
940
+ Now you should see:
941
+
942
+ 1. **Navigation** — both "Task Lists" and "Tasks" in the top menu
943
+ 2. **Create a task list first** — go to Task Lists and create one (tasks need a list to belong to)
944
+ 3. **Create a task** — go to Tasks, click "New Task"; the "Task list" dropdown shows your lists
945
+ 4. **Dot-notation column** — the "List" column on the tasks index shows the related list's title
946
+ 5. **Association list** — the task list show page displays its tasks below the detail section
947
+ 6. **Filter tabs** — "All", "Active", and "Completed" tabs filter tasks by status scope
948
+
949
+ ## Adding a Custom Action
950
+
951
+ Let's add a "Mark Completed" button that sets a task's status to `completed`.
952
+
953
+ ### Step 1: Create the Action Class
954
+
955
+ Create `app/actions/task/mark_completed.rb`:
956
+
957
+ ```ruby
958
+ module LcpRuby
959
+ module HostActions
960
+ module Task
961
+ class MarkCompleted < LcpRuby::Actions::BaseAction
962
+ def call
963
+ unless record
964
+ return failure(message: "No task specified")
965
+ end
966
+
967
+ if record.status == "completed"
968
+ return failure(message: "Task is already completed")
969
+ end
970
+
971
+ record.update!(status: "completed")
972
+ success(message: "Task '#{record.title}' marked as completed!")
973
+ end
974
+ end
975
+ end
976
+ end
977
+ end
978
+ ```
979
+
980
+ The class is resolved by naming convention: `LcpRuby::HostActions::<Model>::<ActionName>`.
981
+
982
+ ### Step 2: Add the Action to the Presenter
983
+
984
+ Update `config/lcp_ruby/presenters/task.rb` — add this action alongside the existing ones:
985
+
986
+ ```ruby
987
+ action :mark_completed, type: :custom, on: :single,
988
+ label: "Mark Completed", icon: "check",
989
+ confirm: true, confirm_message: "Mark this task as completed?",
990
+ visible_when: { field: :status, operator: :not_eq, value: "completed" }
991
+ ```
992
+
993
+ The `visible_when` condition hides the button when the task is already completed.
994
+
995
+ ### Step 3: Add to Permissions
996
+
997
+ Update `config/lcp_ruby/permissions/task.yml` — change `actions: all` to an explicit list that includes `mark_completed`:
998
+
999
+ ```yaml
1000
+ permissions:
1001
+ model: task
1002
+
1003
+ roles:
1004
+ admin:
1005
+ crud: [index, show, create, update, destroy]
1006
+ fields: { readable: all, writable: all }
1007
+ actions:
1008
+ allowed: [mark_completed]
1009
+ scope: all
1010
+ presenters: all
1011
+
1012
+ viewer:
1013
+ crud: [index, show]
1014
+ fields: { readable: all, writable: [] }
1015
+ actions: { allowed: [] }
1016
+ scope: all
1017
+ presenters: all
1018
+
1019
+ default_role: admin
1020
+ ```
1021
+
1022
+ ### Step 4: Enable Auto-Discovery
1023
+
1024
+ Update `config/initializers/lcp_ruby.rb` to discover action and event handler classes:
1025
+
1026
+ ```ruby
1027
+ LcpRuby.configure do |config|
1028
+ config.authentication = :none
1029
+ end
1030
+
1031
+ Rails.application.config.after_initialize do
1032
+ app_path = Rails.root.join("app")
1033
+ LcpRuby::Actions::ActionRegistry.discover!(app_path.to_s)
1034
+ LcpRuby::Events::HandlerRegistry.discover!(app_path.to_s)
1035
+ end
1036
+ ```
1037
+
1038
+ Restart the server. Tasks that are not yet completed now show a "Mark Completed" button on the show page and in the index row actions.
1039
+
1040
+ ## Adding an Event Handler
1041
+
1042
+ The task model already declares `on_field_change :on_status_change, field: :status`. Let's create the handler that responds when a task's status changes.
1043
+
1044
+ Create `app/event_handlers/task/on_status_change.rb`:
1045
+
1046
+ ```ruby
1047
+ module LcpRuby
1048
+ module HostEventHandlers
1049
+ module Task
1050
+ class OnStatusChange < LcpRuby::Events::HandlerBase
1051
+ def self.handles_event
1052
+ "on_status_change"
1053
+ end
1054
+
1055
+ def call
1056
+ old_status = old_value("status")
1057
+ new_status = new_value("status")
1058
+ Rails.logger.info(
1059
+ "[TODO] Task '#{record.title}' status changed: #{old_status} -> #{new_status}"
1060
+ )
1061
+ end
1062
+ end
1063
+ end
1064
+ end
1065
+ end
1066
+ ```
1067
+
1068
+ Key concepts:
1069
+ - **`self.handles_event`** — returns the event name string matching the model's `on_field_change` declaration
1070
+ - **`old_value` / `new_value`** — access the previous and current field values
1071
+ - **`record`** — the affected ActiveRecord instance
1072
+ - Auto-discovered via `HandlerRegistry.discover!` (added in the previous step)
1073
+
1074
+ The class is resolved by convention: `LcpRuby::HostEventHandlers::<Model>::<HandlerName>`.
1075
+
1076
+ Restart the server, then change a task's status. Check the Rails log to see the event handler output.
1077
+
1078
+ ## Dev Workflow
1079
+
1080
+ LCP integrates with Rails' standard development reloader so most metadata edits take effect on the next request — no `pkill puma`, no restart. The exact "what reloads when" is:
1081
+
1082
+ | You edit… | What happens on next request |
1083
+ |---|---|
1084
+ | YAML / DSL Ruby files under `config/lcp_ruby/` | Auto-reload via `Engine.reload!` (registries cleared, dynamic models rebuilt, `LcpRuby.on_models_loaded` callbacks re-fire) |
1085
+ | Ruby files under `app/` (controllers, host actions, host services, custom renderers) | Zeitwerk's standard reload (class redefinition) |
1086
+ | Locale files under `config/locales/` | Rails' i18n reloader |
1087
+ | Initializer files under `config/initializers/` | Requires server restart (Rails initializer chain runs once) |
1088
+ | Gem updates / `Gemfile.lock` changes | Requires server restart |
1089
+ | `LcpRuby.configuration.*` settings | Requires server restart (read once at boot) |
1090
+
1091
+ **Important asymmetry.** Editing only an `app/`-side host file (e.g. a custom action class) reloads the **class** via Zeitwerk, but the LCP registry that holds a reference to the old class is not refreshed until the next YAML edit or manual `LcpRuby::Engine.reload!`. If you find a host action change isn't taking effect, touching any YAML file under `config/lcp_ruby/` (or simply restarting) forces the registry to rebuild.
1092
+
1093
+ **Manual reload.** From the Rails console: `LcpRuby::Engine.reload!`. Useful when you've changed a `LcpRuby.configuration.*` field or want to force a refresh without editing a watched file.
1094
+
1095
+ **Subscribing to reload events.** `ActiveSupport::Notifications` emits `boot.lcp_ruby` on every `load_metadata!` and `reload.lcp_ruby` on every successful reload. See [`docs/reference/boot_lifecycle.md`](reference/boot_lifecycle.md) § Instrumentation.
1096
+
1097
+ The full lifecycle (boot phases, hook ordering, the watcher's glob form) is documented in [`docs/reference/boot_lifecycle.md`](reference/boot_lifecycle.md).
1098
+
1099
+ ## Resetting the Database
1100
+
1101
+ LCP-managed tables are created by the platform's `SchemaManager` from your YAML/DSL model definitions — they do **not** live in `db/migrate/`. The standard Rails db lifecycle commands are wired to materialise these tables alongside Rails' own migrations:
1102
+
1103
+ | Command | Behaviour |
1104
+ |---|---|
1105
+ | `rails db:prepare` | Creates DB if missing, runs Rails migrations, then runs `lcp_ruby:ensure_tables` (post-action) so platform tables exist |
1106
+ | `rails db:setup` | Same as `db:prepare` for a fresh DB; also seeds |
1107
+ | `rails db:reset` | Drops + recreates DB via `db:setup`; inherits the platform-table fix transitively |
1108
+ | `rails db:drop db:prepare db:seed` | Works in one process — `lcp_ruby:ensure_tables` recreates platform tables before seeds run |
1109
+ | `rake lcp_ruby:ensure_tables` | Standalone task; idempotent. Runs automatically as a post-action of `db:prepare` / `db:setup`, but you can invoke it directly when needed |
1110
+
1111
+ **`db:reset` vs `db:prepare`.** Use either — both work after this change. Prior to v1 of the boot/reload lifecycle work, `db:reset` would silently leave platform tables un-created; this is no longer the case.
1112
+
1113
+ **`db:migrate`.** Runs Rails migrations only. Does **not** touch platform tables — those are managed by `SchemaManager` at boot. If you need only platform tables refreshed (rare), invoke `rake lcp_ruby:ensure_tables` directly.
1114
+
1115
+ **Adding a new model.** No migration required: define the YAML/DSL, save the file, and on the next request the dev watcher reloads metadata and `SchemaManager` adds the new table. The `auto_migrate: true` configuration default makes this work without explicit action.
1116
+
1117
+ **Removing a model.** Drop the YAML/DSL file. The platform stops registering the model on the next reload, but the **table itself is not dropped automatically** (data preservation is the safer default). To drop the table manually:
1118
+
1119
+ ```ruby
1120
+ ActiveRecord::Base.connection.drop_table("legacy_things")
1121
+ ```
1122
+
1123
+ ## Troubleshooting
1124
+
1125
+ | Problem | Cause | Solution |
1126
+ |---------|-------|----------|
1127
+ | `NoMethodError: undefined method 'lcp_role'` | User model missing role method | Add `lcp_role` method to your User model or use `authentication: :none` |
1128
+ | `MetadataError: Duplicate model` | Same model defined in both `.rb` and `.yml` | Use one format per model |
1129
+ | Action class not found | Not auto-discovered | Add `ActionRegistry.discover!` to your initializer |
1130
+ | Table not created (after `db:reset` or `db:drop db:prepare`) | Pre-v1 behaviour where Rails db tasks skipped `SchemaManager` | Fixed — `db:prepare` and `db:setup` now invoke `lcp_ruby:ensure_tables` automatically. If you've custom-overridden these tasks, ensure they still run the post-action |
1131
+ | Permission YAML edit not taking effect | Old: caches survived dev reload | Fixed — dev watcher reloads on any change under `config/lcp_ruby/`. If a change still doesn't apply, see [Dev Workflow](#dev-workflow) for what reloads vs. requires restart |
1132
+ | `Duplicate presenter '<name>'` after dev reload | Pre-v1 behaviour where reload re-ran loader on populated registries | Fixed — `Engine.reload!` now resets cleanly. Stop and restart the server once after upgrading; subsequent reloads work |
1133
+ | Host action / event handler change not visible | Zeitwerk reloaded the class but LCP registry holds old reference | Touch any YAML file under `config/lcp_ruby/` to force a reload, or run `LcpRuby::Engine.reload!` in the console |
1134
+ | Association select is empty | No records exist in the target model | Create target records first (e.g., create a task list before a task) |
1135
+ | `Pundit::NotAuthorizedError` | Missing permissions file for the model | Create a permissions YAML file or a `_default.yml` fallback |
1136
+ | Custom action button not visible | `visible_when` hides it or action not in `actions.allowed` | Check both presenter `visible_when` conditions and permissions `actions.allowed` |
1137
+ | Search returns no results | Field not included in `searchable_fields` | Add the field to the `search` block's `searchable_fields` |
1138
+ | Event handler not firing | Event not declared in model or handler not discovered | Verify `on_field_change` in model DSL, `handles_event` return value matches the event name, and `HandlerRegistry.discover!` in initializer |
1139
+
1140
+ ## Seed Data
1141
+
1142
+ To populate the database with initial records in `db/seeds.rb`, you must load metadata first — otherwise the dynamic model classes do not exist yet:
1143
+
1144
+ ```ruby
1145
+ # db/seeds.rb
1146
+
1147
+ # Required: load metadata before accessing dynamic models.
1148
+ # On normal boot this happens automatically, but seeds may run
1149
+ # before the initializer — call explicitly to be safe.
1150
+ LcpRuby::Engine.load_metadata!
1151
+
1152
+ # Access dynamic model classes via registry:
1153
+ TaskList = LcpRuby.registry.model_for("task_list")
1154
+ Task = LcpRuby.registry.model_for("task")
1155
+
1156
+ # Create records as usual:
1157
+ inbox = TaskList.create!(title: "Inbox")
1158
+ Task.create!(title: "Buy milk", task_list: inbox)
1159
+ ```
1160
+
1161
+ Key points:
1162
+ - `load_metadata!` is idempotent — safe to call even if already loaded
1163
+ - `model_for` returns the dynamic ActiveRecord class (e.g., `LcpRuby::Dynamic::TaskList`)
1164
+ - Assigning to a constant is optional but convenient for readability
1165
+
1166
+ ## Next Steps
1167
+
1168
+ - [Host Application Guide](guides/host-application.md) — Full app bootstrap, optional dependencies (XLSX, charts, metrics), available feature generators
1169
+ - [Models Reference](reference/models.md) — All field types, validations, associations, scopes, and events
1170
+ - [Model DSL Reference](reference/model-dsl.md) — Full Ruby DSL syntax for models
1171
+ - [Presenters Reference](reference/presenters.md) — All index, show, form, search, and action options
1172
+ - [Presenter DSL Reference](reference/presenter-dsl.md) — Full Ruby DSL syntax for presenters (with inheritance)
1173
+ - [Permissions Reference](reference/permissions.md) — Field overrides, record rules, scope types
1174
+ - [Types Reference](reference/types.md) — Business types (email, phone, url, color) and custom types
1175
+ - [Custom Types Guide](guides/custom-types.md) — Practical custom type examples
1176
+ - [Attachments Guide](guides/attachments.md) — File upload with Active Storage
1177
+ - [Custom Actions](guides/custom-actions.md) — Advanced action patterns
1178
+ - [Event Handlers](guides/event-handlers.md) — Async handlers, lifecycle events
1179
+ - [Conditional Rendering](guides/conditional-rendering.md) — `visible_when` and `disable_when` on fields, sections, and actions
1180
+ - [Extensibility Guide](guides/extensibility.md) — Transforms, validators, defaults, computed fields, condition services
1181
+ - [View Groups Guide](guides/view-groups.md) — Multi-view navigation and view switcher
1182
+ - [i18n Reference](reference/i18n.md) — Translating model names, field labels, enums, menu items, and UI strings
1183
+ - [Menu Guide](guides/menu.md) — Custom navigation menus
1184
+ - [Custom Fields Guide](guides/custom-fields.md) — Runtime user-defined fields
1185
+ - [Developer Tools](guides/developer-tools.md) — Validate configuration, generate ERD diagrams, inspect permissions
1186
+ - [Engine Configuration](reference/engine-configuration.md) — All `LcpRuby.configure` options
1187
+ - [Example Apps](examples.md) — Complete TODO and CRM walkthroughs