open-loam 0.1.0 → 0.2.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 (273) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +48 -8
  3. data/LICENSE +1 -1
  4. data/README.md +24 -24
  5. data/app/jobs/{loam → open_loam}/custom_field_reindex_job.rb +6 -6
  6. data/app/jobs/{loam → open_loam}/event_delivery_job.rb +8 -8
  7. data/app/jobs/{loam → open_loam}/event_redelivery_sweep_job.rb +4 -4
  8. data/app/jobs/{loam → open_loam}/webhook_delivery_job.rb +7 -7
  9. data/app/models/{loam → open_loam}/api_token.rb +7 -7
  10. data/app/models/{loam → open_loam}/audit_record.rb +3 -3
  11. data/app/models/{loam → open_loam}/auth_attempt.rb +5 -5
  12. data/app/models/{loam → open_loam}/business_rule.rb +10 -10
  13. data/app/models/{loam → open_loam}/business_rule_run.rb +5 -5
  14. data/app/models/{loam → open_loam}/comment.rb +9 -9
  15. data/app/models/{loam → open_loam}/config.rb +7 -7
  16. data/app/models/{loam → open_loam}/custom_field_value.rb +5 -5
  17. data/app/models/{loam → open_loam}/dashboard_widget.rb +5 -5
  18. data/app/models/open_loam/dictionary.rb +20 -0
  19. data/app/models/{loam → open_loam}/dictionary_entry.rb +7 -7
  20. data/app/models/{loam → open_loam}/event_delivery.rb +4 -4
  21. data/app/models/{loam → open_loam}/field_definition.rb +8 -8
  22. data/app/models/{loam → open_loam}/inbound_webhook_delivery.rb +4 -4
  23. data/app/models/{loam → open_loam}/inbound_webhook_source.rb +13 -13
  24. data/app/models/{loam → open_loam}/membership.rb +6 -6
  25. data/app/models/{loam → open_loam}/mfa_credential.rb +8 -8
  26. data/app/models/{loam → open_loam}/notification.rb +10 -10
  27. data/app/models/{loam → open_loam}/pending_action.rb +23 -23
  28. data/app/models/{loam → open_loam}/perspective.rb +5 -5
  29. data/app/models/{loam → open_loam}/progress_job.rb +7 -7
  30. data/app/models/{loam → open_loam}/record_lock.rb +5 -5
  31. data/app/models/{loam → open_loam}/scheduled_job.rb +7 -7
  32. data/app/models/open_loam/search_token.rb +9 -0
  33. data/app/models/{loam → open_loam}/sso_identity.rb +4 -4
  34. data/app/models/{loam → open_loam}/sso_provider.rb +8 -8
  35. data/app/models/open_loam/tenant.rb +20 -0
  36. data/app/models/{loam → open_loam}/translation.rb +5 -5
  37. data/app/models/{loam → open_loam}/webhook_endpoint.rb +6 -6
  38. data/app/views/{loam → open_loam}/attachments/_attachments.html.erb +1 -1
  39. data/app/views/{loam → open_loam}/comments/_comments.html.erb +1 -1
  40. data/app/views/{loam → open_loam}/custom_fields/_fields.html.erb +2 -2
  41. data/lib/generators/{loam → open_loam}/entity/entity_generator.rb +9 -9
  42. data/lib/generators/{loam → open_loam}/entity/templates/api_controller.rb +1 -1
  43. data/lib/generators/{loam → open_loam}/entity/templates/controller.rb +21 -21
  44. data/lib/generators/{loam → open_loam}/entity/templates/entity_test.rb +12 -12
  45. data/lib/generators/{loam → open_loam}/entity/templates/migration.rb +5 -5
  46. data/lib/generators/{loam → open_loam}/entity/templates/model.rb +10 -10
  47. data/lib/generators/{loam → open_loam}/entity/templates/policy.rb +1 -1
  48. data/lib/generators/{loam → open_loam}/entity/templates/views/_form.html.erb +4 -4
  49. data/lib/generators/{loam → open_loam}/entity/templates/views/deleted.html.erb +7 -7
  50. data/lib/generators/open_loam/entity/templates/views/edit.html.erb +3 -0
  51. data/lib/generators/open_loam/entity/templates/views/index.html.erb +90 -0
  52. data/lib/generators/open_loam/entity/templates/views/new.html.erb +3 -0
  53. data/lib/generators/open_loam/entity/templates/views/show.html.erb +36 -0
  54. data/lib/generators/{loam → open_loam}/install/install_generator.rb +47 -47
  55. data/lib/generators/open_loam/install/templates/AGENTS.md +341 -0
  56. data/lib/generators/{loam → open_loam}/install/templates/admin/api_docs_controller.rb +2 -2
  57. data/lib/generators/{loam → open_loam}/install/templates/admin/api_docs_index.html.erb +1 -1
  58. data/lib/generators/{loam → open_loam}/install/templates/admin/api_tokens_controller.rb +1 -1
  59. data/lib/generators/{loam → open_loam}/install/templates/admin/base_controller.rb +38 -38
  60. data/lib/generators/{loam → open_loam}/install/templates/admin/business_rules_controller.rb +7 -7
  61. data/lib/generators/{loam → open_loam}/install/templates/admin/business_rules_form.html.erb +2 -2
  62. data/lib/generators/{loam → open_loam}/install/templates/admin/comments_controller.rb +4 -4
  63. data/lib/generators/{loam → open_loam}/install/templates/admin/configs_controller.rb +9 -9
  64. data/lib/generators/open_loam/install/templates/admin/dashboard_controller.rb +10 -0
  65. data/lib/generators/{loam → open_loam}/install/templates/admin/dashboard_widgets_controller.rb +5 -5
  66. data/lib/generators/{loam → open_loam}/install/templates/admin/dictionaries_controller.rb +5 -5
  67. data/lib/generators/{loam → open_loam}/install/templates/admin/dictionaries_form.html.erb +1 -1
  68. data/lib/generators/{loam → open_loam}/install/templates/admin/dictionary_entries_controller.rb +2 -2
  69. data/lib/generators/{loam → open_loam}/install/templates/admin/event_deliveries_controller.rb +5 -5
  70. data/lib/generators/{loam → open_loam}/install/templates/admin/event_deliveries_index.html.erb +1 -1
  71. data/lib/generators/{loam → open_loam}/install/templates/admin/events_controller.rb +5 -5
  72. data/lib/generators/{loam → open_loam}/install/templates/admin/features_controller.rb +9 -9
  73. data/lib/generators/{loam → open_loam}/install/templates/admin/field_definitions_controller.rb +5 -5
  74. data/lib/generators/{loam → open_loam}/install/templates/admin/field_definitions_new.html.erb +2 -2
  75. data/lib/generators/{loam → open_loam}/install/templates/admin/history_controller.rb +7 -7
  76. data/lib/generators/{loam → open_loam}/install/templates/admin/history_index.html.erb +1 -1
  77. data/lib/generators/{loam → open_loam}/install/templates/admin/imports_controller.rb +12 -12
  78. data/lib/generators/{loam → open_loam}/install/templates/admin/inbound_webhook_sources_controller.rb +6 -6
  79. data/lib/generators/{loam → open_loam}/install/templates/admin/inbound_webhook_sources_new.html.erb +2 -2
  80. data/lib/generators/open_loam/install/templates/admin/layout.html.erb +76 -0
  81. data/lib/generators/{loam → open_loam}/install/templates/admin/mfa_controller.rb +6 -6
  82. data/lib/generators/{loam → open_loam}/install/templates/admin/notifications_controller.rb +3 -3
  83. data/lib/generators/{loam → open_loam}/install/templates/admin/overrides_controller.rb +3 -3
  84. data/lib/generators/{loam → open_loam}/install/templates/admin/overrides_index.html.erb +2 -2
  85. data/lib/generators/{loam → open_loam}/install/templates/admin/pending_actions_controller.rb +3 -3
  86. data/lib/generators/{loam → open_loam}/install/templates/admin/perspectives_controller.rb +7 -7
  87. data/lib/generators/{loam → open_loam}/install/templates/admin/perspectives_index.html.erb +1 -1
  88. data/lib/generators/open_loam/install/templates/admin/progress_jobs_controller.rb +19 -0
  89. data/lib/generators/{loam → open_loam}/install/templates/admin/progress_jobs_index.html.erb +1 -1
  90. data/lib/generators/{loam → open_loam}/install/templates/admin/record_locks_controller.rb +4 -4
  91. data/lib/generators/{loam → open_loam}/install/templates/admin/scheduled_jobs_controller.rb +7 -7
  92. data/lib/generators/{loam → open_loam}/install/templates/admin/scheduled_jobs_form.html.erb +1 -1
  93. data/lib/generators/{loam → open_loam}/install/templates/admin/scheduled_jobs_index.html.erb +1 -1
  94. data/lib/generators/{loam → open_loam}/install/templates/admin/search_controller.rb +5 -5
  95. data/lib/generators/{loam → open_loam}/install/templates/admin/sessions_controller.rb +32 -32
  96. data/lib/generators/{loam → open_loam}/install/templates/admin/sso_providers_controller.rb +6 -6
  97. data/lib/generators/{loam → open_loam}/install/templates/admin/sso_providers_form.html.erb +2 -2
  98. data/lib/generators/{loam → open_loam}/install/templates/admin/sudo_controller.rb +5 -5
  99. data/lib/generators/{loam → open_loam}/install/templates/admin/sudo_new.html.erb +1 -1
  100. data/lib/generators/{loam → open_loam}/install/templates/admin/translations_controller.rb +7 -7
  101. data/lib/generators/{loam → open_loam}/install/templates/admin/translations_index.html.erb +3 -3
  102. data/lib/generators/{loam → open_loam}/install/templates/admin/webhook_endpoints_controller.rb +4 -4
  103. data/lib/generators/{loam → open_loam}/install/templates/admin/webhook_endpoints_index.html.erb +1 -1
  104. data/lib/generators/{loam → open_loam}/install/templates/admin.css +1 -1
  105. data/lib/generators/{loam → open_loam}/install/templates/api_base_controller.rb +15 -15
  106. data/lib/generators/{loam → open_loam}/install/templates/guardrails_test.rb +17 -17
  107. data/lib/generators/{loam → open_loam}/install/templates/import_job.rb +7 -7
  108. data/lib/generators/{loam → open_loam}/install/templates/inbound_webhooks_controller.rb +4 -4
  109. data/lib/generators/{loam → open_loam}/install/templates/initializer.rb +74 -74
  110. data/lib/generators/open_loam/install/templates/migrations/create_open_loam_api_tokens.rb +15 -0
  111. data/lib/generators/open_loam/install/templates/migrations/create_open_loam_audit_records.rb +14 -0
  112. data/lib/generators/{loam/install/templates/migrations/create_loam_auth_attempts.rb → open_loam/install/templates/migrations/create_open_loam_auth_attempts.rb} +3 -3
  113. data/lib/generators/{loam/install/templates/migrations/create_loam_business_rules.rb → open_loam/install/templates/migrations/create_open_loam_business_rules.rb} +10 -10
  114. data/lib/generators/open_loam/install/templates/migrations/create_open_loam_comments.rb +13 -0
  115. data/lib/generators/{loam/install/templates/migrations/create_loam_configs.rb → open_loam/install/templates/migrations/create_open_loam_configs.rb} +7 -7
  116. data/lib/generators/open_loam/install/templates/migrations/create_open_loam_custom_field_values.rb +19 -0
  117. data/lib/generators/open_loam/install/templates/migrations/create_open_loam_dashboard_widgets.rb +12 -0
  118. data/lib/generators/open_loam/install/templates/migrations/create_open_loam_dictionaries.rb +11 -0
  119. data/lib/generators/{loam/install/templates/migrations/create_loam_dictionary_entries.rb → open_loam/install/templates/migrations/create_open_loam_dictionary_entries.rb} +6 -6
  120. data/lib/generators/{loam/install/templates/migrations/create_loam_event_deliveries.rb → open_loam/install/templates/migrations/create_open_loam_event_deliveries.rb} +5 -5
  121. data/lib/generators/{loam/install/templates/migrations/create_loam_field_definitions.rb → open_loam/install/templates/migrations/create_open_loam_field_definitions.rb} +4 -4
  122. data/lib/generators/{loam/install/templates/migrations/create_loam_inbound_webhooks.rb → open_loam/install/templates/migrations/create_open_loam_inbound_webhooks.rb} +9 -9
  123. data/lib/generators/open_loam/install/templates/migrations/create_open_loam_memberships.rb +11 -0
  124. data/lib/generators/{loam/install/templates/migrations/create_loam_mfa_credentials.rb → open_loam/install/templates/migrations/create_open_loam_mfa_credentials.rb} +4 -4
  125. data/lib/generators/open_loam/install/templates/migrations/create_open_loam_notifications.rb +15 -0
  126. data/lib/generators/{loam/install/templates/migrations/create_loam_pending_actions.rb → open_loam/install/templates/migrations/create_open_loam_pending_actions.rb} +9 -9
  127. data/lib/generators/{loam/install/templates/migrations/create_loam_perspectives.rb → open_loam/install/templates/migrations/create_open_loam_perspectives.rb} +5 -5
  128. data/lib/generators/{loam/install/templates/migrations/create_loam_progress_jobs.rb → open_loam/install/templates/migrations/create_open_loam_progress_jobs.rb} +5 -5
  129. data/lib/generators/open_loam/install/templates/migrations/create_open_loam_record_locks.rb +16 -0
  130. data/lib/generators/{loam/install/templates/migrations/create_loam_scheduled_jobs.rb → open_loam/install/templates/migrations/create_open_loam_scheduled_jobs.rb} +5 -5
  131. data/lib/generators/open_loam/install/templates/migrations/create_open_loam_search_tokens.rb +18 -0
  132. data/lib/generators/{loam/install/templates/migrations/create_loam_sso_providers.rb → open_loam/install/templates/migrations/create_open_loam_sso_providers.rb} +12 -12
  133. data/lib/generators/open_loam/install/templates/migrations/create_open_loam_tenants.rb +9 -0
  134. data/lib/generators/open_loam/install/templates/migrations/create_open_loam_translations.rb +15 -0
  135. data/lib/generators/open_loam/install/templates/migrations/create_open_loam_webhook_endpoints.rb +13 -0
  136. data/lib/generators/{loam → open_loam}/install/templates/migrations/create_users.rb +1 -1
  137. data/lib/generators/{loam → open_loam}/install/templates/user.rb +5 -5
  138. data/lib/generators/{loam → open_loam}/primary_key_options.rb +23 -23
  139. data/lib/open-loam.rb +2 -2
  140. data/lib/{loam → open_loam}/attachable.rb +4 -4
  141. data/lib/{loam → open_loam}/auditable.rb +23 -23
  142. data/lib/{loam → open_loam}/auth_throttle.rb +10 -10
  143. data/lib/{loam → open_loam}/base32.rb +1 -1
  144. data/lib/{loam → open_loam}/bulk.rb +7 -7
  145. data/lib/{loam → open_loam}/business_rules/actions.rb +7 -7
  146. data/lib/{loam → open_loam}/business_rules/condition.rb +5 -5
  147. data/lib/{loam → open_loam}/business_rules.rb +19 -19
  148. data/lib/{loam → open_loam}/commentable.rb +6 -6
  149. data/lib/{loam → open_loam}/configs.rb +19 -19
  150. data/lib/{loam → open_loam}/cron.rb +2 -2
  151. data/lib/{loam → open_loam}/csv.rb +2 -2
  152. data/lib/{loam → open_loam}/current.rb +5 -5
  153. data/lib/{loam → open_loam}/custom_field_index.rb +23 -23
  154. data/lib/{loam → open_loam}/custom_fields.rb +17 -17
  155. data/lib/{loam → open_loam}/dashboard.rb +5 -5
  156. data/lib/{loam → open_loam}/dictionaries.rb +12 -12
  157. data/lib/{loam → open_loam}/durable_events.rb +19 -19
  158. data/lib/{loam → open_loam}/encryptable.rb +33 -33
  159. data/lib/{loam → open_loam}/encryption/cipher.rb +3 -3
  160. data/lib/{loam → open_loam}/encryption/key_provider.rb +3 -3
  161. data/lib/{loam → open_loam}/encryption.rb +11 -11
  162. data/lib/open_loam/engine.rb +57 -0
  163. data/lib/{loam → open_loam}/enrichers.rb +5 -5
  164. data/lib/{loam → open_loam}/errors.rb +10 -10
  165. data/lib/{loam → open_loam}/eval.rb +2 -2
  166. data/lib/{loam → open_loam}/event_stream.rb +14 -14
  167. data/lib/{loam → open_loam}/eventful.rb +12 -12
  168. data/lib/{loam → open_loam}/events.rb +5 -5
  169. data/lib/{loam → open_loam}/export.rb +8 -8
  170. data/lib/{loam → open_loam}/features.rb +15 -15
  171. data/lib/{loam → open_loam}/generated_key.rb +6 -6
  172. data/lib/{loam → open_loam}/import.rb +12 -12
  173. data/lib/{loam → open_loam}/inbound_webhooks.rb +7 -7
  174. data/lib/{loam → open_loam}/lifecycle.rb +25 -25
  175. data/lib/{loam/locales/loam.en.yml → open_loam/locales/open_loam.en.yml} +5 -5
  176. data/lib/{loam → open_loam}/mcp/server.rb +9 -9
  177. data/lib/{loam → open_loam}/mcp.rb +21 -21
  178. data/lib/{loam → open_loam}/notifications.rb +5 -5
  179. data/lib/{loam → open_loam}/open_api.rb +16 -16
  180. data/lib/{loam → open_loam}/overrides.rb +10 -10
  181. data/lib/{loam → open_loam}/pending_actions.rb +9 -9
  182. data/lib/{loam → open_loam}/permissions.rb +8 -8
  183. data/lib/{loam → open_loam}/perspectives.rb +9 -9
  184. data/lib/{loam → open_loam}/policy.rb +6 -6
  185. data/lib/{loam → open_loam}/progress.rb +6 -6
  186. data/lib/{loam → open_loam}/record_locks.rb +9 -9
  187. data/lib/{loam → open_loam}/scheduler.rb +20 -20
  188. data/lib/{loam → open_loam}/search/driver.rb +3 -3
  189. data/lib/{loam → open_loam}/search/like_driver.rb +5 -5
  190. data/lib/{loam → open_loam}/search/token_driver.rb +15 -15
  191. data/lib/{loam → open_loam}/search.rb +5 -5
  192. data/lib/{loam → open_loam}/searchable.rb +22 -22
  193. data/lib/{loam → open_loam}/soft_deletable.rb +10 -10
  194. data/lib/{loam → open_loam}/sso/claims.rb +1 -1
  195. data/lib/{loam → open_loam}/sso/fake_provider.rb +1 -1
  196. data/lib/{loam → open_loam}/sso/http_client.rb +3 -3
  197. data/lib/{loam → open_loam}/sso/oidc_provider.rb +2 -2
  198. data/lib/{loam → open_loam}/sso.rb +17 -17
  199. data/lib/{loam → open_loam}/telemetry.rb +6 -6
  200. data/lib/{loam → open_loam}/tenant_record.rb +10 -10
  201. data/lib/{loam → open_loam}/test_helpers.rb +4 -4
  202. data/lib/{loam → open_loam}/totp.rb +3 -3
  203. data/lib/{loam → open_loam}/translatable.rb +24 -24
  204. data/lib/{loam → open_loam}/undo.rb +11 -11
  205. data/lib/open_loam/version.rb +3 -0
  206. data/lib/{loam → open_loam}/webhooks.rb +4 -4
  207. data/lib/{loam → open_loam}/widgets.rb +9 -9
  208. data/lib/{loam → open_loam}/workflow.rb +45 -45
  209. data/lib/open_loam.rb +122 -0
  210. data/lib/tasks/{loam.rake → open_loam.rake} +43 -43
  211. data/lib/tasks/{loam_eval.rake → open_loam_eval.rake} +7 -7
  212. data/lib/tasks/open_loam_mcp.rake +20 -0
  213. metadata +242 -242
  214. data/app/models/loam/dictionary.rb +0 -20
  215. data/app/models/loam/search_token.rb +0 -9
  216. data/app/models/loam/tenant.rb +0 -20
  217. data/lib/generators/loam/entity/templates/views/edit.html.erb +0 -3
  218. data/lib/generators/loam/entity/templates/views/index.html.erb +0 -90
  219. data/lib/generators/loam/entity/templates/views/new.html.erb +0 -3
  220. data/lib/generators/loam/entity/templates/views/show.html.erb +0 -36
  221. data/lib/generators/loam/install/templates/AGENTS.md +0 -341
  222. data/lib/generators/loam/install/templates/admin/dashboard_controller.rb +0 -10
  223. data/lib/generators/loam/install/templates/admin/layout.html.erb +0 -76
  224. data/lib/generators/loam/install/templates/admin/progress_jobs_controller.rb +0 -19
  225. data/lib/generators/loam/install/templates/migrations/create_loam_api_tokens.rb +0 -15
  226. data/lib/generators/loam/install/templates/migrations/create_loam_audit_records.rb +0 -14
  227. data/lib/generators/loam/install/templates/migrations/create_loam_comments.rb +0 -13
  228. data/lib/generators/loam/install/templates/migrations/create_loam_custom_field_values.rb +0 -19
  229. data/lib/generators/loam/install/templates/migrations/create_loam_dashboard_widgets.rb +0 -12
  230. data/lib/generators/loam/install/templates/migrations/create_loam_dictionaries.rb +0 -11
  231. data/lib/generators/loam/install/templates/migrations/create_loam_memberships.rb +0 -11
  232. data/lib/generators/loam/install/templates/migrations/create_loam_notifications.rb +0 -15
  233. data/lib/generators/loam/install/templates/migrations/create_loam_record_locks.rb +0 -16
  234. data/lib/generators/loam/install/templates/migrations/create_loam_search_tokens.rb +0 -18
  235. data/lib/generators/loam/install/templates/migrations/create_loam_tenants.rb +0 -9
  236. data/lib/generators/loam/install/templates/migrations/create_loam_translations.rb +0 -15
  237. data/lib/generators/loam/install/templates/migrations/create_loam_webhook_endpoints.rb +0 -13
  238. data/lib/loam/engine.rb +0 -57
  239. data/lib/loam/version.rb +0 -3
  240. data/lib/loam.rb +0 -122
  241. data/lib/tasks/loam_mcp.rake +0 -20
  242. /data/lib/generators/{loam → open_loam}/install/templates/admin/api_tokens_index.html.erb +0 -0
  243. /data/lib/generators/{loam → open_loam}/install/templates/admin/business_rules_edit.html.erb +0 -0
  244. /data/lib/generators/{loam → open_loam}/install/templates/admin/business_rules_index.html.erb +0 -0
  245. /data/lib/generators/{loam → open_loam}/install/templates/admin/business_rules_new.html.erb +0 -0
  246. /data/lib/generators/{loam → open_loam}/install/templates/admin/configs_edit.html.erb +0 -0
  247. /data/lib/generators/{loam → open_loam}/install/templates/admin/configs_index.html.erb +0 -0
  248. /data/lib/generators/{loam → open_loam}/install/templates/admin/dashboard_index.html.erb +0 -0
  249. /data/lib/generators/{loam → open_loam}/install/templates/admin/dashboard_widgets_index.html.erb +0 -0
  250. /data/lib/generators/{loam → open_loam}/install/templates/admin/dictionaries_edit.html.erb +0 -0
  251. /data/lib/generators/{loam → open_loam}/install/templates/admin/dictionaries_index.html.erb +0 -0
  252. /data/lib/generators/{loam → open_loam}/install/templates/admin/dictionaries_new.html.erb +0 -0
  253. /data/lib/generators/{loam → open_loam}/install/templates/admin/features_index.html.erb +0 -0
  254. /data/lib/generators/{loam → open_loam}/install/templates/admin/field_definitions_index.html.erb +0 -0
  255. /data/lib/generators/{loam → open_loam}/install/templates/admin/imports_new.html.erb +0 -0
  256. /data/lib/generators/{loam → open_loam}/install/templates/admin/imports_preview.html.erb +0 -0
  257. /data/lib/generators/{loam → open_loam}/install/templates/admin/imports_summary.html.erb +0 -0
  258. /data/lib/generators/{loam → open_loam}/install/templates/admin/inbound_webhook_sources_index.html.erb +0 -0
  259. /data/lib/generators/{loam → open_loam}/install/templates/admin/mfa_activated.html.erb +0 -0
  260. /data/lib/generators/{loam → open_loam}/install/templates/admin/mfa_new.html.erb +0 -0
  261. /data/lib/generators/{loam → open_loam}/install/templates/admin/mfa_show.html.erb +0 -0
  262. /data/lib/generators/{loam → open_loam}/install/templates/admin/notifications_index.html.erb +0 -0
  263. /data/lib/generators/{loam → open_loam}/install/templates/admin/pagination.rb +0 -0
  264. /data/lib/generators/{loam → open_loam}/install/templates/admin/pending_actions_index.html.erb +0 -0
  265. /data/lib/generators/{loam → open_loam}/install/templates/admin/scheduled_jobs_edit.html.erb +0 -0
  266. /data/lib/generators/{loam → open_loam}/install/templates/admin/scheduled_jobs_new.html.erb +0 -0
  267. /data/lib/generators/{loam → open_loam}/install/templates/admin/search_index.html.erb +0 -0
  268. /data/lib/generators/{loam → open_loam}/install/templates/admin/sessions_mfa_challenge.html.erb +0 -0
  269. /data/lib/generators/{loam → open_loam}/install/templates/admin/sessions_new.html.erb +0 -0
  270. /data/lib/generators/{loam → open_loam}/install/templates/admin/sso_providers_edit.html.erb +0 -0
  271. /data/lib/generators/{loam → open_loam}/install/templates/admin/sso_providers_index.html.erb +0 -0
  272. /data/lib/generators/{loam → open_loam}/install/templates/admin/sso_providers_new.html.erb +0 -0
  273. /data/lib/generators/{loam → open_loam}/install/templates/admin/webhook_endpoints_new.html.erb +0 -0
