open-loam 0.1.1 → 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 +32 -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,17 +1,17 @@
1
- module Loam
2
- # An MCP (Model Context Protocol) server surface exposing Loam to an AI agent —
1
+ module OpenLoam
2
+ # An MCP (Model Context Protocol) server surface exposing OpenLoam to an AI agent —
3
3
  # tools-only v1 (L-302). It lets an agent DISCOVER the domain (entities, schema,
4
4
  # policy, workflow) and READ tenant-scoped records, and PROPOSE writes that are
5
5
  # STAGED for human approval — never committed. Everything runs inside the
6
6
  # tenant + actor of the API token the server authenticated with; whatever that
7
7
  # user may do, no more. Approval authority stays with a human in the admin.
8
8
  #
9
- # Two layers: the tool methods (pure, assume Loam::Current is established) and
9
+ # Two layers: the tool methods (pure, assume OpenLoam::Current is established) and
10
10
  # `handle_jsonrpc` (a pure JSON-RPC dispatcher for initialize / tools/list /
11
11
  # tools/call). The stdio transport (newline-delimited JSON-RPC) lives in
12
- # Loam::Mcp::Server.
12
+ # OpenLoam::Mcp::Server.
13
13
  #
14
- # SECURITY posture, reusing Loam's existing gates:
14
+ # SECURITY posture, reusing OpenLoam's existing gates:
15
15
  # * entity names resolve against an allowlist (API-exposed TenantRecord
16
16
  # descendants), never a bare constantize;
17
17
  # * query filters/order are whitelisted to real columns (or a known custom
