command_tower 0.4.0 → 0.11.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 (722) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +106 -29
  3. data/app/auth/command_tower/auth/auth_context.rb +42 -0
  4. data/app/auth/command_tower/auth/password_recovery_session_context.rb +11 -0
  5. data/app/auth/command_tower/auth/signup_session_context.rb +11 -0
  6. data/app/controllers/command_tower/admin/application_controller.rb +27 -0
  7. data/app/controllers/command_tower/admin/audit/events_controller.rb +61 -0
  8. data/app/controllers/command_tower/admin/messaging/announcements_controller.rb +27 -0
  9. data/app/controllers/command_tower/admin/users/identities_controller.rb +77 -0
  10. data/app/controllers/command_tower/admin/users/impersonation_sessions_controller.rb +33 -0
  11. data/app/controllers/command_tower/admin/users/roles_controller.rb +40 -0
  12. data/app/controllers/command_tower/admin/users_controller.rb +46 -0
  13. data/app/controllers/command_tower/admin/workspace_controller.rb +15 -0
  14. data/app/controllers/command_tower/application_controller.rb +97 -15
  15. data/app/controllers/command_tower/auth/email/availability_controller.rb +35 -0
  16. data/app/controllers/command_tower/auth/email_verification/send_controller.rb +24 -0
  17. data/app/controllers/command_tower/auth/email_verification/verify_controller.rb +41 -0
  18. data/app/controllers/command_tower/auth/identity_policy_controller.rb +14 -0
  19. data/app/controllers/command_tower/auth/impersonation_session_controller.rb +27 -0
  20. data/app/controllers/command_tower/auth/logout_controller.rb +16 -0
  21. data/app/controllers/command_tower/auth/password_recovery_session/create_controller.rb +17 -0
  22. data/app/controllers/command_tower/auth/password_reset/reset_controller.rb +35 -0
  23. data/app/controllers/command_tower/auth/password_reset/send_controller.rb +40 -0
  24. data/app/controllers/command_tower/auth/password_reset/validate_controller.rb +35 -0
  25. data/app/controllers/command_tower/auth/plain_text/login_controller.rb +22 -0
  26. data/app/controllers/command_tower/auth/principal_capabilities_controller.rb +19 -0
  27. data/app/controllers/command_tower/auth/register_controller.rb +33 -0
  28. data/app/controllers/command_tower/auth/session_controller.rb +21 -0
  29. data/app/controllers/command_tower/auth/signup_session/create_controller.rb +17 -0
  30. data/app/controllers/command_tower/auth/username/availability_controller.rb +35 -0
  31. data/app/controllers/command_tower/me/audit_events_controller.rb +59 -0
  32. data/app/controllers/command_tower/me/inbox_controller.rb +85 -0
  33. data/app/controllers/command_tower/me/name_controller.rb +37 -0
  34. data/app/controllers/command_tower/me/password_controller.rb +37 -0
  35. data/app/controllers/command_tower/me/phone_controller.rb +44 -0
  36. data/app/controllers/command_tower/me/phone_verification/verifications_controller.rb +23 -0
  37. data/app/controllers/command_tower/me/phone_verification/verify_controller.rb +34 -0
  38. data/app/controllers/command_tower/me/preferences_controller.rb +46 -0
  39. data/app/controllers/command_tower/me/pushover/verifications_controller.rb +23 -0
  40. data/app/controllers/command_tower/me/pushover_controller.rb +66 -0
  41. data/app/controllers/command_tower/me_controller.rb +19 -0
  42. data/app/controllers/command_tower/profile_controller.rb +19 -0
  43. data/app/controllers/concerns/command_tower/api/application_response_renderer.rb +87 -0
  44. data/app/controllers/concerns/command_tower/api/deserializer_failure_details.rb +22 -0
  45. data/app/controllers/concerns/command_tower/auth/authentication_boundary.rb +35 -0
  46. data/app/controllers/concerns/command_tower/auth/authorization_boundary.rb +26 -0
  47. data/app/controllers/concerns/command_tower/auth/invalid_credentials_deserializer_renderer.rb +23 -0
  48. data/app/controllers/concerns/command_tower/auth/password_recovery_session_boundary.rb +29 -0
  49. data/app/controllers/concerns/command_tower/auth/signup_session_boundary.rb +29 -0
  50. data/app/controllers/concerns/command_tower/execution/http_boundary.rb +65 -0
  51. data/app/deserializers/command_tower/deserializers/admin/messaging/create_announcement_deserializer.rb +106 -0
  52. data/app/deserializers/command_tower/deserializers/admin/scope_parameter.rb +49 -0
  53. data/app/deserializers/command_tower/deserializers/admin/users.rb +218 -0
  54. data/app/deserializers/command_tower/deserializers/application_deserializer.rb +148 -0
  55. data/app/deserializers/command_tower/deserializers/audit/events.rb +224 -0
  56. data/app/deserializers/command_tower/deserializers/auth/email_availability_deserializer.rb +19 -0
  57. data/app/deserializers/command_tower/deserializers/auth/email_verification/verify_deserializer.rb +21 -0
  58. data/app/deserializers/command_tower/deserializers/auth/password_reset/reset_deserializer.rb +31 -0
  59. data/app/deserializers/command_tower/deserializers/auth/password_reset/send_deserializer.rb +21 -0
  60. data/app/deserializers/command_tower/deserializers/auth/password_reset/validate_deserializer.rb +23 -0
  61. data/app/deserializers/command_tower/deserializers/auth/plain_text/login_deserializer.rb +24 -0
  62. data/app/deserializers/command_tower/deserializers/auth/register_deserializer.rb +42 -0
  63. data/app/deserializers/command_tower/deserializers/auth/username_availability_deserializer.rb +19 -0
  64. data/app/deserializers/command_tower/deserializers/clients/errors.rb +45 -0
  65. data/app/deserializers/command_tower/deserializers/clients/missing.rb +10 -0
  66. data/app/deserializers/command_tower/deserializers/clients/payload.rb +21 -0
  67. data/app/deserializers/command_tower/deserializers/clients/result.rb +122 -0
  68. data/app/deserializers/command_tower/deserializers/clients/types.rb +219 -0
  69. data/app/deserializers/command_tower/deserializers/coercion_result.rb +35 -0
  70. data/app/deserializers/command_tower/deserializers/failure.rb +14 -0
  71. data/app/deserializers/command_tower/deserializers/me/change_password_deserializer.rb +41 -0
  72. data/app/deserializers/command_tower/deserializers/me/phone_verification/verify_deserializer.rb +29 -0
  73. data/app/deserializers/command_tower/deserializers/me/pushover/credentials_deserializer.rb +31 -0
  74. data/app/deserializers/command_tower/deserializers/me/update_name_deserializer.rb +22 -0
  75. data/app/deserializers/command_tower/deserializers/me/update_phone_deserializer.rb +22 -0
  76. data/app/deserializers/command_tower/deserializers/messaging/inbox.rb +77 -0
  77. data/app/deserializers/command_tower/deserializers/messaging/preferences/show_deserializer.rb +17 -0
  78. data/app/deserializers/command_tower/deserializers/messaging/preferences/update_deserializer.rb +97 -0
  79. data/app/errors/command_tower/errors/account/phone_already_verified_error.rb +17 -0
  80. data/app/errors/command_tower/errors/account/phone_missing_error.rb +17 -0
  81. data/app/errors/command_tower/errors/account/phone_verification_code_invalid_error.rb +17 -0
  82. data/app/errors/command_tower/errors/account/phone_verification_expired_error.rb +17 -0
  83. data/app/errors/command_tower/errors/account/phone_verification_send_failed_error.rb +25 -0
  84. data/app/errors/command_tower/errors/account/phone_verification_stale_error.rb +17 -0
  85. data/app/errors/command_tower/errors/account/phone_verification_throttled_error.rb +24 -0
  86. data/app/errors/command_tower/errors/account/pushover_already_configured_error.rb +21 -0
  87. data/app/errors/command_tower/errors/account/pushover_capability_unavailable_error.rb +21 -0
  88. data/app/errors/command_tower/errors/account/pushover_not_configured_error.rb +21 -0
  89. data/app/errors/command_tower/errors/account/pushover_provider_unavailable_error.rb +21 -0
  90. data/app/errors/command_tower/errors/account/pushover_verification_failed_error.rb +27 -0
  91. data/app/errors/command_tower/errors/account/sms_capability_unavailable_error.rb +21 -0
  92. data/app/errors/command_tower/errors/application_error.rb +27 -0
  93. data/app/errors/command_tower/errors/auth/admin_unavailable_during_impersonation_error.rb +17 -0
  94. data/app/errors/command_tower/errors/auth/csrf_mismatch_error.rb +17 -0
  95. data/app/errors/command_tower/errors/auth/csrf_missing_error.rb +17 -0
  96. data/app/errors/command_tower/errors/auth/default_membership_assignment_error.rb +17 -0
  97. data/app/errors/command_tower/errors/auth/email_already_registered_error.rb +17 -0
  98. data/app/errors/command_tower/errors/auth/email_verification_required_error.rb +21 -0
  99. data/app/errors/command_tower/errors/auth/impersonation_session_expired_error.rb +17 -0
  100. data/app/errors/command_tower/errors/auth/impersonation_session_missing_error.rb +21 -0
  101. data/app/errors/command_tower/errors/auth/invalid_credentials_error.rb +21 -0
  102. data/app/errors/command_tower/errors/auth/nested_impersonation_error.rb +17 -0
  103. data/app/errors/command_tower/errors/auth/password_recovery_ip_rate_limit_error.rb +25 -0
  104. data/app/errors/command_tower/errors/auth/password_recovery_session_expired_error.rb +21 -0
  105. data/app/errors/command_tower/errors/auth/password_recovery_session_invalid_error.rb +21 -0
  106. data/app/errors/command_tower/errors/auth/password_recovery_session_missing_error.rb +21 -0
  107. data/app/errors/command_tower/errors/auth/password_recovery_session_rate_limit_error.rb +25 -0
  108. data/app/errors/command_tower/errors/auth/password_reset_invalid_token_error.rb +21 -0
  109. data/app/errors/command_tower/errors/auth/password_reset_unavailable_error.rb +21 -0
  110. data/app/errors/command_tower/errors/auth/self_impersonation_error.rb +21 -0
  111. data/app/errors/command_tower/errors/auth/signup_ip_rate_limit_error.rb +25 -0
  112. data/app/errors/command_tower/errors/auth/signup_session_expired_error.rb +17 -0
  113. data/app/errors/command_tower/errors/auth/signup_session_invalid_error.rb +17 -0
  114. data/app/errors/command_tower/errors/auth/signup_session_missing_error.rb +17 -0
  115. data/app/errors/command_tower/errors/auth/signup_session_rate_limit_error.rb +25 -0
  116. data/app/errors/command_tower/errors/auth/verification_code_invalid_error.rb +17 -0
  117. data/app/errors/command_tower/errors/auth/verification_send_failed_error.rb +25 -0
  118. data/app/errors/command_tower/errors/continuation_exhausted_error.rb +25 -0
  119. data/app/errors/command_tower/errors/forbidden_error.rb +19 -0
  120. data/app/errors/command_tower/errors/internal_error.rb +19 -0
  121. data/app/errors/command_tower/errors/messaging/accept_rejected_error.rb +21 -0
  122. data/app/errors/command_tower/errors/messaging/idempotency_conflict_error.rb +21 -0
  123. data/app/errors/command_tower/errors/messaging/recipient_unresolved_error.rb +21 -0
  124. data/app/errors/command_tower/errors/not_found_error.rb +19 -0
  125. data/app/errors/command_tower/errors/unauthorized_error.rb +19 -0
  126. data/app/errors/command_tower/errors/validation_error.rb +15 -0
  127. data/app/jobs/command_tower/application_job.rb +7 -0
  128. data/app/jobs/command_tower/execution/job_boundary.rb +19 -0
  129. data/app/jobs/command_tower/messaging/channel_delivery_execution_job.rb +18 -0
  130. data/app/jobs/command_tower/messaging/communications/produce_recipient_job.rb +24 -0
  131. data/app/jobs/command_tower/messaging/execution_recovery_job.rb +13 -0
  132. data/app/jobs/command_tower/messaging/handoff_job.rb +15 -0
  133. data/app/jobs/command_tower/messaging/handoff_recovery_job.rb +13 -0
  134. data/app/mailers/command_tower/application_mailer.rb +11 -1
  135. data/app/mailers/command_tower/email_verification_mailer.rb +5 -3
  136. data/app/mailers/command_tower/messaging/channel_mailer.rb +24 -0
  137. data/app/mailers/command_tower/password_reset_mailer.rb +18 -0
  138. data/app/models/command_tower/audit/event.rb +36 -0
  139. data/app/models/command_tower/impersonation/session.rb +51 -0
  140. data/app/models/command_tower/messaging/channel_delivery.rb +45 -0
  141. data/app/models/command_tower/messaging/communication.rb +60 -0
  142. data/app/models/command_tower/messaging/delivery_attempt.rb +28 -0
  143. data/app/models/command_tower/messaging/destination_plan.rb +17 -0
  144. data/app/models/command_tower/messaging/endpoint.rb +98 -0
  145. data/app/models/command_tower/messaging/endpoint_pushover_credential.rb +18 -0
  146. data/app/models/command_tower/messaging/inbox_item.rb +52 -0
  147. data/app/models/command_tower/messaging/notification_preference.rb +21 -0
  148. data/app/models/user.rb +4 -1
  149. data/app/serializers/command_tower/serializers/admin/messaging/announcement_response_serializer.rb +41 -0
  150. data/app/serializers/command_tower/serializers/admin/users.rb +69 -0
  151. data/app/serializers/command_tower/serializers/admin/workspace/manifest_serializer.rb +58 -0
  152. data/app/serializers/command_tower/serializers/application/envelope_serializer.rb +25 -0
  153. data/app/serializers/command_tower/serializers/application/error_entry_serializer.rb +18 -0
  154. data/app/serializers/command_tower/serializers/application_serializer.rb +26 -0
  155. data/app/serializers/command_tower/serializers/audit/events/filter_options_serializer.rb +44 -0
  156. data/app/serializers/command_tower/serializers/audit/events.rb +42 -0
  157. data/app/serializers/command_tower/serializers/auth/email_availability_serializer.rb +17 -0
  158. data/app/serializers/command_tower/serializers/auth/email_verification/message_response_serializer.rb +15 -0
  159. data/app/serializers/command_tower/serializers/auth/identity_policy_serializer.rb +36 -0
  160. data/app/serializers/command_tower/serializers/auth/login_response_serializer.rb +17 -0
  161. data/app/serializers/command_tower/serializers/auth/logout_response_serializer.rb +13 -0
  162. data/app/serializers/command_tower/serializers/auth/password_recovery_session_response_serializer.rb +16 -0
  163. data/app/serializers/command_tower/serializers/auth/password_reset/message_response_serializer.rb +15 -0
  164. data/app/serializers/command_tower/serializers/auth/password_reset/validate_response_serializer.rb +22 -0
  165. data/app/serializers/command_tower/serializers/auth/principal_capabilities_serializer.rb +15 -0
  166. data/app/serializers/command_tower/serializers/auth/register_response_serializer.rb +16 -0
  167. data/app/serializers/command_tower/serializers/auth/session_response_serializer.rb +40 -0
  168. data/app/serializers/command_tower/serializers/auth/signup_session_response_serializer.rb +16 -0
  169. data/app/serializers/command_tower/serializers/auth/user_serializer.rb +21 -0
  170. data/app/serializers/command_tower/serializers/auth/username_availability_serializer.rb +17 -0
  171. data/app/serializers/command_tower/serializers/impersonation/session_serializer.rb +19 -0
  172. data/app/serializers/command_tower/serializers/me/account_serializer.rb +45 -0
  173. data/app/serializers/command_tower/serializers/me/change_password_response_serializer.rb +13 -0
  174. data/app/serializers/command_tower/serializers/me/pushover_serializer.rb +59 -0
  175. data/app/serializers/command_tower/serializers/messaging/inbox.rb +45 -0
  176. data/app/serializers/command_tower/serializers/messaging/preferences/catalog_serializer.rb +17 -0
  177. data/app/serializers/command_tower/serializers/messaging/preferences/category_serializer.rb +23 -0
  178. data/app/serializers/command_tower/serializers/messaging/preferences/notification_serializer.rb +30 -0
  179. data/app/serializers/command_tower/serializers/profile/profile_serializer.rb +13 -0
  180. data/app/services/command_tower/README.md +24 -14
  181. data/app/services/command_tower/auth/request_context.rb +21 -0
  182. data/app/services/command_tower/authorize/validate.rb +58 -19
  183. data/app/services/command_tower/clients/client_base.rb +183 -0
  184. data/app/services/command_tower/clients/client_result.rb +45 -0
  185. data/app/services/command_tower/clients/const_resolution.rb +32 -0
  186. data/app/services/command_tower/clients/decoded_response.rb +16 -0
  187. data/app/services/command_tower/clients/endpoint_base.rb +242 -0
  188. data/app/services/command_tower/clients/endpoint_input.rb +18 -0
  189. data/app/services/command_tower/clients/errors/authentication_error.rb +26 -0
  190. data/app/services/command_tower/clients/errors/configuration_error.rb +10 -0
  191. data/app/services/command_tower/clients/errors/deserialization_error.rb +26 -0
  192. data/app/services/command_tower/clients/errors/discovery_error.rb +10 -0
  193. data/app/services/command_tower/clients/errors/upstream_error.rb +26 -0
  194. data/app/services/command_tower/clients/invocation.rb +61 -0
  195. data/app/services/command_tower/clients/namespace_proxy.rb +75 -0
  196. data/app/services/command_tower/clients/scoped_client.rb +88 -0
  197. data/app/services/command_tower/clients/serialized_request.rb +17 -0
  198. data/app/services/command_tower/clients/transport/error.rb +18 -0
  199. data/app/services/command_tower/clients/transport/faraday_adapter.rb +129 -0
  200. data/app/services/command_tower/clients/transport/faraday_config.rb +45 -0
  201. data/app/services/command_tower/clients/transport/request.rb +50 -0
  202. data/app/services/command_tower/clients/transport/response.rb +22 -0
  203. data/app/services/command_tower/clients/url.rb +56 -0
  204. data/app/services/command_tower/identity/phone/normalizer.rb +41 -0
  205. data/app/services/command_tower/identity/phone_verification/sms_configuration.rb +58 -0
  206. data/app/services/command_tower/identity/phone_verification/sms_transport/adapters/fake_adapter.rb +35 -0
  207. data/app/services/command_tower/identity/phone_verification/sms_transport/adapters/log_adapter.rb +34 -0
  208. data/app/services/command_tower/identity/phone_verification/sms_transport/adapters/twilio_adapter.rb +60 -0
  209. data/app/services/command_tower/identity/phone_verification/sms_transport.rb +42 -0
  210. data/app/services/command_tower/jwt/authenticate_user.rb +67 -34
  211. data/app/services/command_tower/jwt/authentication_outcome.rb +37 -0
  212. data/app/services/command_tower/jwt/decode.rb +27 -8
  213. data/app/services/command_tower/jwt/encode.rb +4 -6
  214. data/app/services/command_tower/jwt/login_create.rb +10 -8
  215. data/app/services/command_tower/login_strategy/plain_text/email_verification/required.rb +11 -9
  216. data/app/services/command_tower/messaging/accept/channel_delivery_result.rb +13 -0
  217. data/app/services/command_tower/messaging/accept/coordinator.rb +166 -0
  218. data/app/services/command_tower/messaging/accept/error.rb +9 -0
  219. data/app/services/command_tower/messaging/accept/excluded_destination.rb +24 -0
  220. data/app/services/command_tower/messaging/accept/handoff_scheduler.rb +40 -0
  221. data/app/services/command_tower/messaging/accept/idempotency_conflict_error.rb +9 -0
  222. data/app/services/command_tower/messaging/accept/illegal_override_error.rb +9 -0
  223. data/app/services/command_tower/messaging/accept/impossible_mandatory_plan_error.rb +9 -0
  224. data/app/services/command_tower/messaging/accept/invalid_preference_error.rb +9 -0
  225. data/app/services/command_tower/messaging/accept/invariant_error.rb +9 -0
  226. data/app/services/command_tower/messaging/accept/operation_logger.rb +97 -0
  227. data/app/services/command_tower/messaging/accept/persistence_error.rb +9 -0
  228. data/app/services/command_tower/messaging/accept/persister.rb +90 -0
  229. data/app/services/command_tower/messaging/accept/request_normalizer.rb +100 -0
  230. data/app/services/command_tower/messaging/accept/result.rb +99 -0
  231. data/app/services/command_tower/messaging/accept/unknown_type_error.rb +9 -0
  232. data/app/services/command_tower/messaging/accept/validation_error.rb +9 -0
  233. data/app/services/command_tower/messaging/channel_detectors.rb +52 -0
  234. data/app/services/command_tower/messaging/channels/definition.rb +24 -0
  235. data/app/services/command_tower/messaging/channels/error.rb +9 -0
  236. data/app/services/command_tower/messaging/channels/unknown_channel_error.rb +9 -0
  237. data/app/services/command_tower/messaging/channels.rb +85 -0
  238. data/app/services/command_tower/messaging/contract/communications.rb +29 -0
  239. data/app/services/command_tower/messaging/contract/error.rb +9 -0
  240. data/app/services/command_tower/messaging/contract/internal/finder.rb +43 -0
  241. data/app/services/command_tower/messaging/contract/invariant_error.rb +9 -0
  242. data/app/services/command_tower/messaging/contract/mappers/channel_delivery_mapper.rb +53 -0
  243. data/app/services/command_tower/messaging/contract/mappers/communication_mapper.rb +61 -0
  244. data/app/services/command_tower/messaging/contract/mappers/delivery_attempt_mapper.rb +27 -0
  245. data/app/services/command_tower/messaging/contract/mappers/destination_plan_mapper.rb +17 -0
  246. data/app/services/command_tower/messaging/contract/mappers/inbox_item_mapper.rb +17 -0
  247. data/app/services/command_tower/messaging/contract/not_found_error.rb +9 -0
  248. data/app/services/command_tower/messaging/contract/observability/correlation.rb +19 -0
  249. data/app/services/command_tower/messaging/contract/observability/operation_logger.rb +101 -0
  250. data/app/services/command_tower/messaging/contract/observability/publisher.rb +44 -0
  251. data/app/services/command_tower/messaging/contract/requests/find_communication.rb +21 -0
  252. data/app/services/command_tower/messaging/contract/results/channel_delivery_result.rb +25 -0
  253. data/app/services/command_tower/messaging/contract/results/communication_result.rb +22 -0
  254. data/app/services/command_tower/messaging/contract/results/delivery_attempt_result.rb +21 -0
  255. data/app/services/command_tower/messaging/contract/results/destination_plan_result.rb +11 -0
  256. data/app/services/command_tower/messaging/contract/results/inbox_item_result.rb +11 -0
  257. data/app/services/command_tower/messaging/contract/validation_error.rb +9 -0
  258. data/app/services/command_tower/messaging/delivery_retry_policy.rb +30 -0
  259. data/app/services/command_tower/messaging/endpoints/begin_verification.rb +13 -0
  260. data/app/services/command_tower/messaging/endpoints/channel_gate.rb +39 -0
  261. data/app/services/command_tower/messaging/endpoints/conflict_error.rb +9 -0
  262. data/app/services/command_tower/messaging/endpoints/create.rb +181 -0
  263. data/app/services/command_tower/messaging/endpoints/error.rb +9 -0
  264. data/app/services/command_tower/messaging/endpoints/fingerprinter.rb +50 -0
  265. data/app/services/command_tower/messaging/endpoints/invalid_transition_error.rb +9 -0
  266. data/app/services/command_tower/messaging/endpoints/lifecycle.rb +37 -0
  267. data/app/services/command_tower/messaging/endpoints/mark_invalid.rb +32 -0
  268. data/app/services/command_tower/messaging/endpoints/mark_verification_failed.rb +13 -0
  269. data/app/services/command_tower/messaging/endpoints/mark_verified.rb +13 -0
  270. data/app/services/command_tower/messaging/endpoints/not_found_error.rb +9 -0
  271. data/app/services/command_tower/messaging/endpoints/persistence.rb +91 -0
  272. data/app/services/command_tower/messaging/endpoints/pushover/verify.rb +101 -0
  273. data/app/services/command_tower/messaging/endpoints/query.rb +28 -0
  274. data/app/services/command_tower/messaging/endpoints/replace.rb +181 -0
  275. data/app/services/command_tower/messaging/endpoints/reset_verification.rb +13 -0
  276. data/app/services/command_tower/messaging/endpoints/revoke.rb +40 -0
  277. data/app/services/command_tower/messaging/endpoints/safe_view.rb +50 -0
  278. data/app/services/command_tower/messaging/endpoints/secret_box.rb +86 -0
  279. data/app/services/command_tower/messaging/endpoints/secret_reader.rb +72 -0
  280. data/app/services/command_tower/messaging/endpoints/validation_error.rb +9 -0
  281. data/app/services/command_tower/messaging/endpoints/validators/push.rb +24 -0
  282. data/app/services/command_tower/messaging/endpoints/validators/pushover.rb +68 -0
  283. data/app/services/command_tower/messaging/endpoints/validators.rb +36 -0
  284. data/app/services/command_tower/messaging/endpoints/verification.rb +39 -0
  285. data/app/services/command_tower/messaging/endpoints/verification_failed_error.rb +18 -0
  286. data/app/services/command_tower/messaging/endpoints/verification_transition.rb +20 -0
  287. data/app/services/command_tower/messaging/endpoints.rb +55 -0
  288. data/app/services/command_tower/messaging/execution/adapter_request.rb +45 -0
  289. data/app/services/command_tower/messaging/execution/adapter_result.rb +81 -0
  290. data/app/services/command_tower/messaging/execution/adapters/email/adapter.rb +78 -0
  291. data/app/services/command_tower/messaging/execution/adapters/email/configuration.rb +55 -0
  292. data/app/services/command_tower/messaging/execution/adapters/fake_adapter.rb +34 -0
  293. data/app/services/command_tower/messaging/execution/adapters/pushover/adapter.rb +107 -0
  294. data/app/services/command_tower/messaging/execution/adapters/pushover/configuration.rb +30 -0
  295. data/app/services/command_tower/messaging/execution/adapters/sms/adapter.rb +90 -0
  296. data/app/services/command_tower/messaging/execution/adapters/sms/configuration.rb +58 -0
  297. data/app/services/command_tower/messaging/execution/adapters/sms/log_adapter.rb +34 -0
  298. data/app/services/command_tower/messaging/execution/adapters/sms/twilio_http_client.rb +70 -0
  299. data/app/services/command_tower/messaging/execution/adapters/unconfigured_adapter.rb +20 -0
  300. data/app/services/command_tower/messaging/execution/attempt_ledger.rb +146 -0
  301. data/app/services/command_tower/messaging/execution/claim.rb +35 -0
  302. data/app/services/command_tower/messaging/execution/invalid_adapter_contract_error.rb +9 -0
  303. data/app/services/command_tower/messaging/execution/operation_logger.rb +237 -0
  304. data/app/services/command_tower/messaging/execution/readiness_terminal_mapping.rb +37 -0
  305. data/app/services/command_tower/messaging/execution/recovery.rb +78 -0
  306. data/app/services/command_tower/messaging/execution/resolve_recipient_address.rb +58 -0
  307. data/app/services/command_tower/messaging/execution/revalidate_readiness.rb +73 -0
  308. data/app/services/command_tower/messaging/execution/scheduler.rb +38 -0
  309. data/app/services/command_tower/messaging/execution/select_adapter.rb +63 -0
  310. data/app/services/command_tower/messaging/handoff/advance_communication.rb +39 -0
  311. data/app/services/command_tower/messaging/handoff/operation_logger.rb +78 -0
  312. data/app/services/command_tower/messaging/handoff/recovery.rb +26 -0
  313. data/app/services/command_tower/messaging/inbox/bulk_result.rb +19 -0
  314. data/app/services/command_tower/messaging/inbox/error.rb +9 -0
  315. data/app/services/command_tower/messaging/inbox/invalid_bulk_items_error.rb +19 -0
  316. data/app/services/command_tower/messaging/inbox/invariant_error.rb +9 -0
  317. data/app/services/command_tower/messaging/inbox/item_result.rb +64 -0
  318. data/app/services/command_tower/messaging/inbox/list_result.rb +18 -0
  319. data/app/services/command_tower/messaging/inbox/mutator.rb +252 -0
  320. data/app/services/command_tower/messaging/inbox/not_found_error.rb +9 -0
  321. data/app/services/command_tower/messaging/inbox/operation_logger.rb +37 -0
  322. data/app/services/command_tower/messaging/inbox/reader.rb +117 -0
  323. data/app/services/command_tower/messaging/inbox/scope.rb +24 -0
  324. data/app/services/command_tower/messaging/inbox/unread_count_result.rb +16 -0
  325. data/app/services/command_tower/messaging/inbox/validation_error.rb +9 -0
  326. data/app/services/command_tower/messaging/inbox.rb +61 -0
  327. data/app/services/command_tower/messaging/notification_types/catalog_category.rb +19 -0
  328. data/app/services/command_tower/messaging/notification_types/declaration.rb +96 -0
  329. data/app/services/command_tower/messaging/notification_types/declaration_validator.rb +152 -0
  330. data/app/services/command_tower/messaging/notification_types/duplicate_type_error.rb +9 -0
  331. data/app/services/command_tower/messaging/notification_types/error.rb +9 -0
  332. data/app/services/command_tower/messaging/notification_types/invalid_declaration_error.rb +9 -0
  333. data/app/services/command_tower/messaging/notification_types/not_found_error.rb +9 -0
  334. data/app/services/command_tower/messaging/notification_types/registry.rb +103 -0
  335. data/app/services/command_tower/messaging/notification_types/sealed_registry_error.rb +9 -0
  336. data/app/services/command_tower/messaging/notification_types.rb +37 -0
  337. data/app/services/command_tower/messaging/planner/destination_plan.rb +41 -0
  338. data/app/services/command_tower/messaging/planner/error.rb +9 -0
  339. data/app/services/command_tower/messaging/planner/excluded_destination.rb +28 -0
  340. data/app/services/command_tower/messaging/planner/illegal_override_error.rb +9 -0
  341. data/app/services/command_tower/messaging/planner/impossible_mandatory_plan_error.rb +9 -0
  342. data/app/services/command_tower/messaging/planner/invalid_evaluation_error.rb +9 -0
  343. data/app/services/command_tower/messaging/planner/message_overrides.rb +33 -0
  344. data/app/services/command_tower/messaging/planner/operation_logger.rb +28 -0
  345. data/app/services/command_tower/messaging/planner/planner.rb +261 -0
  346. data/app/services/command_tower/messaging/planner/unknown_type_error.rb +9 -0
  347. data/app/services/command_tower/messaging/planner.rb +25 -0
  348. data/app/services/command_tower/messaging/preferences/catalog.rb +96 -0
  349. data/app/services/command_tower/messaging/preferences/catalog_category_result.rb +19 -0
  350. data/app/services/command_tower/messaging/preferences/catalog_notification_result.rb +55 -0
  351. data/app/services/command_tower/messaging/preferences/catalog_result.rb +13 -0
  352. data/app/services/command_tower/messaging/preferences/error.rb +9 -0
  353. data/app/services/command_tower/messaging/preferences/evaluation_result.rb +61 -0
  354. data/app/services/command_tower/messaging/preferences/evaluator.rb +194 -0
  355. data/app/services/command_tower/messaging/preferences/invalid_preference_state_error.rb +9 -0
  356. data/app/services/command_tower/messaging/preferences/invalid_preference_write_error.rb +10 -0
  357. data/app/services/command_tower/messaging/preferences/not_settings_visible_error.rb +10 -0
  358. data/app/services/command_tower/messaging/preferences/preference_state.rb +61 -0
  359. data/app/services/command_tower/messaging/preferences/reason_classes.rb +17 -0
  360. data/app/services/command_tower/messaging/preferences/resolve.rb +50 -0
  361. data/app/services/command_tower/messaging/preferences/store.rb +126 -0
  362. data/app/services/command_tower/messaging/preferences/store_error.rb +10 -0
  363. data/app/services/command_tower/messaging/preferences/suppressed_destination.rb +24 -0
  364. data/app/services/command_tower/messaging/preferences/unknown_type_error.rb +9 -0
  365. data/app/services/command_tower/messaging/preferences/update.rb +248 -0
  366. data/app/services/command_tower/messaging/preferences.rb +68 -0
  367. data/app/services/command_tower/messaging/pushover/adapters/disabled_adapter.rb +33 -0
  368. data/app/services/command_tower/messaging/pushover/adapters/fake_adapter.rb +90 -0
  369. data/app/services/command_tower/messaging/pushover/adapters/http_adapter.rb +145 -0
  370. data/app/services/command_tower/messaging/pushover/adapters/log_adapter.rb +52 -0
  371. data/app/services/command_tower/messaging/pushover/result.rb +34 -0
  372. data/app/services/command_tower/messaging/pushover/transport.rb +64 -0
  373. data/app/services/command_tower/messaging/recipient_readiness/channel_result.rb +55 -0
  374. data/app/services/command_tower/messaging/recipient_readiness/error.rb +9 -0
  375. data/app/services/command_tower/messaging/recipient_readiness/evaluate.rb +319 -0
  376. data/app/services/command_tower/messaging/recipient_readiness/identity_facts.rb +54 -0
  377. data/app/services/command_tower/messaging/recipient_readiness/reason_codes.rb +33 -0
  378. data/app/services/command_tower/messaging/recipient_readiness/recipient_not_found_error.rb +9 -0
  379. data/app/services/command_tower/messaging/recipient_readiness/recipient_result.rb +38 -0
  380. data/app/services/command_tower/messaging/recipient_readiness/unknown_channel_error.rb +9 -0
  381. data/app/services/command_tower/messaging/recipient_readiness.rb +26 -0
  382. data/app/services/command_tower/messaging/rendering/channel_renderer.rb +127 -0
  383. data/app/services/command_tower/messaging/rendering/render_error.rb +24 -0
  384. data/app/services/command_tower/messaging/rendering/rendered_payload.rb +44 -0
  385. data/app/services/command_tower/messaging/rendering/rendered_pushover_payload.rb +43 -0
  386. data/app/services/command_tower/messaging/rendering/rendered_sms_payload.rb +40 -0
  387. data/app/services/command_tower/messaging.rb +35 -0
  388. data/app/services/command_tower/secrets/cleanse.rb +19 -5
  389. data/app/services/command_tower/secrets/generate.rb +62 -27
  390. data/app/services/command_tower/secrets/verify.rb +46 -12
  391. data/app/services/command_tower/secrets.rb +2 -0
  392. data/app/services/command_tower/service_base.rb +30 -43
  393. data/app/services/command_tower/service_logging.rb +2 -36
  394. data/app/services/command_tower/services/account/clear_phone.rb +33 -0
  395. data/app/services/command_tower/services/account/phone_verification/send.rb +114 -0
  396. data/app/services/command_tower/services/account/phone_verification/verify.rb +89 -0
  397. data/app/services/command_tower/services/account/pushover/create.rb +28 -0
  398. data/app/services/command_tower/services/account/pushover/ct_support.rb +70 -0
  399. data/app/services/command_tower/services/account/pushover/destroy.rb +30 -0
  400. data/app/services/command_tower/services/account/pushover/replace.rb +28 -0
  401. data/app/services/command_tower/services/account/pushover/show.rb +19 -0
  402. data/app/services/command_tower/services/account/pushover/verify.rb +30 -0
  403. data/app/services/command_tower/services/account/update_phone.rb +58 -0
  404. data/app/services/command_tower/services/admin/users.rb +377 -0
  405. data/app/services/command_tower/services/admin/workspace/manifest.rb +49 -0
  406. data/app/services/command_tower/services/application_service.rb +58 -0
  407. data/app/services/command_tower/services/audit/events/filter_options.rb +75 -0
  408. data/app/services/command_tower/services/audit/events.rb +199 -0
  409. data/app/services/command_tower/services/auth/assign_default_membership_role.rb +44 -0
  410. data/app/services/command_tower/services/auth/authenticate_session.rb +132 -0
  411. data/app/services/command_tower/services/auth/authorize_request.rb +34 -0
  412. data/app/services/command_tower/services/auth/client_ip_resolver.rb +13 -0
  413. data/app/services/command_tower/services/auth/email_availability.rb +42 -0
  414. data/app/services/command_tower/services/auth/email_verification/send.rb +65 -0
  415. data/app/services/command_tower/services/auth/email_verification/verify.rb +53 -0
  416. data/app/services/command_tower/services/auth/identity_policy.rb +60 -0
  417. data/app/services/command_tower/services/auth/password_recovery/rate_limits/check_send.rb +48 -0
  418. data/app/services/command_tower/services/auth/password_recovery/rate_limits/check_token_issue.rb +35 -0
  419. data/app/services/command_tower/services/auth/password_recovery/rate_limits/enforcement.rb +53 -0
  420. data/app/services/command_tower/services/auth/password_recovery_session/create.rb +26 -0
  421. data/app/services/command_tower/services/auth/password_recovery_session/decode.rb +29 -0
  422. data/app/services/command_tower/services/auth/password_recovery_session/encode.rb +31 -0
  423. data/app/services/command_tower/services/auth/password_recovery_session/validate.rb +58 -0
  424. data/app/services/command_tower/services/auth/password_reset/reset.rb +75 -0
  425. data/app/services/command_tower/services/auth/password_reset/send.rb +77 -0
  426. data/app/services/command_tower/services/auth/password_reset/token_verification.rb +68 -0
  427. data/app/services/command_tower/services/auth/password_reset/validate.rb +29 -0
  428. data/app/services/command_tower/services/auth/plain_text/login.rb +52 -0
  429. data/app/services/command_tower/services/auth/principal_capabilities/project.rb +48 -0
  430. data/app/services/command_tower/services/auth/register.rb +77 -0
  431. data/app/services/command_tower/services/auth/signup_rate_limits/check_availability.rb +52 -0
  432. data/app/services/command_tower/services/auth/signup_rate_limits/check_register.rb +24 -0
  433. data/app/services/command_tower/services/auth/signup_rate_limits/check_token_issue.rb +33 -0
  434. data/app/services/command_tower/services/auth/signup_rate_limits/enforcement.rb +50 -0
  435. data/app/services/command_tower/services/auth/signup_session/create.rb +26 -0
  436. data/app/services/command_tower/services/auth/signup_session/decode.rb +29 -0
  437. data/app/services/command_tower/services/auth/signup_session/encode.rb +31 -0
  438. data/app/services/command_tower/services/auth/signup_session/validate.rb +58 -0
  439. data/app/services/command_tower/services/auth/username_availability.rb +28 -0
  440. data/app/services/command_tower/services/impersonation/create.rb +29 -0
  441. data/app/services/command_tower/services/impersonation/end.rb +28 -0
  442. data/app/services/command_tower/services/impersonation/record_activity.rb +30 -0
  443. data/app/services/command_tower/services/impersonation/terminate_open_sessions.rb +51 -0
  444. data/app/services/command_tower/services/me/capabilities.rb +43 -0
  445. data/app/services/command_tower/services/me/change_password.rb +96 -0
  446. data/app/services/command_tower/services/me/pushover_product_gate.rb +18 -0
  447. data/app/services/command_tower/services/me/sms_product_gate.rb +19 -0
  448. data/app/services/command_tower/services/me/update_name.rb +58 -0
  449. data/app/services/command_tower/services/messaging/communications/produce.rb +68 -0
  450. data/app/services/command_tower/services/messaging/communications/produce_many.rb +154 -0
  451. data/app/services/command_tower/services/messaging/inbox.rb +129 -0
  452. data/app/services/command_tower/services/messaging/preferences/platform_enabled_channels.rb +20 -0
  453. data/app/services/command_tower/services/messaging/preferences/show.rb +36 -0
  454. data/app/services/command_tower/services/messaging/preferences/update.rb +43 -0
  455. data/app/services/command_tower/services/messaging/recipients.rb +20 -0
  456. data/app/services/command_tower/services/rate_limits/check.rb +31 -0
  457. data/app/services/command_tower/services/service_result.rb +73 -0
  458. data/app/services/command_tower/user_attributes/mutate.rb +154 -0
  459. data/app/services/command_tower/username/available.rb +24 -11
  460. data/app/shared_sequences/command_tower/shared_sequences/admin/users/resolve_scoped_user.rb +42 -0
  461. data/app/views/command_tower/email_verification_mailer/verify_email.html.erb +70 -22
  462. data/app/views/command_tower/messaging/rendering/email.html.erb +28 -0
  463. data/app/views/command_tower/messaging/rendering/email.text.erb +7 -0
  464. data/app/views/command_tower/messaging/rendering/pushover.text.erb +1 -0
  465. data/app/views/command_tower/messaging/rendering/sms.text.erb +1 -0
  466. data/app/views/command_tower/password_reset_mailer/reset_password.html.erb +107 -0
  467. data/app/views/layouts/mailer.html.erb +13 -0
  468. data/app/views/layouts/mailer.text.erb +1 -0
  469. data/app/workflows/command_tower/transactional.rb +65 -0
  470. data/app/workflows/command_tower/workflows/admin/messaging/create_announcement_workflow.rb +73 -0
  471. data/app/workflows/command_tower/workflows/admin/scope_resolution.rb +17 -0
  472. data/app/workflows/command_tower/workflows/admin/users/error_mapping.rb +26 -0
  473. data/app/workflows/command_tower/workflows/admin/users/identity_mutation.rb +30 -0
  474. data/app/workflows/command_tower/workflows/admin/users/list_assignable_roles_workflow.rb +30 -0
  475. data/app/workflows/command_tower/workflows/admin/users/list_workflow.rb +54 -0
  476. data/app/workflows/command_tower/workflows/admin/users/set_email_validated_workflow.rb +45 -0
  477. data/app/workflows/command_tower/workflows/admin/users/show_workflow.rb +49 -0
  478. data/app/workflows/command_tower/workflows/admin/users/update_email_workflow.rb +45 -0
  479. data/app/workflows/command_tower/workflows/admin/users/update_name_workflow.rb +49 -0
  480. data/app/workflows/command_tower/workflows/admin/users/update_roles_workflow.rb +61 -0
  481. data/app/workflows/command_tower/workflows/admin/users/update_username_workflow.rb +45 -0
  482. data/app/workflows/command_tower/workflows/admin/workspace/manifest_workflow.rb +25 -0
  483. data/app/workflows/command_tower/workflows/application_workflow.rb +207 -0
  484. data/app/workflows/command_tower/workflows/audit/error_mapping.rb +24 -0
  485. data/app/workflows/command_tower/workflows/audit/events/filter_options_for_admin_workflow.rb +34 -0
  486. data/app/workflows/command_tower/workflows/audit/events/filter_options_for_user_workflow.rb +34 -0
  487. data/app/workflows/command_tower/workflows/audit/events/list_for_admin_workflow.rb +74 -0
  488. data/app/workflows/command_tower/workflows/audit/events/list_for_user_workflow.rb +45 -0
  489. data/app/workflows/command_tower/workflows/audit/events/show_for_admin_workflow.rb +54 -0
  490. data/app/workflows/command_tower/workflows/audit/events/show_for_user_workflow.rb +42 -0
  491. data/app/workflows/command_tower/workflows/auth/authenticate_request_workflow.rb +41 -0
  492. data/app/workflows/command_tower/workflows/auth/authentication_response_effects.rb +25 -0
  493. data/app/workflows/command_tower/workflows/auth/authorize_request_workflow.rb +28 -0
  494. data/app/workflows/command_tower/workflows/auth/email_availability_workflow.rb +39 -0
  495. data/app/workflows/command_tower/workflows/auth/email_verification/send_workflow.rb +32 -0
  496. data/app/workflows/command_tower/workflows/auth/email_verification/verify_workflow.rb +35 -0
  497. data/app/workflows/command_tower/workflows/auth/identity_error_status.rb +36 -0
  498. data/app/workflows/command_tower/workflows/auth/identity_policy_workflow.rb +26 -0
  499. data/app/workflows/command_tower/workflows/auth/logout_workflow.rb +59 -0
  500. data/app/workflows/command_tower/workflows/auth/password_recovery_session/authenticate_workflow.rb +49 -0
  501. data/app/workflows/command_tower/workflows/auth/password_recovery_session/create_workflow.rb +39 -0
  502. data/app/workflows/command_tower/workflows/auth/password_reset/reset_workflow.rb +40 -0
  503. data/app/workflows/command_tower/workflows/auth/password_reset/send_workflow.rb +45 -0
  504. data/app/workflows/command_tower/workflows/auth/password_reset/validate_workflow.rb +40 -0
  505. data/app/workflows/command_tower/workflows/auth/plain_text/login_workflow.rb +48 -0
  506. data/app/workflows/command_tower/workflows/auth/principal_capabilities/show_workflow.rb +27 -0
  507. data/app/workflows/command_tower/workflows/auth/register_workflow.rb +115 -0
  508. data/app/workflows/command_tower/workflows/auth/session/show_workflow.rb +58 -0
  509. data/app/workflows/command_tower/workflows/auth/session_error_status.rb +31 -0
  510. data/app/workflows/command_tower/workflows/auth/signup_error_status.rb +31 -0
  511. data/app/workflows/command_tower/workflows/auth/signup_session/authenticate_workflow.rb +49 -0
  512. data/app/workflows/command_tower/workflows/auth/signup_session/create_workflow.rb +37 -0
  513. data/app/workflows/command_tower/workflows/auth/username_availability_workflow.rb +39 -0
  514. data/app/workflows/command_tower/workflows/impersonation/error_mapping.rb +27 -0
  515. data/app/workflows/command_tower/workflows/impersonation/start_workflow.rb +97 -0
  516. data/app/workflows/command_tower/workflows/impersonation/stop_workflow.rb +66 -0
  517. data/app/workflows/command_tower/workflows/me/change_password_workflow.rb +34 -0
  518. data/app/workflows/command_tower/workflows/me/clear_phone_workflow.rb +52 -0
  519. data/app/workflows/command_tower/workflows/me/error_mapping.rb +46 -0
  520. data/app/workflows/command_tower/workflows/me/error_status.rb +28 -0
  521. data/app/workflows/command_tower/workflows/me/phone_verification/send_workflow.rb +65 -0
  522. data/app/workflows/command_tower/workflows/me/phone_verification/verify_workflow.rb +57 -0
  523. data/app/workflows/command_tower/workflows/me/pushover/create_workflow.rb +38 -0
  524. data/app/workflows/command_tower/workflows/me/pushover/destroy_workflow.rb +34 -0
  525. data/app/workflows/command_tower/workflows/me/pushover/replace_workflow.rb +38 -0
  526. data/app/workflows/command_tower/workflows/me/pushover/show_workflow.rb +34 -0
  527. data/app/workflows/command_tower/workflows/me/pushover/verify_workflow.rb +34 -0
  528. data/app/workflows/command_tower/workflows/me/pushover/workflow_support.rb +31 -0
  529. data/app/workflows/command_tower/workflows/me/show_workflow.rb +33 -0
  530. data/app/workflows/command_tower/workflows/me/update_name_workflow.rb +49 -0
  531. data/app/workflows/command_tower/workflows/me/update_phone_workflow.rb +55 -0
  532. data/app/workflows/command_tower/workflows/messaging/communications/produce_recipient_workflow.rb +60 -0
  533. data/app/workflows/command_tower/workflows/messaging/error_mapping.rb +26 -0
  534. data/app/workflows/command_tower/workflows/messaging/execution/deliver_workflow.rb +234 -0
  535. data/app/workflows/command_tower/workflows/messaging/handoff/process_workflow.rb +90 -0
  536. data/app/workflows/command_tower/workflows/messaging/inbox.rb +97 -0
  537. data/app/workflows/command_tower/workflows/messaging/preferences/show_workflow.rb +31 -0
  538. data/app/workflows/command_tower/workflows/messaging/preferences/update_workflow.rb +37 -0
  539. data/app/workflows/command_tower/workflows/profile/show_workflow.rb +28 -0
  540. data/app/workflows/command_tower/workflows/workflow_result.rb +58 -0
  541. data/config/routes.rb +105 -37
  542. data/db/migrate/{20241117043720_create_command_tower_users.rb → 20260805000001_create_command_tower_users.rb} +7 -9
  543. data/db/migrate/{20241204065708_create_command_tower_user_secrets.rb → 20260805000002_create_command_tower_user_secrets.rb} +3 -0
  544. data/db/migrate/20260805000003_create_command_tower_messaging_core.rb +90 -0
  545. data/db/migrate/20260805000004_create_messaging_notification_preferences.rb +17 -0
  546. data/db/migrate/20260805000005_create_messaging_endpoints_and_pushover_credentials.rb +72 -0
  547. data/db/migrate/20260816000001_create_command_tower_audit_events.rb +45 -0
  548. data/db/migrate/20260817000001_add_scope_columns_to_command_tower_audit_events.rb +34 -0
  549. data/db/migrate/20260817000003_create_command_tower_impersonation_sessions.rb +26 -0
  550. data/docs/admin_workspace.md +158 -0
  551. data/docs/api_reference.md +599 -0
  552. data/docs/architecture.md +35 -0
  553. data/docs/audit.md +195 -0
  554. data/docs/authentication.md +51 -0
  555. data/docs/authentication_authorization_guide.md +154 -0
  556. data/docs/authorization.md +55 -0
  557. data/docs/change_password_workflow.md +67 -0
  558. data/docs/controllers.md +41 -0
  559. data/docs/cookie_authentication_guide.md +167 -0
  560. data/docs/email_verification_workflow.md +58 -0
  561. data/docs/eventing.md +179 -0
  562. data/docs/extending.md +136 -0
  563. data/docs/host_integration_guide.md +249 -0
  564. data/docs/initializing.md +169 -0
  565. data/docs/messaging_integration_guide.md +87 -0
  566. data/docs/models.md +55 -0
  567. data/docs/pagination.md +47 -0
  568. data/docs/password_reset_workflow.md +82 -0
  569. data/docs/principal_capabilities.md +89 -0
  570. data/docs/sensitive_routes.md +47 -0
  571. data/docs/testing.md +74 -0
  572. data/docs/upgrades/0.10.0.md +58 -0
  573. data/docs/upgrades/0.11.0.md +92 -0
  574. data/docs/upgrades/README.md +10 -0
  575. data/lib/command_tower/admin_scope/apply_audit_scoping.rb +45 -0
  576. data/lib/command_tower/admin_scope/apply_users_narrowing.rb +21 -0
  577. data/lib/command_tower/admin_scope/manifest_projection.rb +102 -0
  578. data/lib/command_tower/admin_scope/resolve.rb +31 -0
  579. data/lib/command_tower/admin_scope/scope_context.rb +7 -0
  580. data/lib/command_tower/admin_scope/scope_option.rb +7 -0
  581. data/lib/command_tower/admin_scope.rb +20 -0
  582. data/lib/command_tower/admin_workspace.rb +16 -0
  583. data/lib/command_tower/audit/attribution.rb +90 -0
  584. data/lib/command_tower/audit/emit.rb +113 -0
  585. data/lib/command_tower/audit/masking.rb +41 -0
  586. data/lib/command_tower/audit/payload.rb +128 -0
  587. data/lib/command_tower/audit/persistence/subscriber.rb +85 -0
  588. data/lib/command_tower/audit.rb +27 -0
  589. data/lib/command_tower/authorization/assignable_roles.rb +36 -0
  590. data/lib/command_tower/authorization/default.yml +101 -35
  591. data/lib/command_tower/authorization/effective_entity_grants.rb +55 -0
  592. data/lib/command_tower/authorization/entity.rb +15 -5
  593. data/lib/command_tower/authorization/role.rb +5 -4
  594. data/lib/command_tower/authorization.rb +71 -10
  595. data/lib/command_tower/configuration/admin_scope/config.rb +104 -0
  596. data/lib/command_tower/configuration/admin_scope/tool_registration.rb +28 -0
  597. data/lib/command_tower/configuration/application/config.rb +2 -2
  598. data/lib/command_tower/configuration/authorization/config.rb +6 -0
  599. data/lib/command_tower/configuration/base.rb +0 -1
  600. data/lib/command_tower/configuration/config.rb +51 -1
  601. data/lib/command_tower/configuration/credentials/config.rb +33 -0
  602. data/lib/command_tower/configuration/credentials/smtp.rb +33 -0
  603. data/lib/command_tower/configuration/credentials/twilio.rb +33 -0
  604. data/lib/command_tower/configuration/email/config.rb +1 -18
  605. data/lib/command_tower/configuration/identity/config.rb +19 -0
  606. data/lib/command_tower/configuration/identity/phone_verification.rb +54 -0
  607. data/lib/command_tower/configuration/impersonation/config.rb +38 -0
  608. data/lib/command_tower/configuration/jwt/config.rb +7 -0
  609. data/lib/command_tower/configuration/jwt/cookie/config.rb +64 -0
  610. data/lib/command_tower/configuration/jwt/cookie/csrf/config.rb +72 -0
  611. data/lib/command_tower/configuration/login/strategy/plain_text/config.rb +6 -0
  612. data/lib/command_tower/configuration/login/strategy/plain_text/email_verify.rb +5 -0
  613. data/lib/command_tower/configuration/login/strategy/plain_text/password_reset.rb +49 -0
  614. data/lib/command_tower/configuration/messaging/config.rb +60 -0
  615. data/lib/command_tower/configuration/messaging/pushover.rb +42 -0
  616. data/lib/command_tower/configuration/messaging/sms.rb +32 -0
  617. data/lib/command_tower/configuration/password_recovery_session/config.rb +61 -0
  618. data/lib/command_tower/configuration/password_recovery_session/rate_limits.rb +33 -0
  619. data/lib/command_tower/configuration/registry/admin_workspace/config.rb +199 -0
  620. data/lib/command_tower/configuration/registry/admin_workspace/tool_definition.rb +150 -0
  621. data/lib/command_tower/configuration/registry/audit/config.rb +403 -0
  622. data/lib/command_tower/configuration/registry/audit/event_definition.rb +155 -0
  623. data/lib/command_tower/configuration/registry/config.rb +34 -0
  624. data/lib/command_tower/configuration/registry/principal_capabilities/capability_definition.rb +43 -0
  625. data/lib/command_tower/configuration/registry/principal_capabilities/config.rb +136 -0
  626. data/lib/command_tower/configuration/signup_session/config.rb +67 -0
  627. data/lib/command_tower/configuration/signup_session/email_availability.rb +18 -0
  628. data/lib/command_tower/configuration/signup_session/rate_limits.rb +48 -0
  629. data/lib/command_tower/configuration/user/config.rb +6 -5
  630. data/lib/command_tower/credential_resolution/env_backend.rb +25 -0
  631. data/lib/command_tower/credential_resolution/smtp_action_mailer_bridge.rb +24 -0
  632. data/lib/command_tower/credential_resolution/smtp_credentials.rb +26 -0
  633. data/lib/command_tower/credential_resolution/twilio_credentials.rb +26 -0
  634. data/lib/command_tower/credential_resolution.rb +78 -0
  635. data/lib/command_tower/current.rb +19 -0
  636. data/lib/command_tower/engine.rb +23 -5
  637. data/lib/command_tower/events.rb +184 -0
  638. data/lib/command_tower/execution.rb +111 -0
  639. data/lib/command_tower/impersonation/activity_declaration.rb +23 -0
  640. data/lib/command_tower/impersonation/apply_overlay.rb +88 -0
  641. data/lib/command_tower/impersonation/clear_overlay_for_audit.rb +23 -0
  642. data/lib/command_tower/impersonation/establish_identity.rb +44 -0
  643. data/lib/command_tower/install/baseline.rb +34 -0
  644. data/lib/command_tower/install/doctor.rb +227 -0
  645. data/lib/command_tower/jwt/authorization_helper.rb +136 -0
  646. data/lib/command_tower/jwt/csrf_helper.rb +138 -0
  647. data/lib/command_tower/logging/lifecycle_declaration.rb +27 -0
  648. data/lib/command_tower/logging/projection.rb +67 -0
  649. data/lib/command_tower/logging/subscriber.rb +103 -0
  650. data/lib/command_tower/password_recovery/authorization_helper.rb +25 -0
  651. data/lib/command_tower/principal_capabilities.rb +15 -0
  652. data/lib/command_tower/redis_connection.rb +21 -0
  653. data/lib/command_tower/schema/error/email_validation_required.rb +15 -0
  654. data/lib/command_tower/schema/shared/user.rb +32 -0
  655. data/lib/command_tower/schema.rb +2 -25
  656. data/lib/command_tower/signup/authorization_helper.rb +25 -0
  657. data/lib/command_tower/spec_helper.rb +58 -1
  658. data/lib/command_tower/testing.rb +62 -0
  659. data/lib/command_tower/version.rb +1 -1
  660. data/lib/command_tower.rb +32 -0
  661. data/lib/generators/command_tower/configure/USAGE +14 -2
  662. data/lib/generators/command_tower/configure/configure_generator.rb +29 -2
  663. data/lib/tasks/auto_annotate_models.rake +23 -55
  664. data/lib/tasks/install.rake +81 -0
  665. data/lib/tasks/users.rake +119 -0
  666. data/spec/factories/entity.rb +37 -0
  667. data/spec/factories/impersonation_session.rb +17 -0
  668. data/spec/factories/messaging.rb +156 -0
  669. data/spec/factories/role.rb +29 -0
  670. data/spec/factories/user.rb +69 -0
  671. data/spec/factories/user_secret.rb +12 -0
  672. metadata +686 -55
  673. data/app/controllers/command_tower/admin_controller.rb +0 -110
  674. data/app/controllers/command_tower/auth/plain_text_controller.rb +0 -133
  675. data/app/controllers/command_tower/inbox/message_blast_controller.rb +0 -89
  676. data/app/controllers/command_tower/inbox/message_controller.rb +0 -81
  677. data/app/controllers/command_tower/user_controller.rb +0 -49
  678. data/app/controllers/command_tower/username_controller.rb +0 -26
  679. data/app/helpers/command_tower/pagination_helper.rb +0 -40
  680. data/app/helpers/command_tower/schema_helper.rb +0 -29
  681. data/app/models/message.rb +0 -30
  682. data/app/models/message_blast.rb +0 -27
  683. data/app/services/command_tower/admin_service/users.rb +0 -27
  684. data/app/services/command_tower/inbox_service/blast/delete.rb +0 -23
  685. data/app/services/command_tower/inbox_service/blast/metadata.rb +0 -26
  686. data/app/services/command_tower/inbox_service/blast/new_user_blaster.rb +0 -24
  687. data/app/services/command_tower/inbox_service/blast/retrieve.rb +0 -30
  688. data/app/services/command_tower/inbox_service/blast/upsert.rb +0 -67
  689. data/app/services/command_tower/inbox_service/message/metadata.rb +0 -41
  690. data/app/services/command_tower/inbox_service/message/modify.rb +0 -44
  691. data/app/services/command_tower/inbox_service/message/retrieve.rb +0 -36
  692. data/app/services/command_tower/inbox_service/message/send.rb +0 -33
  693. data/app/services/command_tower/jwt/time_delay_token.rb +0 -17
  694. data/app/services/command_tower/login_strategy/plain_text/create.rb +0 -43
  695. data/app/services/command_tower/login_strategy/plain_text/email_verification/generate.rb +0 -29
  696. data/app/services/command_tower/login_strategy/plain_text/email_verification/send.rb +0 -23
  697. data/app/services/command_tower/login_strategy/plain_text/email_verification/verify.rb +0 -24
  698. data/app/services/command_tower/login_strategy/plain_text/login.rb +0 -50
  699. data/app/services/command_tower/pagination_service_helper.rb +0 -88
  700. data/app/services/command_tower/user_attributes/modify.rb +0 -68
  701. data/app/services/command_tower/user_attributes/roles.rb +0 -27
  702. data/db/migrate/20250223023306_create_command_tower_messages.rb +0 -12
  703. data/db/migrate/20250223023313_create_command_tower_message_blasts.rb +0 -14
  704. data/lib/command_tower/schema/admin/users.rb +0 -16
  705. data/lib/command_tower/schema/inbox/blast_request.rb +0 -15
  706. data/lib/command_tower/schema/inbox/blast_response.rb +0 -16
  707. data/lib/command_tower/schema/inbox/message_blast_entity.rb +0 -16
  708. data/lib/command_tower/schema/inbox/message_blast_metadata.rb +0 -16
  709. data/lib/command_tower/schema/inbox/message_entity.rb +0 -14
  710. data/lib/command_tower/schema/inbox/metadata.rb +0 -18
  711. data/lib/command_tower/schema/inbox/modified.rb +0 -13
  712. data/lib/command_tower/schema/page.rb +0 -11
  713. data/lib/command_tower/schema/pagination.rb +0 -16
  714. data/lib/command_tower/schema/plain_text/create_user_request.rb +0 -18
  715. data/lib/command_tower/schema/plain_text/create_user_response.rb +0 -17
  716. data/lib/command_tower/schema/plain_text/email_verify_request.rb +0 -11
  717. data/lib/command_tower/schema/plain_text/email_verify_response.rb +0 -11
  718. data/lib/command_tower/schema/plain_text/email_verify_send_request.rb +0 -9
  719. data/lib/command_tower/schema/plain_text/email_verify_send_response.rb +0 -11
  720. data/lib/command_tower/schema/plain_text/login_request.rb +0 -15
  721. data/lib/command_tower/schema/plain_text/login_response.rb +0 -16
  722. data/lib/command_tower/schema/user.rb +0 -28