@@ -1,4 +1,4 @@
1
- module Loam
1
+ module OpenLoam
2
2
  module BusinessRules
3
3
  # The typed action vocabulary — a FIXED, safe set the engine dispatches. No
4
4
  # arbitrary code: an action is a json descriptor with a `type` and known
@@ -9,7 +9,7 @@ module Loam
9
9
 
10
10
  # Run one action against the record that triggered the rule. Returns a
11
11
  # short label of what it did (for the execution log). `:veto` is the
12
- # block_transition signal (see Loam::BusinessRules.veto?).
12
+ # block_transition signal (see OpenLoam::BusinessRules.veto?).
13
13
  def self.run(action, record)
14
14
  case action["type"].to_s
15
15
  when "notify" then run_notify(action, record)
@@ -24,10 +24,10 @@ module Loam
24
24
  title = action["title"].to_s
25
25
  body = action["body"]
26
26
  if action["role"].present?
27
- Loam::Notifications.notify_role(action["role"], title: title, body: body)
27
+ OpenLoam::Notifications.notify_role(action["role"], title: title, body: body)
28
28
  elsif action["user_id"].present?
29
29
  user = User.find_by(id: action["user_id"])
30
- Loam::Notifications.notify(user, title: title, body: body) if user
30
+ OpenLoam::Notifications.notify(user, title: title, body: body) if user
31
31
  end