@@ -32,7 +32,7 @@ module Loam
32
32
  TOOLS = [
33
33
  {
34
34
  name: "list_entities",
35
- description: "List the business entities available in this Loam tenant.",
35
+ description: "List the business entities available in this OpenLoam tenant.",
36
36
  inputSchema: { type: "object", properties: {}, additionalProperties: false }
37
37
  },
38
38
  {
@@ -72,7 +72,7 @@ module Loam
72
72
  },
73
73
  {
74
74
  name: "stage_write",
75
- description: "PROPOSE an update to one record. It is staged as a Loam PendingAction for a human manager to approve — it does NOT take effect until approved. Only policy-writable columns are accepted; the workflow column is refused (use a transition).",
75
+ description: "PROPOSE an update to one record. It is staged as a OpenLoam PendingAction for a human manager to approve — it does NOT take effect until approved. Only policy-writable columns are accepted; the workflow column is refused (use a transition).",
76
76
  inputSchema: {
77
77
  type: "object",
78
78
  properties: {
@@ -91,9 +91,9 @@ module Loam
91
91
 
92
92
  def entities
93
93
  # Models are lazy-loaded (Zeitwerk), so `descendants` is only complete after
94
- # an eager load — same as Loam::OpenApi's discovery.
94
+ # an eager load — same as OpenLoam::OpenApi's discovery.
95
95
  Rails.application.eager_load! if defined?(Rails) && Rails.respond_to?(:application)
96
- Loam::TenantRecord.descendants
96
+ OpenLoam::TenantRecord.descendants
97
97
  .reject { |model| model.name.blank? }
98
98
  .select { |model| api_exposed?(model) }
99
99
  .sort_by(&:name)
@@ -117,7 +117,7 @@ module Loam
117
117
 
118
118
  def describe_entity(entity:)
119
119
  model = resolve!(entity)
120
- policy = Loam::Policy.for(model.new)
120
+ policy = OpenLoam::Policy.for(model.new)
121
121
 
122
122
  columns = model.columns.reject { |c| c.name.end_with?("_hash") }.map do |col|
123
123
  { name: col.name, type: col.sql_type_metadata.type.to_s,
@@ -134,8 +134,8 @@ module Loam
134
134
  []
135
135
  end
136
136
 
137
- workflow = if model.respond_to?(:loam_workflow) && model.loam_workflow
138
- wf = model.loam_workflow
137
+ workflow = if model.respond_to?(:open_loam_workflow) && model.open_loam_workflow
138
+ wf = model.open_loam_workflow
139
139
  { column: wf.column, states: wf.states,
140
140
  transitions: wf.transitions.values.map { |t| { name: t.name.to_s, from: t.from, to: t.to, roles: Array(t.roles).map(&:to_s) } } }
141
141
  end
@@ -145,7 +145,7 @@ module Loam
145
145
 
146
146
  def query_entity(entity:, filters: [], order: nil, dir: "asc", limit: MAX_LIMIT)
147
147
  model = resolve!(entity)
148
- policy = Loam::Policy.for(model.new)
148
+ policy = OpenLoam::Policy.for(model.new)
149
149
  scope = apply_filters(model, model.all, filters, policy)
150
150
  scope = apply_order(model, scope, order, dir)
151
151
  capped = [ [ limit.to_i, 1 ].max, MAX_LIMIT ].min
@@ -157,8 +157,8 @@ module Loam
157
157
  def stage_write(entity:, id:, changes:)
158
158
  model = resolve!(entity)
159
159
  record = model.find(id) # tenant-scoped
160
- policy = Loam::Policy.for(record)
161
- workflow_column = model.respond_to?(:loam_workflow) ? model.loam_workflow&.column.to_s : nil
160
+ policy = OpenLoam::Policy.for(record)
161
+ workflow_column = model.respond_to?(:open_loam_workflow) ? model.open_loam_workflow&.column.to_s : nil
162
162
 
163
163
  clean = {}
164
164
  (changes || {}).each do |field, value|
@@ -177,7 +177,7 @@ module Loam
177
177
  end
178
178
  raise ToolError, "no writable changes" if clean.empty?
179
179
 
180
- action = Loam::PendingActions.stage(
180
+ action = OpenLoam::PendingActions.stage(
181
181
  summary: "MCP proposal: update #{model.name}##{id}",
182
182
  on: record, action: :update, changes: clean
183
183
  )
@@ -206,14 +206,14 @@ module Loam
206
206
  when "initialize"
207
207
  ok(id, protocolVersion: request.dig("params", "protocolVersion") || PROTOCOL_VERSION,
208
208
  capabilities: { tools: {} },
209
- serverInfo: { name: "loam", version: Loam::VERSION })
209
+ serverInfo: { name: "open_loam", version: OpenLoam::VERSION })
210
210
  when "tools/list"
211
211
  ok(id, tools: TOOLS)
212
212
  when "tools/call"
213
213
  begin
214
214
  data = call_tool(request.dig("params", "name"), request.dig("params", "arguments"))
215
215
  ok(id, content: [ { type: "text", text: JSON.generate(data) } ])
216
- rescue ToolError, Loam::Error, ActiveRecord::RecordNotFound => error
216
+ rescue ToolError, OpenLoam::Error, ActiveRecord::RecordNotFound => error
217
217
  ok(id, isError: true, content: [ { type: "text", text: error.message } ])
218
218
  end
219
219
  when "notifications/initialized", "notifications/cancelled", nil
@@ -239,8 +239,8 @@ module Loam
239
239
  # CustomFieldIndex.filter carries its own L-711 read-ACL for the current
240
240
  # actor; surface its refusal as a clean tool error.
241
241
  begin
242
- scope = scope.merge(Loam::CustomFieldIndex.filter(model, field, op, value))
243
- rescue Loam::FieldAccessError => error
242
+ scope = scope.merge(OpenLoam::CustomFieldIndex.filter(model, field, op, value))
243
+ rescue OpenLoam::FieldAccessError => error
244
244
  raise ToolError, error.message
245
245
  end
246
246
  else
@@ -274,7 +274,7 @@ module Loam
274
274
 
275
275
  def serialize(record, policy)
276
276
  model = record.class
277
- encrypted = model.respond_to?(:loam_encrypted_attributes) ? model.loam_encrypted_attributes.map(&:to_s) : []
277
+ encrypted = model.respond_to?(:open_loam_encrypted_attributes) ? model.open_loam_encrypted_attributes.map(&:to_s) : []
278
278
 
279
279
  json = {}
280
280
  policy.readable_fields(model.column_names).each do |col|
@@ -1,14 +1,14 @@
1
- module Loam
1
+ module OpenLoam
2
2
  # The one way to tell someone something inside the app.
3
3
  #
4
- # Loam::Notifications.notify(user, title: "Order approved", source: order)
5
- # Loam::Notifications.notify_role(:manager, title: "New damage report")
4
+ # OpenLoam::Notifications.notify(user, title: "Order approved", source: order)
5
+ # OpenLoam::Notifications.notify_role(:manager, title: "New damage report")
6
6
  #
7
- # Records land in the CURRENT tenant (Loam::Notification is tenant-scoped),
7
+ # Records land in the CURRENT tenant (OpenLoam::Notification is tenant-scoped),
8
8
  # so a notification can never be delivered across a tenant boundary.
9
9
  #
10
10
  # The intended pattern is event -> notification: subscribe to a domain event
11
- # in config/initializers/loam.rb and notify from there, instead of scattering
11
+ # in config/initializers/open_loam.rb and notify from there, instead of scattering
12
12
  # delivery calls through models and controllers.
13
13
  module Notifications
14
14
  # Returns the created notifications. Accepts one user or many; `source` is
@@ -1,17 +1,17 @@
1
1
  require "json"
2
2
 
3
- module Loam
3
+ module OpenLoam
4
4
  # Auto-generates an OpenAPI 3.1 document for the app's JSON API by
5
- # INTROSPECTING what Loam already knows — the generated `Api::<Plural>Controller`s,
5
+ # INTROSPECTING what OpenLoam already knows — the generated `Api::<Plural>Controller`s,
6
6
  # each entity's columns/types, its exposed `FIELDS`, its custom fields, and that
7
7
  # every endpoint is bearer-authenticated and tenant-scoped. No hand-written
8
8
  # annotations, no external gem.
9
9
  #
10
- # Loam::OpenApi.document # => a Hash conforming to OpenAPI 3.1
11
- # Loam::OpenApi.markdown # => a Markdown rendering
10
+ # OpenLoam::OpenApi.document # => a Hash conforming to OpenAPI 3.1
11
+ # OpenLoam::OpenApi.markdown # => a Markdown rendering
12
12
  #
13
13
  # The document describes the SHAPE of the API only — never tenant data. It is
14
- # served at /admin/api_docs and exported by `bin/rails loam:openapi:export`.
14
+ # served at /admin/api_docs and exported by `bin/rails open_loam:openapi:export`.
15
15
  module OpenApi
16
16
  TYPE_MAP = {
17
17
  "string" => { "type" => "string" }, "text" => { "type" => "string" },
@@ -40,13 +40,13 @@ module Loam
40
40
  }
41
41
  end
42
42
 
43
- # The Loam entities that have a generated JSON API controller. Anonymous
44
- # subclasses (Class.new(Loam::TenantRecord), common in tests) have no name,
43
+ # The OpenLoam entities that have a generated JSON API controller. Anonymous
44
+ # subclasses (Class.new(OpenLoam::TenantRecord), common in tests) have no name,
45
45
  # so model_name would raise "Class name cannot be blank" — skip them: a
46
46
  # nameless class has no controller or route to document anyway.
47
47
  def api_entities
48
48
  Rails.application.eager_load! if defined?(Rails) && Rails.respond_to?(:application)
49
- Loam::TenantRecord.descendants
49
+ OpenLoam::TenantRecord.descendants
50
50
  .reject { |model| model.name.blank? }
51
51
  .select { |model| controller_for(model) }
52
52
  .sort_by(&:name)
@@ -59,17 +59,17 @@ module Loam
59
59
  end
60
60
 
61
61
  def info
62
- name = defined?(Rails) ? Rails.application.class.module_parent_name : "Loam"
62
+ name = defined?(Rails) ? Rails.application.class.module_parent_name : "OpenLoam"
63
63
  {
64
64
  "title" => "#{name} API",
65
65
  "version" => "1.0.0",
66
- "description" => "Auto-generated from the Loam entities. Bearer-token authenticated. #{TENANCY_NOTE}"
66
+ "description" => "Auto-generated from the OpenLoam entities. Bearer-token authenticated. #{TENANCY_NOTE}"
67
67
  }
68
68
  end
69
69
 
70
70
  def security_schemes
71
71
  { "bearerAuth" => { "type" => "http", "scheme" => "bearer",
72
- "description" => "A Loam::ApiToken — identifies one user in one tenant." } }
72
+ "description" => "A OpenLoam::ApiToken — identifies one user in one tenant." } }
73
73
  end
74
74
 
75
75
  def schemas
@@ -89,7 +89,7 @@ module Loam
89
89
 
90
90
  # Request body: the writable, declared fields only — never id/tenant_id/
91
91
  # timestamps. Field-level write access is enforced per the token's role at
92
- # runtime (Loam::Policy), which a structural schema can't express per-role;
92
+ # runtime (OpenLoam::Policy), which a structural schema can't express per-role;
93
93
  # noted in the description rather than emitting a schema per role.
94
94
  def input_schema(model)
95
95
  props = {}
@@ -143,9 +143,9 @@ module Loam
143
143
  return controller::FIELDS.map(&:to_s) if controller.const_defined?(:FIELDS)
144
144
 
145
145
  # No declared FIELDS: fall back to columns, but NEVER surface an encrypted
146
- # column or its blind-index `_hash` (same exclusion as Loam::Export).
147
- encrypted = model.respond_to?(:loam_encrypted_attributes) ? model.loam_encrypted_attributes : []
148
- blind = model.respond_to?(:loam_searchable_encrypted_attributes) ? model.loam_searchable_encrypted_attributes.map { |a| "#{a}_hash" } : []
146
+ # column or its blind-index `_hash` (same exclusion as OpenLoam::Export).
147
+ encrypted = model.respond_to?(:open_loam_encrypted_attributes) ? model.open_loam_encrypted_attributes : []
148
+ blind = model.respond_to?(:open_loam_searchable_encrypted_attributes) ? model.open_loam_searchable_encrypted_attributes.map { |a| "#{a}_hash" } : []
149
149
  model.column_names - plumbing(model) - encrypted - blind
150
150
  end
151
151
 
@@ -161,7 +161,7 @@ module Loam
161
161
  end
162
162
 
163
163
  def custom_field_names(model)
164
- return [] unless model.respond_to?(:custom_field_definitions) && Loam::Current.tenant
164
+ return [] unless model.respond_to?(:custom_field_definitions) && OpenLoam::Current.tenant
165
165
 
166
166
  model.custom_field_definitions.map(&:name)
167
167
  rescue StandardError
@@ -1,13 +1,13 @@
1
- module Loam
2
- # Disable or replace an entry in one of Loam's OWN keyed registries from an
1
+ module OpenLoam
2
+ # Disable or replace an entry in one of OpenLoam's OWN keyed registries from an
3
3
  # initializer — customization without forking the gem, and without
4
4
  # monkeypatching. This is deliberately SMALL: Rails already handles structural
5
5
  # overriding (shadow a view/controller by path, prepend a module). Overrides
6
6
  # only covers the in-gem keyed registries, where path-shadowing doesn't reach:
7
7
  #
8
- # Loam::Overrides.disable(:widgets, "open_progress") # drop a built-in widget
9
- # Loam::Overrides.replace(:widgets, "audit_recent") { |actor| { kind: "count", value: 0 } }
10
- # Loam::Overrides.disable(:broadcast_events, "loam.progress.") # stop pushing an event over SSE
8
+ # OpenLoam::Overrides.disable(:widgets, "open_progress") # drop a built-in widget
9
+ # OpenLoam::Overrides.replace(:widgets, "audit_recent") { |actor| { kind: "count", value: 0 } }
10
+ # OpenLoam::Overrides.disable(:broadcast_events, "open_loam.progress.") # stop pushing an event over SSE
11
11
  #
12
12
  # THE VALUE-ADD over raw monkeypatching: a stale override (a typo, or an entry
13
13
  # that no longer exists) is caught at boot by `check!` and warned about, so a
@@ -19,7 +19,7 @@ module Loam
19
19
  # doesn't wrap those. Controllers/views/routes are NOT here — that's Rails'
20
20
  # path-shadowing job (see docs).
21
21
  module Overrides
22
- DISABLED = :__loam_disabled__
22
+ DISABLED = :__open_loam_disabled__
23
23
 
24
24
  class << self
25
25
  def disable(registry, key)
@@ -81,7 +81,7 @@ module Loam
81
81
  def check!
82
82
  found = stale
83
83
  found.each do |registry, key|
84
- message = "[loam] stale override: #{registry} has no entry #{key.inspect} to disable/replace — the override is doing nothing."
84
+ message = "[open_loam] stale override: #{registry} has no entry #{key.inspect} to disable/replace — the override is doing nothing."
85
85
  logger ? logger.warn(message) : warn(message)
86
86
  end
87
87
  found
@@ -96,9 +96,9 @@ module Loam
96
96
  # The live keys of an introspectable registry, or nil when we can't tell.
97
97
  def known_keys(registry)
98
98
  case registry.to_sym
99
- when :widgets then Loam::Widgets.keys
100
- when :broadcast_events then Loam.broadcast_events
101
- when :scheduler then defined?(Loam::Scheduler) ? Loam::Scheduler.registered.map { |d| d[:key] } : nil
99
+ when :widgets then OpenLoam::Widgets.keys
100
+ when :broadcast_events then OpenLoam.broadcast_events
101
+ when :scheduler then defined?(OpenLoam::Scheduler) ? OpenLoam::Scheduler.registered.map { |d| d[:key] } : nil
102
102
  end
103
103
  end
104
104
 
@@ -1,19 +1,19 @@
1
- module Loam
2
- # Staging and reviewing gated mutations (see Loam::PendingAction).
1
+ module OpenLoam
2
+ # Staging and reviewing gated mutations (see OpenLoam::PendingAction).
3
3
  #
4
- # pending = Loam::PendingActions.stage(
4
+ # pending = OpenLoam::PendingActions.stage(
5
5
  # summary: "Raise the excavator's daily rate to 1100",
6
6
  # on: equipment, action: :update, changes: { daily_rate: 1100 }
7
7
  # )
8
8
  # pending.preview # => { "daily_rate" => { "from" => 950, "to" => 1100 } }
9
9
  # pending.approve!(by: manager) # role-gated; executes the change
10
10
  #
11
- # `stage` NEVER touches the target — it only records the intent. Loam does not
11
+ # `stage` NEVER touches the target — it only records the intent. OpenLoam does not
12
12
  # intercept Active Record globally (that would be fragile and out of scope);
13
13
  # this is the primitive a confirm-mode write path calls instead of saving.
14
14
  module PendingActions
15
15
  class << self
16
- def stage(summary:, on:, action:, changes: {}, idempotency_key: nil, actor: Loam::Current.actor)
16
+ def stage(summary:, on:, action:, changes: {}, idempotency_key: nil, actor: OpenLoam::Current.actor)
17
17
  target_type, target_id = resolve_target(on)
18
18
  changes = changes.transform_keys(&:to_s)
19
19
  key = idempotency_key || compute_key(target_type, target_id, action, changes)
@@ -21,10 +21,10 @@ module Loam
21
21
  # The same proposal staged twice collapses to one row — but only a still
22
22
  # PENDING one. A rejected or executed proposal with this key may be
23
23
  # re-staged as a fresh pending row (the partial index allows the coexist).
24
- existing = Loam::PendingAction.pending.find_by(idempotency_key: key)
24
+ existing = OpenLoam::PendingAction.pending.find_by(idempotency_key: key)
25
25
  return existing if existing
26
26
 
27
- Loam::PendingAction.create!(
27
+ OpenLoam::PendingAction.create!(
28
28
  actor_id: actor&.id,
29
29
  action_type: action.to_s,
30
30
  target_type: target_type,
@@ -35,7 +35,7 @@ module Loam
35
35
  )
36
36
  rescue ActiveRecord::RecordNotUnique
37
37
  # Lost a concurrent double-stage race — return the pending row that won.
38
- Loam::PendingAction.pending.find_by!(idempotency_key: key)
38
+ OpenLoam::PendingAction.pending.find_by!(idempotency_key: key)
39
39
  end
40
40
 
41
41
  private
@@ -53,7 +53,7 @@ module Loam
53
53
  # the same key; a reordered hash is treated as a different proposal.
54
54
  def compute_key(target_type, target_id, action, changes)
55
55
  payload = [ target_type, target_id, action, changes.to_json ].join("|")
56
- Loam::Encryption.blind_index_scoped(payload, "tenant/#{Loam.tenant!.id}")
56
+ OpenLoam::Encryption.blind_index_scoped(payload, "tenant/#{OpenLoam.tenant!.id}")
57
57
  end
58
58
  end
59
59
  end
@@ -1,21 +1,21 @@
1
- module Loam
1
+ module OpenLoam
2
2
  # Feature-string permissions with wildcards (L-705) — a fine-grained capability
3
3
  # layer that sits UNDER the coarse role. Roles answer "manager or clerk";
4
4
  # permissions answer "may this role do `equipment.edit`" without inventing a new
5
- # role for every distinction. Orthogonal to Loam::Policy (which gates field-level
6
- # writes on a record) and to Loam::Features (a per-tenant capability switch).
5
+ # role for every distinction. Orthogonal to OpenLoam::Policy (which gates field-level
6
+ # writes on a record) and to OpenLoam::Features (a per-tenant capability switch).
7
7
  #
8
8
  # Declared once, in the initializer (like broadcast_events / scheduler defaults):
9
9
  #
10
- # Loam::Permissions.configure do
10
+ # OpenLoam::Permissions.configure do
11
11
  # role :admin, allow: "*" # everything
12
12
  # role :manager, allow: %w[equipment.* damage_report.* billing.read]
13
13
  # role :clerk, allow: %w[equipment.read damage_report.create]
14
14
  # end
15
15
  #
16
- # Loam::Permissions.allow?(:clerk, "equipment.read") # => true
17
- # Loam::Permissions.allow?(:clerk, "equipment.edit") # => false
18
- # Loam.can?("equipment.edit") # for the current actor's role
16
+ # OpenLoam::Permissions.allow?(:clerk, "equipment.read") # => true
17
+ # OpenLoam::Permissions.allow?(:clerk, "equipment.edit") # => false
18
+ # OpenLoam.can?("equipment.edit") # for the current actor's role
19
19
  #
20
20
  # DENY BY DEFAULT: a role with no matching grant (or no grants at all) is denied.
21
21
  #
@@ -72,7 +72,7 @@ module Loam
72
72
  # Tiny DSL so `configure { role ... }` reads well without a receiver.
73
73
  class DSL
74
74
  def role(name, allow:)
75
- Loam::Permissions.role(name, allow: allow)
75
+ OpenLoam::Permissions.role(name, allow: allow)
76
76
  end
77
77
  end
78
78
  end
@@ -1,20 +1,20 @@
1
- module Loam
2
- # Reading the saved views (Loam::Perspective) a user may see for an entity.
1
+ module OpenLoam
2
+ # Reading the saved views (OpenLoam::Perspective) a user may see for an entity.
3
3
  #
4
- # Loam::Perspectives.visible_to("Equipment", user: current_actor) # pick list
5
- # Loam::Perspectives.default_for("Equipment", user: current_actor) # the applicable default
6
- # Loam::Perspectives.resolve("Equipment", user:, id: params[:perspective_id])
4
+ # OpenLoam::Perspectives.visible_to("Equipment", user: current_actor) # pick list
5
+ # OpenLoam::Perspectives.default_for("Equipment", user: current_actor) # the applicable default
6
+ # OpenLoam::Perspectives.resolve("Equipment", user:, id: params[:perspective_id])
7
7
  #
8
- # Every query is tenant-scoped by Loam::Perspective. The membership role used
8
+ # Every query is tenant-scoped by OpenLoam::Perspective. The membership role used
9
9
  # for role-shared views is the user's role in the CURRENT tenant.
10
10
  module Perspectives
11
11
  class << self
12
12
  # The views this user may see for an entity: their own private ones, the
13
13
  # role-shared ones matching their membership role, and the tenant-wide
14
14
  # ones. Default(s) first, then by name. Named `visible_to` rather than
15
- # `for` so it does not read like Loam::Policy.for (which builds a policy).
15
+ # `for` so it does not read like OpenLoam::Policy.for (which builds a policy).
16
16
  def visible_to(entity_type, user:)
17
- base = Loam::Perspective.where(entity_type: entity_type.to_s)
17
+ base = OpenLoam::Perspective.where(entity_type: entity_type.to_s)
18
18
  role = membership_role(user)
19
19
 
20
20
  # Build the OR chain on UNORDERED relations — `.or` refuses to combine
@@ -55,7 +55,7 @@ module Loam
55
55
  def membership_role(user)
56
56
  return nil unless user
57
57
 
58
- Loam::Membership.find_by(user_id: user.id)&.role
58
+ OpenLoam::Membership.find_by(user_id: user.id)&.role
59
59
  end
60
60
  end
61
61
  end
@@ -1,13 +1,13 @@
1
- module Loam
1
+ module OpenLoam
2
2
  # Base policy. One policy class per entity, one instance per (actor, record)
3
3
  # pair. Action checks (read?/create?/update?/destroy?) default to "any member
4
4
  # of the current tenant"; field-level write access is declared, not coded:
5
5
  #
6
- # class EquipmentPolicy < Loam::Policy
6
+ # class EquipmentPolicy < OpenLoam::Policy
7
7
  # field :daily_rate, writable: [:manager]
8
8
  # end
9
9
  #
10
- # Roles come from Loam::Membership (actor + current tenant -> role).
10
+ # Roles come from OpenLoam::Membership (actor + current tenant -> role).
11
11
  class Policy
12
12
  class << self
13
13
  def field_rules
@@ -22,7 +22,7 @@ module Loam
22
22
  policy_class = "#{record.class.name}Policy".safe_constantize
23
23
  raise Error, "No policy defined for #{record.class.name} (expected #{record.class.name}Policy)" unless policy_class
24
24
 
25
- policy_class.new(Loam::Current.actor, record)
25
+ policy_class.new(OpenLoam::Current.actor, record)
26
26
  end
27
27
  end
28
28
 
@@ -36,7 +36,7 @@ module Loam
36
36
  def role
37
37
  return nil unless actor
38
38
 
39
- @role ||= Loam::Membership.find_by(user_id: actor.id)&.role&.to_sym
39
+ @role ||= OpenLoam::Membership.find_by(user_id: actor.id)&.role&.to_sym
40
40
  end
41
41
 
42
42
  def member? = role.present?
@@ -73,7 +73,7 @@ module Loam
73
73
  end
74
74
 
75
75
  # Same semantics as the static `field writable:` declaration, but for a
76
- # runtime Loam::FieldDefinition (see Loam::CustomFields): no
76
+ # runtime OpenLoam::FieldDefinition (see OpenLoam::CustomFields): no
77
77
  # writable_roles recorded means any member may write it.
78
78
  def custom_field_writable?(field_name)
79
79
  return false unless member?
@@ -1,8 +1,8 @@
1
- module Loam
1
+ module OpenLoam
2
2
  # Entry point for progress tracking. Start a job, then drive it through the
3
- # returned Loam::ProgressJob:
3
+ # returned OpenLoam::ProgressJob:
4
4
  #
5
- # progress = Loam::Progress.start(name: "Reindex", total: equipment.count)
5
+ # progress = OpenLoam::Progress.start(name: "Reindex", total: equipment.count)
6
6
  # equipment.find_each do |record|
7
7
  # break if progress.cancelled? # cooperative cancel
8
8
  # do_work(record)
@@ -12,18 +12,18 @@ module Loam
12
12
  #
13
13
  # The job is created in the current tenant (and stamped with the current
14
14
  # actor), so it is only visible and streamable there. In a background job,
15
- # establish the tenant with Loam.as_tenant first, like the webhook/digest jobs.
15
+ # establish the tenant with OpenLoam.as_tenant first, like the webhook/digest jobs.
16
16
  module Progress
17
17
  module_function
18
18
 
19
19
  def start(name:, total:, key: nil)
20
- Loam::ProgressJob.create!(
20
+ OpenLoam::ProgressJob.create!(
21
21
  key: key,
22
22
  name: name,
23
23
  total: total.to_i,
24
24
  completed: 0,
25
25
  status: "running",
26
- actor_id: Loam.actor&.id,
26
+ actor_id: OpenLoam.actor&.id,
27
27
  started_at: Time.current
28
28
  )
29
29
  end
@@ -1,15 +1,15 @@
1
- module Loam
2
- # Advisory record locks (Loam::RecordLock) — a "who's editing this" courtesy
1
+ module OpenLoam
2
+ # Advisory record locks (OpenLoam::RecordLock) — a "who's editing this" courtesy
3
3
  # for the multi-user admin.
4
4
  #
5
- # Loam::RecordLocks.acquire(record, by: current_actor) # take/refresh, or nil if held
6
- # Loam::RecordLocks.holder(record) # the user holding it, or nil
7
- # Loam::RecordLocks.release(record, by: current_actor) # give it up
8
- # Loam::RecordLocks.force_release(record) # manager override
5
+ # OpenLoam::RecordLocks.acquire(record, by: current_actor) # take/refresh, or nil if held
6
+ # OpenLoam::RecordLocks.holder(record) # the user holding it, or nil
7
+ # OpenLoam::RecordLocks.release(record, by: current_actor) # give it up
8
+ # OpenLoam::RecordLocks.force_release(record) # manager override
9
9
  #
10
10
  # THIS IS ADVISORY: a held lock warns, it does not hard-block — optimistic
11
11
  # locking (lock_version) is the actual guarantee that two edits can't clobber.
12
- # Every query is tenant-scoped by Loam::RecordLock, so a lock is invisible and
12
+ # Every query is tenant-scoped by OpenLoam::RecordLock, so a lock is invisible and
13
13
  # unaffectable from another tenant.
14
14
  module RecordLocks
15
15
  DEFAULT_TTL = 5.minutes
@@ -25,7 +25,7 @@ module Loam
25
25
  lock = lock_row(record)
26
26
  return nil if lock && !lock.expired? && lock.locked_by_id != by.id
27
27
 
28
- lock ||= Loam::RecordLock.new(lockable_type: type_of(record), lockable_id: record.id)
28
+ lock ||= OpenLoam::RecordLock.new(lockable_type: type_of(record), lockable_id: record.id)
29
29
  # A fresh session token when the lock is newly created or taken over from
30
30
  # an expired holder; kept as-is on a heartbeat by the same user.
31
31
  lock.token = SecureRandom.hex(16) if lock.new_record? || lock.locked_by_id != by.id
@@ -71,7 +71,7 @@ module Loam
71
71
  private
72
72
 
73
73
  def lock_row(record)
74
- Loam::RecordLock.find_by(lockable_type: type_of(record), lockable_id: record.id)
74
+ OpenLoam::RecordLock.find_by(lockable_type: type_of(record), lockable_id: record.id)
75
75
  end
76
76
 
77
77
  def type_of(record)