@@ -0,0 +1,249 @@
1
+ # Host Integration Guide
2
+
3
+ **Start here** for integrating CommandTower into a new Rails host.
4
+
5
+ This page owns the **order of operations**. It does not replace specialty docs: install details stay in [Initializing](initializing.md), HTTP contracts in [API reference](api_reference.md), boundaries in [Extending](extending.md).
6
+
7
+ `command_tower:doctor` green means secrets/migrations look sane. It does **not** prove Me/Auth authorization works.
8
+
9
+ ## Prerequisites
10
+
11
+ - A Rails host application (engine is mounted into the host)
12
+ - `gem "command_tower"` in the host Gemfile (path, git, or released gem)
13
+ - Host-owned database (and any host Redis/job stack your app already uses)
14
+
15
+ ## Step 1 — Install
16
+
17
+ Follow [Initializing](initializing.md):
18
+
19
+ ```bash
20
+ bundle install
21
+ bin/rails command_tower:install
22
+ bin/rails db:migrate
23
+ bin/rails command_tower:doctor
24
+ ```
25
+
26
+ That copies CT migrations, generates `config/initializers/command_tower.rb` (unless skipped), and mounts `CommandTower::Engine` (unless skipped).
27
+
28
+ ## Step 2 — Secrets and initializer
29
+
30
+ In the host initializer, set at least:
31
+
32
+ - `config.jwt.hmac_secret`
33
+ - `config.signup_session.jwt_secret` (or `SIGNUP_SESSION_JWT_SECRET`)
34
+ - `config.password_recovery_session.jwt_secret` (or `PASSWORD_RECOVERY_SESSION_JWT_SECRET`)
35
+
36
+ Re-run `bin/rails command_tower:doctor`. Details: [Initializing — Configuration](initializing.md#configuration).
37
+
38
+ Dummy-host reference: [`rails_app/config/initializers/command_tower.rb`](../rails_app/config/initializers/command_tower.rb).
39
+
40
+ ### Email / SMTP
41
+
42
+ CommandTower owns ActionMailer delivery for engine mailers (email verification, password reset, messaging channel mail).
43
+
44
+ | Environment | Delivery |
45
+ |-------------|----------|
46
+ | `test` | `:test` (in-memory `ActionMailer::Base.deliveries`; no external SMTP) |
47
+ | development / production | `:smtp` unless the host explicitly sets `config.email.delivery_method` |
48
+
49
+ Non-secret knobs live on `config.email.*` (defaults: `smtp.gmail.com`, port `587`, `plain`, STARTTLS auto). Secrets come from Credential Resolution:
50
+
51
+ - `config.credentials.smtp.user_name` / `password`, or
52
+ - ENV `GMAIL_USER_NAME` / `GMAIL_PASSWORD`
53
+
54
+ `SmtpActionMailerBridge` merges resolved credentials into `action_mailer.smtp_settings` at the end of `CommandTower.configure`. Missing credentials fail at send when `raise_delivery_errors` is true. `From` uses the resolved SMTP username when present.
55
+
56
+ Doctor does **not** probe SMTP connectivity.
57
+
58
+ ## Step 3 — Confirm mount path
59
+
60
+ Ensure routes include something like:
61
+
62
+ ```ruby
63
+ mount CommandTower::Engine => "/" # or "/api"
64
+ ```
65
+
66
+ Engine paths below are **relative to that mount**. Route area index: [Controllers](controllers.md).
67
+
68
+ ## Step 3b — Inherit execution-boundary bases
69
+
70
+ Greenfield hosts should inherit CommandTower bases so Execution Context is established automatically:
71
+
72
+ ```ruby
73
+ class ApplicationController < CommandTower::ApplicationController
74
+ end
75
+
76
+ class ApplicationJob < CommandTower::ApplicationJob
77
+ end
78
+ ```
79
+
80
+ Unauthenticated host endpoints (for example health checks) still receive HTTP `execution_uuid` / `correlation_id`. Successful authentication enriches the **same** context with `user_id` / `effective_user_id`.
81
+
82
+ Workflows and services consume `CommandTower::Current` (or `execution_context`); they do not establish a new execution. For Rake/console, use `CommandTower.with_execution(source: :rake) { ... }`.
83
+
84
+ `Auth::RequestContext` is JWT request/response transport, not Execution Context. Details: [Extending — Execution Context](extending.md#execution-context).
85
+
86
+ Lifecycle and semantic events: [Eventing](eventing.md).
87
+
88
+ If superclass inheritance is technically blocked, include `CommandTower::Execution::HttpBoundary` / `JobBoundary` on the host bases. That is an escape hatch, not the preferred contract.
89
+
90
+ ## Step 4 — Host RBAC (required)
91
+
92
+ AuthorizeRequest **fails closed**. CommandTower ships **CT-owned** entity definitions (Me, session, inbox, Admin Workspace capabilities, …) and the platform full-access role (`owner`) in `lib/command_tower/authorization/default.yml`. CommandTower does **not** ship an operational `admin` role.
93
+
94
+ The host YAML (default `config/rbac_groups.yml`) is a **second source**. Composition is additive. Hosts:
95
+
96
+ 1. Define product roles (typically `member`).
97
+ 2. **Grant names** of already-defined CT entities to those roles.
98
+ 3. Optionally define **host-owned** entities for **host** controllers.
99
+ 4. Deliberately compose operational Admin roles (least privilege or a broad host-owned `admin`).
100
+
101
+ Do **not** copy CommandTower controller/entity blocks into the host file. Do **not** redefine `owner` or CT entity names. A host **may** define an `admin` group as host policy. Conflicts fail at boot (no last-write-wins).
102
+
103
+ Dummy host grants-only example: [`rails_app/config/rbac_groups.yml`](../rails_app/config/rbac_groups.yml).
104
+
105
+ ```ruby
106
+ CommandTower.configure do |c|
107
+ c.authorization.rbac_group_path = Rails.root.join("config/rbac_groups.yml")
108
+ c.authorization.default_membership_role = "member" # optional; nil disables
109
+ end
110
+ ```
111
+
112
+ `default_membership_role` is validated against the **composed** graph at boot. Unknown names fail configuration finalization.
113
+
114
+ More: [Authorization](authorization.md), [Authentication & authorization guide](authentication_authorization_guide.md).
115
+
116
+ Product audit names (later) register additively:
117
+
118
+ ```ruby
119
+ CommandTower.configure do |c|
120
+ c.registry.audit.event :wager_placed do |event|
121
+ event.allowed_changes = %i[status]
122
+ event.user_history = true
123
+ end
124
+ end
125
+ ```
126
+
127
+ Do **not** redefine CommandTower-owned audit names. Audit rows persist in CommandTower after `command_tower:install:migrations` and `db:migrate`. See [Audit](audit.md).
128
+
129
+ Admin Workspace tools register additively (navigation metadata, not a dispatcher):
130
+
131
+ ```ruby
132
+ CommandTower.configure do |c|
133
+ c.registry.admin_workspace.tool :host_example do |tool|
134
+ tool.label = "Example"
135
+ tool.description = "Short launcher explanation of what this tool does."
136
+ tool.route = "/admin/example"
137
+ tool.group = :product
138
+ tool.sort_order = 300
139
+ tool.required_entity = :host_example_entity
140
+ end
141
+ end
142
+ ```
143
+
144
+ Do **not** redefine CommandTower-owned tool ids (`users`, `audit`, `messaging`). Hosts own copy for host tools (`description` soft ≤100 / hard ≤160). Manifest: [Admin Workspace](admin_workspace.md).
145
+
146
+ Principal capabilities register additively (frontend-projectable ids, not a dump of all entities):
147
+
148
+ ```ruby
149
+ CommandTower.configure do |c|
150
+ c.registry.principal_capabilities.capability :host_example do |capability|
151
+ capability.required_entity = :host_example_entity
152
+ end
153
+ end
154
+ ```
155
+
156
+ Do **not** redefine CommandTower-owned capability ids (`admin_workspace`, `admin_users`, `admin_impersonation`, `admin_audit_events`, `admin_messaging_announcements`). Projection: [Principal capabilities](principal_capabilities.md). Grant `admin_impersonation` only to roles that should start impersonation of visible users. Dummy `admin` does not include it.
157
+
158
+ ## Step 5 — Roles on users
159
+
160
+ RBAC YAML defines what a role **may** do. Users still need that role assigned.
161
+
162
+ - Specs and the dummy pattern use role name **`member`** for Me/Auth surfaces (including entity `principal_capabilities`).
163
+ - When `authorization.default_membership_role` is set (for example `"member"`), register assigns that role **in the same transaction** as user create. Failure rolls back the user.
164
+ - When it is `nil`, register does not attach roles. Hosts may assign via product logic, ops (`command_tower:users:create`), or other host workflows.
165
+ - Installing CommandTower does **not** grant operational Admin access. Hosts must deliberately grant Admin entities.
166
+ - Admin announcements need a host role that includes `admin_messaging_announcements`.
167
+ - Admin Workspace manifest needs a host role that includes `admin_workspace`. Tool visibility still depends on each tool's `required_entity`.
168
+ - `GET /auth/principal-capabilities` needs entity `principal_capabilities` on the caller’s roles (grant on `member` like session/me). Possessed Admin projectables still depend on the Admin entity grants above.
169
+ - A host may define a broad `admin` role that grants many Admin entities — that is host policy, not a CommandTower default.
170
+ ## Step 6 — Enable feature gates you need
171
+
172
+ When a gate is off, the route is **not drawn** → **404**.
173
+
174
+ | Capability | Config |
175
+ |------------|--------|
176
+ | Plain-text login | `config.login.plain_text.enable = true` |
177
+ | Email verification routes | `config.login.plain_text.email_verify = true` |
178
+ | Password reset routes | `config.login.plain_text.password_reset = true` |
179
+ | Email availability | `config.signup_session.email_availability = true` |
180
+ | Username availability | `config.username.realtime_username_check = true` |
181
+
182
+ Full gate list: [API reference — Feature gates](api_reference.md#feature-gates).
183
+
184
+ ## Step 7 — Choose auth client path
185
+
186
+ - **API / mobile:** `Authorization: Bearer <jwt>` (default)
187
+ - **Browser / SPA cookies:** enable `config.jwt.cookie` (+ CSRF as needed) — [Cookie authentication](cookie_authentication_guide.md)
188
+
189
+ Engine HTTP success/error bodies use the application envelope `{ data, meta, errors }`. Host provisional helpers (`authenticate_user!`) can differ — [Authentication](authentication.md).
190
+
191
+ ## Step 8 — Smoke check
192
+
193
+ With gates and RBAC in place (paths relative to your mount):
194
+
195
+ 1. `POST /auth/register` (always drawn) — with `default_membership_role` configured, the user is created **and** assigned that role in one transaction.
196
+ 2. `POST /auth/plain-text/login` (if enabled) — receive `data.token`.
197
+ 3. `GET /me` with Bearer token — expect **200** and envelope `data` (account payload).
198
+
199
+ If you get **401**, authn failed. If you get **403**, fix Steps 4–5 before debugging clients.
200
+
201
+ Contracts: [API reference](api_reference.md).
202
+
203
+ ## Step 9 — Messaging (when needed)
204
+
205
+ Host owns:
206
+
207
+ - Notification catalog / types
208
+ - `platform_enabled_channels` / channel policy
209
+ - Adapter credentials (email / SMS / Pushover)
210
+
211
+ Emit from a **host product workflow** via `Communications::Produce` / `ProduceMany` — not by bypassing workflows. See [Messaging](messaging_integration_guide.md) and [Extending](extending.md).
212
+
213
+ Phone/Pushover routes are always drawn; missing product readiness returns **503** capability errors.
214
+
215
+ ## Step 10 — Host tests
216
+
217
+ ```ruby
218
+ require "command_tower/testing"
219
+ CommandTower::Testing.install!
220
+ ```
221
+
222
+ Details: [Testing](testing.md). Prefer `spec/requests/` patterns in the gem as HTTP contract proof.
223
+
224
+ ## Done when
225
+
226
+ - Doctor passes for secrets/migrations
227
+ - Host `rbac_groups.yml` maps Me/Auth entities
228
+ - Users who should use Me surfaces have the host `member` (or equivalent) role
229
+ - Needed feature gates are enabled
230
+ - `GET /me` returns **200** with a Bearer token for a member user
231
+
232
+ ## Common failures
233
+
234
+ | Symptom | Likely cause |
235
+ |---------|----------------|
236
+ | Doctor green, `GET /me` is **403** | Missing host RBAC YAML or user lacks `member` (Steps 4–5) |
237
+ | `POST /auth/plain-text/login` is **404** | `login.plain_text.enable?` off (Step 6) |
238
+ | Password-reset / availability **404** | Matching feature gate off |
239
+ | Phone / Pushover **503** | Capability / adapters not ready (Step 9) |
240
+ | Confused error JSON on host controllers | Provisional `authenticate_user!` vs engine envelope (Step 7) |
241
+
242
+ ## Related
243
+
244
+ - [Initializing](initializing.md)
245
+ - [Extending](extending.md)
246
+ - [API reference](api_reference.md)
247
+ - [Authentication & authorization guide](authentication_authorization_guide.md)
248
+ - [Messaging](messaging_integration_guide.md)
249
+ - [README](../README.md)
@@ -0,0 +1,169 @@
1
+ # Initializing CommandTower
2
+
3
+ CommandTower is a Rails engine. The install flow below gets the engine **mounted, migrated, and doctor-checked**. That alone is not a fully usable Me/Auth host — complete RBAC, feature gates, and a smoke check via the [Host integration guide](host_integration_guide.md).
4
+
5
+ Back to [README](../README.md).
6
+
7
+ ## Quick start
8
+
9
+ ```bash
10
+ # Gemfile: gem "command_tower" (or path/git source)
11
+ bundle install
12
+
13
+ bin/rails command_tower:install
14
+ bin/rails db:migrate
15
+ bin/rails command_tower:doctor
16
+ ```
17
+
18
+ `command_tower:install` does **not** run `db:migrate`. Installing and migrating stay separate on purpose.
19
+
20
+ ### After install
21
+
22
+ Continue with [Host integration](host_integration_guide.md):
23
+
24
+ 1. Host `rbac_groups.yml` product role that **grants** CT-owned Me/Auth entity names (required — otherwise authenticated Me/Auth calls **403**)
25
+ 2. Set `authorization.default_membership_role` (for example `"member"`) or assign roles some other supported way
26
+ 3. Enable feature gates you need (login, reset, availability, …)
27
+ 4. Smoke-check `GET /me` with a Bearer token
28
+ 5. Wire messaging catalog/adapters when you emit or use phone/Pushover
29
+
30
+ ### What `command_tower:install` does
31
+
32
+ 1. Runs Rails-native `command_tower:install:migrations` (copies engine migrations into the host `db/migrate/` with `*.command_tower.rb` scope).
33
+ 2. Runs `rails g command_tower:configure` unless skipped (creates initializer; mounts the engine).
34
+ 3. Prints next steps.
35
+
36
+ ### Flags / environment
37
+
38
+ | Variable | Effect |
39
+ |----------|--------|
40
+ | `SKIP_CONFIGURE=1` | Migrations only (existing custom initializer / mount) |
41
+ | `SKIP_MOUNT=1` | Generate initializer but do not mount routes |
42
+ | `FORCE=1` | Overwrite an existing `config/initializers/command_tower.rb` |
43
+
44
+ Examples:
45
+
46
+ ```bash
47
+ SKIP_CONFIGURE=1 bin/rails command_tower:install
48
+ SKIP_MOUNT=1 bin/rails command_tower:install
49
+ FORCE=1 bin/rails command_tower:install
50
+ ```
51
+
52
+ ## Configure generator (optional)
53
+
54
+ Prefer `command_tower:install` for greenfield hosts. The generator remains available:
55
+
56
+ ```bash
57
+ bin/rails generate command_tower:configure
58
+ bin/rails generate command_tower:configure --skip-routes
59
+ bin/rails generate command_tower:configure --force
60
+ ```
61
+
62
+ The generator:
63
+
64
+ 1. Adds `config/initializers/command_tower.rb` when missing (or overwrites with `--force`).
65
+ 2. Mounts `CommandTower::Engine` unless `--skip-routes` or already mounted.
66
+
67
+ Dummy-host example initializer (engine development): [`rails_app/config/initializers/command_tower.rb`](../rails_app/config/initializers/command_tower.rb).
68
+
69
+ ## Database migrations
70
+
71
+ CommandTower is the **sole authoring authority** for CommandTower-owned schema (`db/migrate` inside the gem). Hosts must **not** manually write, edit, or copy-paste CommandTower schema migrations (**AD-SCH-01**).
72
+
73
+ ### Fresh host install
74
+
75
+ Handled by `command_tower:install` (step 1). Equivalent migration-only command:
76
+
77
+ ```bash
78
+ bin/rails command_tower:install:migrations
79
+ bin/rails db:migrate
80
+ ```
81
+
82
+ `command_tower:install:migrations` is the standard Rails engine task (wrapper around `railties:install:migrations`). Re-running installation is **idempotent**: already-installed CommandTower migrations are skipped.
83
+
84
+ Rails may **retimestamp** newly copied host files. That is normal. Do not hand-edit installed `*.command_tower.rb` files.
85
+
86
+ ### Upgrade workflow
87
+
88
+ 1. Bump/release the CommandTower gem dependency in the host.
89
+ 2. Run `bin/rails command_tower:install:migrations` (or `SKIP_CONFIGURE=1 bin/rails command_tower:install`).
90
+ 3. Run `bin/rails db:migrate`.
91
+ 4. Optionally run `bin/rails command_tower:doctor`.
92
+
93
+ Do not re-run configure on hosts that already customize the initializer unless you intend to regenerate it (`FORCE=1`).
94
+
95
+ ### Adding future migrations
96
+
97
+ 1. Author the migration **only** in CommandTower `db/migrate/`.
98
+ 2. Release / bump the gem in the host.
99
+ 3. Install + migrate as above.
100
+
101
+ Installed host copies are an **execution context**, not a second authoring home.
102
+
103
+ ## Configuration
104
+
105
+ Required for production-ready hosts:
106
+
107
+ - `config.jwt.hmac_secret` — typically `SECRET_KEY_BASE` / `Rails.application.secret_key_base`
108
+ - `config.signup_session.jwt_secret` — or `SIGNUP_SESSION_JWT_SECRET`
109
+ - `config.password_recovery_session.jwt_secret` — or `PASSWORD_RECOVERY_SESSION_JWT_SECRET`
110
+
111
+ Optional / feature-gated:
112
+
113
+ - Messaging SMS / Pushover adapters and credential resolution (`config.credentials.*` or ENV)
114
+ - Cookie + CSRF JWT modes
115
+ - Admin enablement, application URL, welcome content hooks
116
+
117
+ The generated initializer documents available options via class_composer. Defaults live in CommandTower; do not duplicate them unnecessarily in the host.
118
+
119
+ ## Doctor
120
+
121
+ ```bash
122
+ bin/rails command_tower:doctor
123
+ ```
124
+
125
+ Checks Rails version compatibility, engine baseline migrations, host-installed migration copies, JWT / session secrets, and messaging adapter names. Failures abort with remediation text; warnings print but allow success.
126
+
127
+ Doctor does **not** probe Redis/SMTP connectivity.
128
+
129
+ ## Host vs CommandTower responsibilities
130
+
131
+ | Concern | Owner |
132
+ |---------|--------|
133
+ | Author CT schema migrations | CommandTower |
134
+ | Install / run migrations | Host (via engine tasks + `db:migrate`) |
135
+ | Product configuration / secrets | Host initializer + ENV |
136
+ | Dual-author CT schema in the host | **Forbidden** |
137
+
138
+ ## Troubleshooting
139
+
140
+ | Symptom | Fix |
141
+ |---------|-----|
142
+ | `users already exists` on migrate | Database not empty / stale `schema.rb` load — migrate an empty DB, or dump schema after a clean migrate |
143
+ | Install copies nothing new | Already installed — expected idempotency |
144
+ | Missing tables after install | You installed but did not `db:migrate` |
145
+ | Doctor fails on JWT default | Set `config.jwt.hmac_secret` from a real secret |
146
+ | Accidental public engine mount | Use `SKIP_MOUNT=1` / `--skip-routes`, or mount at the path your product needs |
147
+
148
+ ## Existing customized hosts
149
+
150
+ If the host already has a bespoke initializer and mount:
151
+
152
+ ```bash
153
+ SKIP_CONFIGURE=1 bin/rails command_tower:install
154
+ # same as: bin/rails command_tower:install:migrations
155
+ bin/rails db:migrate
156
+ ```
157
+
158
+ Do not run `rails g command_tower:configure` unless you intentionally want stock scaffolding.
159
+
160
+ ## Test suite factories
161
+
162
+ Shared FactoryBot definitions ship with the gem. In the host test boot path:
163
+
164
+ ```ruby
165
+ require "command_tower/testing"
166
+ CommandTower::Testing.install!
167
+ ```
168
+
169
+ Then extend with `FactoryBot.modify` as needed. See [Testing with CommandTower](testing.md).
@@ -0,0 +1,87 @@
1
+ # Messaging with CommandTower
2
+
3
+ CommandTower owns modern messaging **platform** surfaces. Hosts supply product content, channel policy, and adapter credentials.
4
+
5
+ Complete install and host RBAC first: [Host integration](host_integration_guide.md) (Steps 1–8 before emitting or wiring phone/Pushover).
6
+
7
+ ## Current surfaces
8
+
9
+ | Concern | Path / entry |
10
+ |---------|----------------|
11
+ | User inbox (consume) | Engine `/me/inbox*` — see [API reference](api_reference.md#me-inbox) |
12
+ | Preferences | Engine `/me/preferences*` — see [API reference](api_reference.md#preferences) |
13
+ | Phone / Pushover endpoints | Engine `/me/phone*`, `/me/pushover*` (503 when capability unavailable) |
14
+ | Single-recipient emit | `CommandTower::Services::Messaging::Communications::Produce` |
15
+ | Multi-recipient emit | `CommandTower::Services::Messaging::Communications::ProduceMany` |
16
+ | Admin cohort announce | Engine `POST /admin/messaging/announcements` |
17
+ | Host ops announce | Host-owned rake/job (product-specific; not part of the gem) |
18
+
19
+ Authentication uses JWT bearer or cookie session as documented in [Authentication](authentication.md). Me Inbox authorization requires host RBAC entities (dummy host uses a `member` role mapping). Admin announcements use entity `admin_messaging_announcements` (engine `default.yml` admin group).
20
+
21
+ ## Produce (single recipient)
22
+
23
+ Call from a **product workflow**, not from a controller service bypass:
24
+
25
+ ```ruby
26
+ CommandTower::Services::Messaging::Communications::Produce.call(
27
+ user: user,
28
+ notification_type_key: "welcome",
29
+ host_event_identity: "welcome/#{user.id}/#{SecureRandom.uuid}",
30
+ title: "Welcome",
31
+ body: "Thanks for joining.",
32
+ platform_enabled_channels: [:inbox, :email],
33
+ metadata: { source: "onboarding" } # optional
34
+ )
35
+ ```
36
+
37
+ | Kwarg | Required |
38
+ |-------|----------|
39
+ | `user` | yes (`User`) |
40
+ | `notification_type_key` | yes (`String`) |
41
+ | `host_event_identity` | yes (`String`) |
42
+ | `title` | yes |
43
+ | `body` | yes |
44
+ | `platform_enabled_channels` | yes (`Array`) |
45
+ | `metadata` | no (`Hash`) |
46
+
47
+ ## ProduceMany (multi recipient)
48
+
49
+ | Kwarg | Required / notes |
50
+ |-------|------------------|
51
+ | `user_ids` | yes (`Array` of integer ids) |
52
+ | `notification_type_key` | yes |
53
+ | `campaign_identity` | yes — fan-out builds `host_event_identity` as `"#{campaign_identity}/#{user.id}"` |
54
+ | `title`, `body` | yes |
55
+ | `platform_enabled_channels` | yes |
56
+ | `metadata` | optional |
57
+ | `execution_mode` | optional, default `:async`; `:sync` capped at **25** recipients |
58
+
59
+ Admin announcements HTTP is a product path over ProduceMany (async/sync, audience selection). Contract: [API reference — Admin messaging](api_reference.md#admin-messaging).
60
+
61
+ ## Me Inbox HTTP (summary)
62
+
63
+ | Concern | Contract |
64
+ |---------|----------|
65
+ | List | `GET /me/inbox?limit=&offset=&scope=` — meta `{ limit, offset, totalCount }` |
66
+ | Detail / open / archive / delete | `/me/inbox/:id` (+ `open`, `archive`) |
67
+ | Bulk | `POST /me/inbox/bulk/{read,unread,archive,restore,delete}` with body `ids` |
68
+ | Unread | `GET /me/inbox/unread-count` |
69
+
70
+ Pagination detail: [pagination.md](pagination.md). Full catalog: [api_reference.md](api_reference.md#me-inbox).
71
+
72
+ ## Host responsibilities
73
+
74
+ - Notification catalog content (registered into CommandTower notification types)
75
+ - `platform_enabled_channels` / channel policy injection
76
+ - Messaging adapter credentials (email / SMS / Pushover) via initializer or ENV
77
+ - Host product roles that grant CT-owned Me inbox/preferences/phone/pushover entities (and `admin` if used)
78
+ - Product-specific operational tooling (announce rake tasks, welcome copy)
79
+
80
+ ## Related
81
+
82
+ - [Controllers / routes](controllers.md)
83
+ - [API reference](api_reference.md)
84
+ - [Extending](extending.md) — Produce from host workflows; Do-Not-Extend
85
+ - [Initializing](initializing.md) — configuration and doctor
86
+ - [Pagination](pagination.md)
87
+ - [README](../README.md)
data/docs/models.md ADDED
@@ -0,0 +1,55 @@
1
+ # CommandTower Models
2
+
3
+ Core models live in the root / CommandTower namespaces and support authentication, authorization, and messaging ledger associations.
4
+
5
+ Back to [README](../README.md).
6
+
7
+ ## User
8
+
9
+ `User` is the primary identity model for host applications.
10
+
11
+ It underpins [Authentication](authentication.md) and [Authorization](authorization.md), and participates in messaging via associations such as `messaging_communications`.
12
+
13
+ Sensitive session invalidation uses the user’s verifier token — see [Sensitive changes](sensitive_routes.md).
14
+
15
+ ### Reopening `User` in the host
16
+
17
+ Prefer services/workflows for new behavior. When you must reopen the class:
18
+
19
+ ```ruby
20
+ require CommandTower::Engine.root.join("app", "models", "user.rb")
21
+
22
+ class User
23
+ def self.my_class_method; end
24
+ def my_instance_method; end
25
+ end
26
+ ```
27
+
28
+ ## UserSecret
29
+
30
+ `UserSecret` backs validation and recovery-related secrets (for example plain-text email validation flows). It complements [Sensitive changes](sensitive_routes.md).
31
+
32
+ ### Reopening `UserSecret` in the host
33
+
34
+ ```ruby
35
+ require CommandTower::Engine.root.join("app", "models", "user_secret.rb")
36
+
37
+ class UserSecret
38
+ def self.my_class_method; end
39
+ def my_instance_method; end
40
+ end
41
+ ```
42
+
43
+ ## Messaging models
44
+
45
+ Engine-owned messaging persistence (communications, endpoints, preferences, and related records) ships with CommandTower. Prefer platform services/workflows for mutations; do not dual-author schema in the host ([Initializing](initializing.md)).
46
+
47
+ ## Audit ledger
48
+
49
+ `CommandTower::Audit::Event` is the append-only platform ledger (`command_tower_audit_events`). Only `CommandTower::Audit::Persistence::Subscriber` writes rows. There are no foreign keys to users. Envelope `changes` persist as `change_set`. See [Audit](audit.md).
50
+
51
+ ## Related
52
+
53
+ - [Architecture](architecture.md)
54
+ - [Sensitive changes](sensitive_routes.md)
55
+ - [Testing](testing.md) — shared factories for CT-owned models
@@ -0,0 +1,47 @@
1
+ # Pagination
2
+
3
+ CommandTower exposes live HTTP list contracts that return pagination metadata: **Me Inbox**, **audit event lists** (`GET /me/audit-events`, `GET /admin/audit-events`), and **Admin Users** (`GET /admin/users`). These lists reuse the Inbox `limit` / `offset` / `totalCount` contract.
4
+
5
+ Back to [README](../README.md).
6
+
7
+ ## Me Inbox list contract
8
+
9
+ `GET /me/inbox` accepts query parameters:
10
+
11
+ | Param | Default | Notes |
12
+ |-------|---------|--------|
13
+ | `limit` | `50` | Max `100` |
14
+ | `offset` | `0` | |
15
+ | `scope` | `"inbox"` | `"inbox"` or `"archived"` |
16
+
17
+ Success envelope `meta`:
18
+
19
+ ```json
20
+ {
21
+ "limit": 50,
22
+ "offset": 0,
23
+ "totalCount": 123
24
+ }
25
+ ```
26
+
27
+ `data` is an array of inbox items. Full route table: [API reference — Me Inbox](api_reference.md#me-inbox).
28
+
29
+ Deserializer: `CommandTower::Deserializers::Messaging::Inbox::ListDeserializer`.
30
+
31
+ ## Global pagination config
32
+
33
+ `CommandTower.config.pagination.limit` defaults to **10**. That value is a generic configuration default for pagination helpers — it is **not** the Me Inbox HTTP default (Inbox uses 50).
34
+
35
+ ```ruby
36
+ CommandTower.configure do |c|
37
+ c.pagination.limit = 50
38
+ end
39
+ ```
40
+
41
+ There is no `pagination=true` / `page` / `cursor` query API on current engine HTTP surfaces. Admin audit list uses the same limit/offset contract as Inbox.
42
+
43
+ ## Related
44
+
45
+ - [API reference](api_reference.md)
46
+ - [Messaging](messaging_integration_guide.md)
47
+ - [Controllers](controllers.md)