32
32
  "notify"
33
33
  end
@@ -35,7 +35,7 @@ module Loam
35
35
  # Publish validates the name format (raising InvalidEventNameError), so a
36
36
  # malformed event name is caught by the engine's per-rule isolation.
37
37
  def self.run_emit_event(action)
38
- Loam::Events.publish(action["name"], (action["payload"] || {}).symbolize_keys)
38
+ OpenLoam::Events.publish(action["name"], (action["payload"] || {}).symbolize_keys)
39
39
  "emit_event(#{action["name"]})"
40
40
  end
41
41
 
@@ -65,7 +65,7 @@ module Loam
65
65
  end
66
66
 
67
67
  def self.refuse_workflow_column!(record, field)
68
- return unless record.class.respond_to?(:loam_workflow) && record.class.loam_workflow&.column == field
68
+ return unless record.class.respond_to?(:open_loam_workflow) && record.class.open_loam_workflow&.column == field
69
69
 
70
70
  raise ArgumentError, "set_field must not write the workflow column #{field.inspect} — use a transition"
71
71
  end
@@ -83,7 +83,7 @@ module Loam
83
83
  # but never write one whose tenant is not the tenant in context.
84
84
  def self.refuse_cross_tenant!(record)
85
85
  return unless record.respond_to?(:tenant_id)
86
- return if record.tenant_id == Loam.tenant!.id
86
+ return if record.tenant_id == OpenLoam.tenant!.id
87
87
 
88
88
  raise ArgumentError, "set_field refuses a record outside the current tenant"
89
89
  end
@@ -1,4 +1,4 @@
1
- module Loam
1
+ module OpenLoam
2
2
  module BusinessRules
3
3
  # The SAFE condition evaluator — the critical security boundary of the rules
4
4
  # engine. A rule is DATA an admin edits, so this must NEVER run arbitrary
@@ -8,7 +8,7 @@ module Loam
8
8
  # else is refused — no `send` of arbitrary methods, no SQL, no eval.
9
9
  module Condition
10
10
  OPS = %w[eq neq gt gte lt lte in contains present blank].freeze
11
- REFUSED = :__loam_field_refused__
11
+ REFUSED = :__open_loam_field_refused__
12
12
 
13
13
  def self.matches?(node, record)
14
14
  node = node.is_a?(Hash) ? node : {}
@@ -48,7 +48,7 @@ module Loam
48
48
  elsif custom_field?(record, field)
49
49
  begin
50
50
  record.custom_field(field)
51
- rescue Loam::UnknownCustomFieldError
51
+ rescue OpenLoam::UnknownCustomFieldError
52
52
  REFUSED
53
53
  end
54
54
  else
@@ -59,8 +59,8 @@ module Loam
59
59
  def self.refused_column?(klass, field)
60
60
  return true if field == "tenant_id"
61
61
 
62
- klass.respond_to?(:loam_encrypted_attributes) &&
63
- klass.loam_encrypted_attributes.map(&:to_s).include?(field)
62
+ klass.respond_to?(:open_loam_encrypted_attributes) &&
63
+ klass.open_loam_encrypted_attributes.map(&:to_s).include?(field)
64
64
  end
65
65
 
66
66
  def self.custom_field?(record, field)
@@ -1,12 +1,12 @@
1
- require "loam/business_rules/condition"
2
- require "loam/business_rules/actions"
1
+ require "open_loam/business_rules/condition"
2
+ require "open_loam/business_rules/actions"
3
3
 
4
- module Loam
5
- # The engine that evaluates Loam::BusinessRule rows: WHEN a trigger fires and
4
+ module OpenLoam
5
+ # The engine that evaluates OpenLoam::BusinessRule rows: WHEN a trigger fires and
6
6
  # the condition holds, THEN run the actions — in the event's tenant context,
7
7
  # in priority order, each rule isolated so one failure never breaks dispatch.
8
8
  #
9
- # It listens to every Loam event (like Loam::Webhooks), so a tenant can add a
9
+ # It listens to every OpenLoam event (like OpenLoam::Webhooks), so a tenant can add a
10
10
  # rule from the admin without a reboot. Evaluation runs INLINE in whatever
11
11
  # published the event — cheap for the prototype; a job-based dispatcher is the
12
12
  # scaling path.
@@ -15,19 +15,19 @@ module Loam
15
15
  # rules, but only so deep, so a self-triggering rule terminates.
16
16
 
17
17
  class << self
18
- # Wired once from Loam::Engine. Idempotent — subscribing twice would run
19
- # every rule twice (see Loam::Webhooks.subscribe!).
18
+ # Wired once from OpenLoam::Engine. Idempotent — subscribing twice would run
19
+ # every rule twice (see OpenLoam::Webhooks.subscribe!).
20
20
  def subscribe!
21
- @subscription ||= Loam::Events.subscribe_all { |event_name, payload| on_event(event_name, payload) }
21
+ @subscription ||= OpenLoam::Events.subscribe_all { |event_name, payload| on_event(event_name, payload) }
22
22
  end
23
23
 
24
24
  def on_event(event_name, payload)
25
- tenant = Loam::Tenant.find_by(id: payload[:tenant_id])
25
+ tenant = OpenLoam::Tenant.find_by(id: payload[:tenant_id])
26
26
  return if tenant.nil?
27
27
 
28
- Loam.as_tenant(tenant) do
28
+ OpenLoam.as_tenant(tenant) do
29
29
  within_depth_guard do
30
- Loam::BusinessRule.active.by_priority.each do |rule|
30
+ OpenLoam::BusinessRule.active.by_priority.each do |rule|
31
31
  next unless rule.matches_trigger?(event_name)
32
32
 
33
33
  run_rule(rule, subject_for(rule, payload), event_name)
@@ -40,7 +40,7 @@ module Loam
40
40
  # active rules for the record's entity type (optionally filtered to a
41
41
  # trigger) in priority order.
42
42
  def evaluate(record, trigger: nil)
43
- Loam::BusinessRule.active.for_entity(record.class.base_class.name).by_priority.each do |rule|
43
+ OpenLoam::BusinessRule.active.for_entity(record.class.base_class.name).by_priority.each do |rule|
44
44
  next if trigger && !rule.matches_trigger?(trigger)
45
45
 
46
46
  run_rule(rule, record, trigger)
@@ -51,7 +51,7 @@ module Loam
51
51
  # holds, veto this transition? Consulted by a workflow BEFORE it moves (see
52
52
  # the demo's DamageReport). Evaluate-only — no actions run, nothing logged.
53
53
  def veto?(record, trigger)
54
- Loam::BusinessRule.active.for_entity(record.class.base_class.name).by_priority.any? do |rule|
54
+ OpenLoam::BusinessRule.active.for_entity(record.class.base_class.name).by_priority.any? do |rule|
55
55
  rule.matches_trigger?(trigger) &&
56
56
  rule.action_list.any? { |action| action["type"].to_s == "block_transition" } &&
57
57
  Condition.matches?(rule.condition_tree, record)
@@ -81,7 +81,7 @@ module Loam
81
81
  # deterministic "condition didn't match" ones (readable from the rule).
82
82
  return if !matched && error.nil?
83
83
 
84
- Loam::BusinessRuleRun.create!(
84
+ OpenLoam::BusinessRuleRun.create!(
85
85
  business_rule: rule,
86
86
  subject_type: record&.class&.base_class&.name,
87
87
  subject_id: record&.id,
@@ -102,21 +102,21 @@ module Loam
102
102
  # A rule may ONLY target a tenant-scoped model. This is the security
103
103
  # boundary: a global model like `User` has no tenant default scope, so a
104
104
  # find_by(id:) would reach across tenants — refusing anything that is not
105
- # a Loam::TenantRecord closes that, and a TenantRecord.find_by can only
105
+ # a OpenLoam::TenantRecord closes that, and a TenantRecord.find_by can only
106
106
  # ever return a record in the CURRENT tenant even if an id is injected.
107
- return nil unless klass.is_a?(Class) && klass < Loam::TenantRecord
107
+ return nil unless klass.is_a?(Class) && klass < OpenLoam::TenantRecord
108
108
 
109
109
  klass.find_by(id: payload[:id])
110
110
  end
111
111
 
112
112
  def within_depth_guard
113
- depth = Thread.current[:loam_rule_depth] ||= 0
113
+ depth = Thread.current[:open_loam_rule_depth] ||= 0
114
114
  return if depth >= MAX_DEPTH
115
115
 
116
- Thread.current[:loam_rule_depth] = depth + 1
116
+ Thread.current[:open_loam_rule_depth] = depth + 1
117
117
  yield
118
118
  ensure
119
- Thread.current[:loam_rule_depth] = depth if depth
119
+ Thread.current[:open_loam_rule_depth] = depth if depth
120
120
  end
121
121
  end
122
122
  end
@@ -1,8 +1,8 @@
1
- module Loam
1
+ module OpenLoam
2
2
  # Discussion on a record:
3
3
  #
4
- # equipment.comment!("Hydraulics serviced") # as Loam.actor
5
- # equipment.loam_comments.oldest_first
4
+ # equipment.comment!("Hydraulics serviced") # as OpenLoam.actor
5
+ # equipment.open_loam_comments.oldest_first
6
6
  #
7
7
  # Included by every generated entity. Comments are tenant-scoped like their
8
8
  # subject, so a discussion can never be read from another tenant.
@@ -10,13 +10,13 @@ module Loam
10
10
  extend ActiveSupport::Concern
11
11
 
12
12
  included do
13
- has_many :loam_comments, as: :commentable, class_name: "Loam::Comment", dependent: :destroy
13
+ has_many :open_loam_comments, as: :commentable, class_name: "OpenLoam::Comment", dependent: :destroy
14
14
  end
15
15
 
16
16
  # Author defaults to whoever is acting — the same person the audit trail
17
17
  # and the event payload would name.
18
- def comment!(body, author: Loam::Current.actor)
19
- loam_comments.create!(body: body, author: author)
18
+ def comment!(body, author: OpenLoam::Current.actor)
19
+ open_loam_comments.create!(body: body, author: author)
20
20
  end
21
21
  end
22
22
  end
@@ -1,18 +1,18 @@
1
- module Loam
1
+ module OpenLoam
2
2
  # The one way to read and write per-tenant settings.
3
3
  #
4
- # Loam::Configs.get("rental.late_fee_per_day") # resolved for the current tenant
5
- # Loam::Configs.set("rental.late_fee_per_day", 45) # this tenant's override
6
- # Loam::Configs.set("rental.currency", "PLN", scope: :global)
7
- # Loam::Configs.reset("rental.late_fee_per_day") # drop the override → fall back
4
+ # OpenLoam::Configs.get("rental.late_fee_per_day") # resolved for the current tenant
5
+ # OpenLoam::Configs.set("rental.late_fee_per_day", 45) # this tenant's override
6
+ # OpenLoam::Configs.set("rental.currency", "PLN", scope: :global)
7
+ # OpenLoam::Configs.reset("rental.late_fee_per_day") # drop the override → fall back
8
8
  #
9
9
  # Resolution order, most specific first:
10
10
  # 1. the current tenant's OVERRIDE row (tenant_id = current tenant)
11
11
  # 2. the GLOBAL row (tenant_id NULL)
12
- # 3. the declared default in Loam.config_defaults[key]
12
+ # 3. the declared default in OpenLoam.config_defaults[key]
13
13
  # 4. the `default:` argument (nil)
14
14
  #
15
- # Reads are memoized per request in Loam::Current.config_cache, keyed by
15
+ # Reads are memoized per request in OpenLoam::Current.config_cache, keyed by
16
16
  # [key, tenant_id], and the whole cache is dropped on any write. That is the
17
17
  # deliberately-simple prototype cache; a Rails.cache-backed layer shared across
18
18
  # requests is the scaling path, and it would slot in behind this same API.
@@ -36,7 +36,7 @@ module Loam
36
36
  end
37
37
 
38
38
  # Write a setting. scope: :tenant writes the current tenant's override and
39
- # requires a tenant in context (a missing one raises, like every Loam
39
+ # requires a tenant in context (a missing one raises, like every OpenLoam
40
40
  # write); scope: :global writes the app-wide row (tenant_id NULL). Upsert.
41
41
  def set(key, value, scope: :tenant)
42
42
  key = key.to_s
@@ -66,8 +66,8 @@ module Loam
66
66
  # defaults, plus any global or current-tenant rows already written. Sorted
67
67
  # and de-duplicated, for the settings screen.
68
68
  def defined_keys
69
- rows = Loam::Config.where(tenant_id: [nil, Loam.tenant&.id]).distinct.pluck(:key)
70
- (Loam.config_defaults.keys + rows).map(&:to_s).uniq.sort
69
+ rows = OpenLoam::Config.where(tenant_id: [nil, OpenLoam.tenant&.id]).distinct.pluck(:key)
70
+ (OpenLoam.config_defaults.keys + rows).map(&:to_s).uniq.sort
71
71
  end
72
72
 
73
73
  private
@@ -76,39 +76,39 @@ module Loam
76
76
  # the caller then applies its own `default:` without caching it.
77
77
  def resolve(key)
78
78
  if (tenant_id = current_tenant_id)
79
- override = Loam::Config.find_by(key: key, tenant_id: tenant_id)
79
+ override = OpenLoam::Config.find_by(key: key, tenant_id: tenant_id)
80
80
  return [true, override.value_json] if override
81
81
  end
82
82
 
83
- global = Loam::Config.find_by(key: key, tenant_id: nil)
83
+ global = OpenLoam::Config.find_by(key: key, tenant_id: nil)
84
84
  return [true, global.value_json] if global
85
85
 
86
- return [true, Loam.config_defaults[key]] if Loam.config_defaults.key?(key)
86
+ return [true, OpenLoam.config_defaults[key]] if OpenLoam.config_defaults.key?(key)
87
87
 
88
88
  [false, nil]
89
89
  end
90
90
 
91
91
  # The row(s) a write/read targets. :global is the tenant_id NULL row;
92
92
  # :tenant is the current tenant's — which requires a tenant in context,
93
- # so Loam.tenant! raises MissingTenantError when there is none.
93
+ # so OpenLoam.tenant! raises MissingTenantError when there is none.
94
94
  def row_for(key, scope)
95
95
  case scope
96
- when :global then Loam::Config.where(key: key, tenant_id: nil)
97
- when :tenant then Loam::Config.where(key: key, tenant_id: Loam.tenant!.id)
96
+ when :global then OpenLoam::Config.where(key: key, tenant_id: nil)
97
+ when :tenant then OpenLoam::Config.where(key: key, tenant_id: OpenLoam.tenant!.id)
98
98
  else raise ArgumentError, "unknown config scope #{scope.inspect} (use :tenant or :global)"
99
99
  end
100
100
  end
101
101
 
102
102
  def current_tenant_id
103
- Loam.tenant&.id
103
+ OpenLoam.tenant&.id
104
104
  end
105
105
 
106
106
  def cache
107
- Loam::Current.config_cache ||= {}
107
+ OpenLoam::Current.config_cache ||= {}
108
108
  end
109
109
 
110
110
  def clear_cache
111
- Loam::Current.config_cache = {}
111
+ OpenLoam::Current.config_cache = {}
112
112
  end
113
113
  end
114
114
  end
@@ -1,9 +1,9 @@
1
1
  require "set"
2
2
 
3
- module Loam
3
+ module OpenLoam
4
4
  # A small, dependency-free "next run" calculator for a standard 5-field cron
5
5
  # expression ("min hour dom month dow") plus an "interval:N" (every N seconds)
6
- # form — same stdlib-only spirit as Loam::Totp / Loam::Base32. Timezone-aware;
6
+ # form — same stdlib-only spirit as OpenLoam::Totp / OpenLoam::Base32. Timezone-aware;
7
7
  # always returns UTC. Supports `*`, lists (`1,15`), ranges (`1-5`), and steps
8
8
  # (`*/15`, `0-30/10`), and the classic cron day-of-month / day-of-week OR quirk
9
9
  # (when BOTH are restricted, a match on either fires).
@@ -1,9 +1,9 @@
1
- module Loam
1
+ module OpenLoam
2
2
  # CSV formula-injection defense. A cell whose value starts with =, +, -, @, or
3
3
  # a tab/CR is treated as a FORMULA by Excel/Google Sheets when the file is
4
4
  # opened — so `=cmd|...` or `=HYPERLINK(...)` in imported/exported data can run.
5
5
  # Prefixing such a value with a single quote neutralizes it while leaving the
6
- # visible text intact. Applied on every CSV cell Loam writes (export + the
6
+ # visible text intact. Applied on every CSV cell OpenLoam writes (export + the
7
7
  # import error file).
8
8
  module Csv
9
9
  DANGEROUS = /\A[=+\-@\t\r]/
@@ -1,20 +1,20 @@
1
1
  require "active_support/current_attributes"
2
2
 
3
- module Loam
3
+ module OpenLoam
4
4
  # Per-request (and per-job) execution context. Every tenant-scoped query,
5
5
  # audit record, and published event reads from here.
6
6
  class Current < ActiveSupport::CurrentAttributes
7
- # config_cache memoizes resolved Loam::Configs values for the duration of
7
+ # config_cache memoizes resolved OpenLoam::Configs values for the duration of
8
8
  # one request/job, keyed by [key, tenant_id]. It resets with everything else
9
9
  # here, so a value can never be read stale across requests.
10
10
  #
11
- # mutation_mode is the approval-gate seam (Loam::PendingActions): nil/:direct
11
+ # mutation_mode is the approval-gate seam (OpenLoam::PendingActions): nil/:direct
12
12
  # means writes commit normally; :confirm means a caller (an MCP tool acting
13
13
  # for an AI agent) stages writes for human approval instead. It lives here so
14
14
  # it is per-request and resets automatically.
15
- # dictionary_cache memoizes resolved Loam::Dictionaries lookups for one
15
+ # dictionary_cache memoizes resolved OpenLoam::Dictionaries lookups for one
16
16
  # request/job, keyed by [kind, key, tenant_id] — same posture as config_cache.
17
- # locale is the current content-translation language (Loam::Translatable) —
17
+ # locale is the current content-translation language (OpenLoam::Translatable) —
18
18
  # request state like tenant/actor, set in a before_action and reset here.
19
19
  attribute :tenant, :actor, :config_cache, :mutation_mode, :dictionary_cache, :locale
20
20
  end
@@ -1,12 +1,12 @@
1
- module Loam
2
- # The read-model index for custom fields (Loam::CustomFieldValue) — a typed-EAV
1
+ module OpenLoam
2
+ # The read-model index for custom fields (OpenLoam::CustomFieldValue) — a typed-EAV
3
3
  # projection that makes custom-field filter/sort/search index-backed.
4
4
  #
5
- # Loam::CustomFieldIndex.filter(DamageReport, "severity", "eq", "critical") # a relation
6
- # Loam::CustomFieldIndex.order(DamageReport, "severity", :asc)
7
- # Loam::CustomFieldIndex.reindex(DamageReport) # rebuild
5
+ # OpenLoam::CustomFieldIndex.filter(DamageReport, "severity", "eq", "critical") # a relation
6
+ # OpenLoam::CustomFieldIndex.order(DamageReport, "severity", :asc)
7
+ # OpenLoam::CustomFieldIndex.reindex(DamageReport) # rebuild
8
8
  #
9
- # SAFETY: `field_key` must name a real Loam::FieldDefinition (no arbitrary
9
+ # SAFETY: `field_key` must name a real OpenLoam::FieldDefinition (no arbitrary
10
10
  # keys); values are cast to the declared type; queries are tenant-scoped
11
11
  # throughout (index rows carry tenant_id, the model relation is default-scoped),
12
12
  # so a filter can't reach across tenants. Encrypted data lives in real columns,
@@ -16,7 +16,7 @@ module Loam
16
16
 
17
17
  module_function
18
18
 
19
- # --- maintenance (called from Loam::CustomFields) ---
19
+ # --- maintenance (called from OpenLoam::CustomFields) ---
20
20
 
21
21
  # Re-project one record's custom fields (delete + insert). Soft-delete keeps
22
22
  # the rows (the filter's base scope hides the record anyway — the same
@@ -26,18 +26,18 @@ module Loam
26
26
  return unless model.respond_to?(:custom_field_definitions)
27
27
 
28
28
  type = index_type(model)
29
- Loam::CustomFieldValue.where(indexable_type: type, indexable_id: record.id).delete_all
29
+ OpenLoam::CustomFieldValue.where(indexable_type: type, indexable_id: record.id).delete_all
30
30
 
31
31
  rows = model.custom_field_definitions.filter_map { |definition| row_for(record, definition, type) }
32
- Loam::CustomFieldValue.insert_all(rows) if rows.any?
32
+ OpenLoam::CustomFieldValue.insert_all(rows) if rows.any?
33
33
  end
34
34
 
35
35
  def remove(record)
36
- Loam::CustomFieldValue.where(indexable_type: index_type(record.class), indexable_id: record.id).delete_all
36
+ OpenLoam::CustomFieldValue.where(indexable_type: index_type(record.class), indexable_id: record.id).delete_all
37
37
  end
38
38
 
39
39
  def reindex(model)
40
- Loam::CustomFieldValue.where(indexable_type: index_type(model)).delete_all
40
+ OpenLoam::CustomFieldValue.where(indexable_type: index_type(model)).delete_all
41
41
  model.find_each { |record| project(record) }
42
42
  end
43
43
 
@@ -47,7 +47,7 @@ module Loam
47
47
  field_key = field_key.to_s
48
48
  refuse_unknown_field!(model, field_key)
49
49
  refuse_unreadable_field!(model, field_key)
50
- raise Loam::Error, "unknown custom-field op #{op.inspect}" unless OPS.include?(op.to_s)
50
+ raise OpenLoam::Error, "unknown custom-field op #{op.inspect}" unless OPS.include?(op.to_s)
51
51
 
52
52
  if covered?(model, field_key)
53
53
  self.partial = false
@@ -89,12 +89,12 @@ module Loam
89
89
  self.partial = true
90
90
  schedule_reindex(model)
91
91
  end
92
- table = Loam::CustomFieldValue.table_name
92
+ table = OpenLoam::CustomFieldValue.table_name
93
93
  conn = model.connection
94
94
  join = "LEFT JOIN #{table} ON #{table}.indexable_type = #{conn.quote(index_type(model))} " \
95
95
  "AND #{table}.indexable_id = #{model.table_name}.id " \
96
96
  "AND #{table}.field_key = #{conn.quote(field_key.to_s)} " \
97
- "AND #{table}.tenant_id = #{Loam.tenant!.id}"
97
+ "AND #{table}.tenant_id = #{OpenLoam.tenant!.id}"
98
98
  model.joins(join).order(Arel.sql("#{table}.value_text #{dir.to_s.casecmp('desc').zero? ? 'DESC' : 'ASC'}"))
99
99
  end
100
100
 
@@ -132,22 +132,22 @@ module Loam
132
132
  # Was the last filter/order served over an incomplete index? The admin surfaces
133
133
  # this as an honest "results may be incomplete, reindexing…".
134
134
  def partial?
135
- Thread.current[:loam_index_partial] == true
135
+ Thread.current[:open_loam_index_partial] == true
136
136
  end
137
137
 
138
138
  def partial=(value)
139
- Thread.current[:loam_index_partial] = value
139
+ Thread.current[:open_loam_index_partial] = value
140
140
  end
141
141
 
142
142
  # Enqueue a background reindex to heal a gap — DEDUPED so a hot gappy field
143
143
  # doesn't enqueue one per request. In-process dedup here (single-process
144
144
  # prototype); a DB/cache marker is the multi-process path.
145
145
  def schedule_reindex(model)
146
- key = [ Loam.tenant!.id, model.base_class.name ]
146
+ key = [ OpenLoam.tenant!.id, model.base_class.name ]
147
147
  return if pending_reindex.include?(key)
148
148
 
149
149
  pending_reindex << key
150
- Loam::CustomFieldReindexJob.perform_later(Loam.tenant!.id, model.base_class.name)
150
+ OpenLoam::CustomFieldReindexJob.perform_later(OpenLoam.tenant!.id, model.base_class.name)
151
151
  end
152
152
 
153
153
  def clear_pending(tenant_id, model_name)
@@ -188,7 +188,7 @@ module Loam
188
188
  # --- internals ---
189
189
 
190
190
  def base(model)
191
- Loam::CustomFieldValue.where(indexable_type: index_type(model)) # tenant-scoped by default_scope
191
+ OpenLoam::CustomFieldValue.where(indexable_type: index_type(model)) # tenant-scoped by default_scope
192
192
  end
193
193
 
194
194
  def index_type(model_or_class)
@@ -235,7 +235,7 @@ module Loam
235
235
 
236
236
  def refuse_unknown_field!(model, field_key)
237
237
  known = model.respond_to?(:custom_field_definitions) && model.custom_field_definitions.exists?(name: field_key)
238
- raise Loam::Error, "no custom field #{field_key.inspect} on #{model.name}" unless known
238
+ raise OpenLoam::Error, "no custom field #{field_key.inspect} on #{model.name}" unless known
239
239
  end
240
240
 
241
241
  # THE oracle guard: filtering or sorting on a custom field the current role
@@ -243,16 +243,16 @@ module Loam
243
243
  # records match. Enforced against the current actor's role; a system/background
244
244
  # context (no actor — reindex, a business rule) is trusted and not gated.
245
245
  def refuse_unreadable_field!(model, field_key)
246
- actor = Loam::Current.actor
246
+ actor = OpenLoam::Current.actor
247
247
  return if actor.nil?
248
248
 
249
249
  definition = model.custom_field_definitions.find_by(name: field_key.to_s)
250
250
  return if definition.nil? # unknown field is refuse_unknown_field!'s job
251
251
 
252
- role = Loam::Membership.find_by(user_id: actor.id)&.role
252
+ role = OpenLoam::Membership.find_by(user_id: actor.id)&.role
253
253
  return if definition.readable_by?(role)
254
254
 
255
- raise Loam::FieldAccessError, "custom field #{field_key.inspect} is not readable by #{role.inspect}"
255
+ raise OpenLoam::FieldAccessError, "custom field #{field_key.inspect} is not readable by #{role.inspect}"
256
256
  end
257
257
 
258
258
  def sanitize_like(value)
@@ -1,35 +1,35 @@
1
- module Loam
1
+ module OpenLoam
2
2
  # Runtime, migration-free fields — stored in the `custom_fields` json
3
3
  # column every generated entity table carries. Included automatically by
4
- # `rails g loam:entity`. Shape is declared at runtime via a
5
- # Loam::FieldDefinition (typically through the admin "Field definitions"
4
+ # `rails g open_loam:entity`. Shape is declared at runtime via a
5
+ # OpenLoam::FieldDefinition (typically through the admin "Field definitions"
6
6
  # screen), not in code — that's what makes it migration-free.
7
7
  #
8
8
  # equipment.custom_field(:serial_number) # => "SN-123" (cast)
9
9
  # equipment.set_custom_field(:serial_number, "SN-123")
10
10
  #
11
- # Reading/writing a name with no matching Loam::FieldDefinition for this
12
- # tenant + entity raises Loam::UnknownCustomFieldError immediately — the
13
- # same "fail loudly at the access site" philosophy as Loam.tenant!.
11
+ # Reading/writing a name with no matching OpenLoam::FieldDefinition for this
12
+ # tenant + entity raises OpenLoam::UnknownCustomFieldError immediately — the
13
+ # same "fail loudly at the access site" philosophy as OpenLoam.tenant!.
14
14
  module CustomFields
15
15
  extend ActiveSupport::Concern
16
16
 
17
17
  included do
18
- # Keep the read-model index (Loam::CustomFieldIndex) current so custom-field
18
+ # Keep the read-model index (OpenLoam::CustomFieldIndex) current so custom-field
19
19
  # filter/sort is index-backed. Re-project only when the custom_fields column
20
20
  # actually changed (a soft-delete touches only deleted_at, so the rows stay
21
21
  # and the base scope hides the record — the L-912 posture). A no-op for a
22
- # model with no custom_fields column. Guarded by respond_to? so Loam::
22
+ # model with no custom_fields column. Guarded by respond_to? so OpenLoam::
23
23
  # CustomFields stays includable in a plain class for a DSL-only test.
24
24
  if respond_to?(:after_save)
25
- after_save :loam_reindex_custom_fields, if: :loam_custom_fields_dirty?
26
- after_destroy :loam_deindex_custom_fields
25
+ after_save :open_loam_reindex_custom_fields, if: :open_loam_custom_fields_dirty?
26
+ after_destroy :open_loam_deindex_custom_fields
27
27
  end
28
28
  end
29
29
 
30
30
  class_methods do
31
31
  def custom_field_definitions
32
- Loam::FieldDefinition.where(entity_type: name)
32
+ OpenLoam::FieldDefinition.where(entity_type: name)
33
33
  end
34
34
  end
35
35
 
@@ -53,15 +53,15 @@ module Loam
53
53
  value = custom_field(name)
54
54
  return value unless definition.field_type == "dictionary"
55
55
 
56
- Loam::Dictionaries.label_for(definition.dictionary_key, value)
56
+ OpenLoam::Dictionaries.label_for(definition.dictionary_key, value)
57
57
  end
58
58
 
59
59
  private
60
60
 
61
- def loam_reindex_custom_fields = Loam::CustomFieldIndex.project(self)
62
- def loam_deindex_custom_fields = Loam::CustomFieldIndex.remove(self)
61
+ def open_loam_reindex_custom_fields = OpenLoam::CustomFieldIndex.project(self)
62
+ def open_loam_deindex_custom_fields = OpenLoam::CustomFieldIndex.remove(self)
63
63
 
64
- def loam_custom_fields_dirty?
64
+ def open_loam_custom_fields_dirty?
65
65
  return false unless self.class.respond_to?(:custom_field_definitions)
66
66
 
67
67
  # On create every column counts as changed; on update, only re-project when
@@ -71,8 +71,8 @@ module Loam
71
71
 
72
72
  def custom_field_definition!(name)
73
73
  custom_field_definitions_by_name.fetch(name.to_s) do
74
- raise UnknownCustomFieldError, "No Loam::FieldDefinition named #{name.inspect} for #{self.class.name} " \
75
- "(tenant #{Loam.tenant&.id.inspect})"
74
+ raise UnknownCustomFieldError, "No OpenLoam::FieldDefinition named #{name.inspect} for #{self.class.name} " \
75
+ "(tenant #{OpenLoam.tenant&.id.inspect})"
76
76
  end
77
77
  end
78
78
 
@@ -1,17 +1,17 @@
1
- module Loam
1
+ module OpenLoam
2
2
  # Resolves the admin dashboard for the current tenant/actor: the ordered,
3
3
  # role-visible, computed widgets to show. Uses the tenant's configured
4
- # Loam::DashboardWidget rows (a manager arranges them); falls back to every
4
+ # OpenLoam::DashboardWidget rows (a manager arranges them); falls back to every
5
5
  # registered widget in registration order when the tenant has configured none,
6
6
  # so the dashboard is useful out of the box.
7
7
  module Dashboard
8
8
  module_function
9
9
 
10
10
  def for(actor:, role:)
11
- configured = Loam::DashboardWidget.active.ordered.pluck(:widget_key)
12
- keys = configured.presence || Loam::Widgets.keys
11
+ configured = OpenLoam::DashboardWidget.active.ordered.pluck(:widget_key)
12
+ keys = configured.presence || OpenLoam::Widgets.keys
13
13
 
14
- keys.filter_map { |key| Loam::Widgets.resolve(key, actor: actor, role: role) }
14
+ keys.filter_map { |key| OpenLoam::Widgets.resolve(key, actor: actor, role: role) }
15
15
  end
16
16
  end
17
17
  end
@@ -1,18 +1,18 @@
1
- module Loam
2
- # Read API for per-tenant managed lookup lists (Loam::Dictionary /
3
- # Loam::DictionaryEntry). Everything is tenant-scoped automatically and
4
- # memoized per request in Loam::Current.dictionary_cache (keyed with the tenant
1
+ module OpenLoam
2
+ # Read API for per-tenant managed lookup lists (OpenLoam::Dictionary /
3
+ # OpenLoam::DictionaryEntry). Everything is tenant-scoped automatically and
4
+ # memoized per request in OpenLoam::Current.dictionary_cache (keyed with the tenant
5
5
  # id, so an as_tenant switch mid-request can't read another tenant's list) —
6
- # the same simple prototype cache as Loam::Configs.
6
+ # the same simple prototype cache as OpenLoam::Configs.
7
7
  #
8
- # Loam::Dictionaries.entries("damage_severity") # active, ordered
9
- # Loam::Dictionaries.default("damage_severity") # the default entry
10
- # Loam::Dictionaries.label_for("damage_severity", "critical") # => "Critical"
8
+ # OpenLoam::Dictionaries.entries("damage_severity") # active, ordered
9
+ # OpenLoam::Dictionaries.default("damage_severity") # the default entry
10
+ # OpenLoam::Dictionaries.label_for("damage_severity", "critical") # => "Critical"
11
11
  module Dictionaries
12
12
  class << self
13
13
  # The dictionary for the current tenant, or nil.
14
14
  def get(key)
15
- memo([:dict, key.to_s]) { Loam::Dictionary.find_by(key: key.to_s) }
15
+ memo([:dict, key.to_s]) { OpenLoam::Dictionary.find_by(key: key.to_s) }
16
16
  end
17
17
 
18
18
  # Active entries, ordered by position. Empty for an unknown key.
@@ -38,14 +38,14 @@ module Loam
38
38
  end
39
39
 
40
40
  def clear_cache
41
- Loam::Current.dictionary_cache = {}
41
+ OpenLoam::Current.dictionary_cache = {}
42
42
  end
43
43
 
44
44
  private
45
45
 
46
46
  def memo(subkey)
47
- store = (Loam::Current.dictionary_cache ||= {})
48
- cache_key = subkey + [ Loam.tenant&.id ]
47
+ store = (OpenLoam::Current.dictionary_cache ||= {})
48
+ cache_key = subkey + [ OpenLoam.tenant&.id ]
49
49
  return store[cache_key] if store.key?(cache_key)
50
50
 
51
51
  store[cache_key] = yield