command_tower 0.3.1 → 0.10.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 (603) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +104 -28
  3. data/app/auth/command_tower/auth/auth_context.rb +36 -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/messaging/announcements_controller.rb +34 -0
  7. data/app/controllers/command_tower/application_controller.rb +80 -14
  8. data/app/controllers/command_tower/auth/email/availability_controller.rb +35 -0
  9. data/app/controllers/command_tower/auth/email_verification/send_controller.rb +24 -0
  10. data/app/controllers/command_tower/auth/email_verification/verify_controller.rb +41 -0
  11. data/app/controllers/command_tower/auth/identity_policy_controller.rb +14 -0
  12. data/app/controllers/command_tower/auth/logout_controller.rb +14 -0
  13. data/app/controllers/command_tower/auth/password_recovery_session/create_controller.rb +17 -0
  14. data/app/controllers/command_tower/auth/password_reset/reset_controller.rb +35 -0
  15. data/app/controllers/command_tower/auth/password_reset/send_controller.rb +40 -0
  16. data/app/controllers/command_tower/auth/password_reset/validate_controller.rb +35 -0
  17. data/app/controllers/command_tower/auth/plain_text/login_controller.rb +22 -0
  18. data/app/controllers/command_tower/auth/register_controller.rb +33 -0
  19. data/app/controllers/command_tower/auth/session_controller.rb +21 -0
  20. data/app/controllers/command_tower/auth/signup_session/create_controller.rb +17 -0
  21. data/app/controllers/command_tower/auth/username/availability_controller.rb +35 -0
  22. data/app/controllers/command_tower/me/inbox_controller.rb +85 -0
  23. data/app/controllers/command_tower/me/name_controller.rb +37 -0
  24. data/app/controllers/command_tower/me/password_controller.rb +37 -0
  25. data/app/controllers/command_tower/me/phone_controller.rb +44 -0
  26. data/app/controllers/command_tower/me/phone_verification/verifications_controller.rb +23 -0
  27. data/app/controllers/command_tower/me/phone_verification/verify_controller.rb +34 -0
  28. data/app/controllers/command_tower/me/preferences_controller.rb +46 -0
  29. data/app/controllers/command_tower/me/pushover/verifications_controller.rb +23 -0
  30. data/app/controllers/command_tower/me/pushover_controller.rb +66 -0
  31. data/app/controllers/command_tower/me_controller.rb +19 -0
  32. data/app/controllers/command_tower/profile_controller.rb +19 -0
  33. data/app/controllers/concerns/command_tower/api/application_response_renderer.rb +82 -0
  34. data/app/controllers/concerns/command_tower/api/deserializer_failure_details.rb +22 -0
  35. data/app/controllers/concerns/command_tower/auth/authentication_boundary.rb +34 -0
  36. data/app/controllers/concerns/command_tower/auth/authorization_boundary.rb +26 -0
  37. data/app/controllers/concerns/command_tower/auth/invalid_credentials_deserializer_renderer.rb +23 -0
  38. data/app/controllers/concerns/command_tower/auth/password_recovery_session_boundary.rb +29 -0
  39. data/app/controllers/concerns/command_tower/auth/signup_session_boundary.rb +29 -0
  40. data/app/deserializers/command_tower/deserializers/admin/messaging/create_announcement_deserializer.rb +106 -0
  41. data/app/deserializers/command_tower/deserializers/application_deserializer.rb +148 -0
  42. data/app/deserializers/command_tower/deserializers/auth/email_availability_deserializer.rb +19 -0
  43. data/app/deserializers/command_tower/deserializers/auth/email_verification/verify_deserializer.rb +21 -0
  44. data/app/deserializers/command_tower/deserializers/auth/password_reset/reset_deserializer.rb +31 -0
  45. data/app/deserializers/command_tower/deserializers/auth/password_reset/send_deserializer.rb +21 -0
  46. data/app/deserializers/command_tower/deserializers/auth/password_reset/validate_deserializer.rb +23 -0
  47. data/app/deserializers/command_tower/deserializers/auth/plain_text/login_deserializer.rb +24 -0
  48. data/app/deserializers/command_tower/deserializers/auth/register_deserializer.rb +42 -0
  49. data/app/deserializers/command_tower/deserializers/auth/username_availability_deserializer.rb +19 -0
  50. data/app/deserializers/command_tower/deserializers/clients/errors.rb +45 -0
  51. data/app/deserializers/command_tower/deserializers/clients/missing.rb +10 -0
  52. data/app/deserializers/command_tower/deserializers/clients/payload.rb +21 -0
  53. data/app/deserializers/command_tower/deserializers/clients/result.rb +122 -0
  54. data/app/deserializers/command_tower/deserializers/clients/types.rb +192 -0
  55. data/app/deserializers/command_tower/deserializers/coercion_result.rb +35 -0
  56. data/app/deserializers/command_tower/deserializers/failure.rb +14 -0
  57. data/app/deserializers/command_tower/deserializers/me/change_password_deserializer.rb +41 -0
  58. data/app/deserializers/command_tower/deserializers/me/phone_verification/verify_deserializer.rb +29 -0
  59. data/app/deserializers/command_tower/deserializers/me/pushover/credentials_deserializer.rb +31 -0
  60. data/app/deserializers/command_tower/deserializers/me/update_name_deserializer.rb +22 -0
  61. data/app/deserializers/command_tower/deserializers/me/update_phone_deserializer.rb +22 -0
  62. data/app/deserializers/command_tower/deserializers/messaging/inbox.rb +77 -0
  63. data/app/deserializers/command_tower/deserializers/messaging/preferences/show_deserializer.rb +17 -0
  64. data/app/deserializers/command_tower/deserializers/messaging/preferences/update_deserializer.rb +97 -0
  65. data/app/errors/command_tower/errors/account/phone_already_verified_error.rb +17 -0
  66. data/app/errors/command_tower/errors/account/phone_missing_error.rb +17 -0
  67. data/app/errors/command_tower/errors/account/phone_verification_code_invalid_error.rb +17 -0
  68. data/app/errors/command_tower/errors/account/phone_verification_expired_error.rb +17 -0
  69. data/app/errors/command_tower/errors/account/phone_verification_send_failed_error.rb +25 -0
  70. data/app/errors/command_tower/errors/account/phone_verification_stale_error.rb +17 -0
  71. data/app/errors/command_tower/errors/account/phone_verification_throttled_error.rb +24 -0
  72. data/app/errors/command_tower/errors/account/pushover_already_configured_error.rb +21 -0
  73. data/app/errors/command_tower/errors/account/pushover_capability_unavailable_error.rb +21 -0
  74. data/app/errors/command_tower/errors/account/pushover_not_configured_error.rb +21 -0
  75. data/app/errors/command_tower/errors/account/pushover_provider_unavailable_error.rb +21 -0
  76. data/app/errors/command_tower/errors/account/pushover_verification_failed_error.rb +27 -0
  77. data/app/errors/command_tower/errors/account/sms_capability_unavailable_error.rb +21 -0
  78. data/app/errors/command_tower/errors/application_error.rb +27 -0
  79. data/app/errors/command_tower/errors/auth/csrf_mismatch_error.rb +17 -0
  80. data/app/errors/command_tower/errors/auth/csrf_missing_error.rb +17 -0
  81. data/app/errors/command_tower/errors/auth/email_already_registered_error.rb +17 -0
  82. data/app/errors/command_tower/errors/auth/email_verification_required_error.rb +21 -0
  83. data/app/errors/command_tower/errors/auth/invalid_credentials_error.rb +21 -0
  84. data/app/errors/command_tower/errors/auth/password_recovery_ip_rate_limit_error.rb +25 -0
  85. data/app/errors/command_tower/errors/auth/password_recovery_session_expired_error.rb +21 -0
  86. data/app/errors/command_tower/errors/auth/password_recovery_session_invalid_error.rb +21 -0
  87. data/app/errors/command_tower/errors/auth/password_recovery_session_missing_error.rb +21 -0
  88. data/app/errors/command_tower/errors/auth/password_recovery_session_rate_limit_error.rb +25 -0
  89. data/app/errors/command_tower/errors/auth/password_reset_invalid_token_error.rb +21 -0
  90. data/app/errors/command_tower/errors/auth/password_reset_unavailable_error.rb +21 -0
  91. data/app/errors/command_tower/errors/auth/signup_ip_rate_limit_error.rb +25 -0
  92. data/app/errors/command_tower/errors/auth/signup_session_expired_error.rb +17 -0
  93. data/app/errors/command_tower/errors/auth/signup_session_invalid_error.rb +17 -0
  94. data/app/errors/command_tower/errors/auth/signup_session_missing_error.rb +17 -0
  95. data/app/errors/command_tower/errors/auth/signup_session_rate_limit_error.rb +25 -0
  96. data/app/errors/command_tower/errors/auth/verification_code_invalid_error.rb +17 -0
  97. data/app/errors/command_tower/errors/auth/verification_send_failed_error.rb +25 -0
  98. data/app/errors/command_tower/errors/forbidden_error.rb +19 -0
  99. data/app/errors/command_tower/errors/internal_error.rb +19 -0
  100. data/app/errors/command_tower/errors/messaging/accept_rejected_error.rb +21 -0
  101. data/app/errors/command_tower/errors/messaging/idempotency_conflict_error.rb +21 -0
  102. data/app/errors/command_tower/errors/messaging/recipient_unresolved_error.rb +21 -0
  103. data/app/errors/command_tower/errors/not_found_error.rb +19 -0
  104. data/app/errors/command_tower/errors/unauthorized_error.rb +19 -0
  105. data/app/errors/command_tower/errors/validation_error.rb +15 -0
  106. data/app/jobs/command_tower/messaging/channel_delivery_execution_job.rb +18 -0
  107. data/app/jobs/command_tower/messaging/communications/produce_recipient_job.rb +24 -0
  108. data/app/jobs/command_tower/messaging/execution_recovery_job.rb +13 -0
  109. data/app/jobs/command_tower/messaging/handoff_job.rb +15 -0
  110. data/app/jobs/command_tower/messaging/handoff_recovery_job.rb +13 -0
  111. data/app/mailers/command_tower/email_verification_mailer.rb +5 -3
  112. data/app/mailers/command_tower/messaging/channel_mailer.rb +25 -0
  113. data/app/mailers/command_tower/password_reset_mailer.rb +18 -0
  114. data/app/models/command_tower/messaging/channel_delivery.rb +45 -0
  115. data/app/models/command_tower/messaging/communication.rb +60 -0
  116. data/app/models/command_tower/messaging/delivery_attempt.rb +28 -0
  117. data/app/models/command_tower/messaging/destination_plan.rb +17 -0
  118. data/app/models/command_tower/messaging/endpoint.rb +98 -0
  119. data/app/models/command_tower/messaging/endpoint_pushover_credential.rb +18 -0
  120. data/app/models/command_tower/messaging/inbox_item.rb +52 -0
  121. data/app/models/command_tower/messaging/notification_preference.rb +21 -0
  122. data/app/models/user.rb +4 -1
  123. data/app/serializers/command_tower/serializers/admin/messaging/announcement_response_serializer.rb +41 -0
  124. data/app/serializers/command_tower/serializers/application/envelope_serializer.rb +25 -0
  125. data/app/serializers/command_tower/serializers/application/error_entry_serializer.rb +18 -0
  126. data/app/serializers/command_tower/serializers/application_serializer.rb +26 -0
  127. data/app/serializers/command_tower/serializers/auth/email_availability_serializer.rb +17 -0
  128. data/app/serializers/command_tower/serializers/auth/email_verification/message_response_serializer.rb +15 -0
  129. data/app/serializers/command_tower/serializers/auth/identity_policy_serializer.rb +36 -0
  130. data/app/serializers/command_tower/serializers/auth/login_response_serializer.rb +17 -0
  131. data/app/serializers/command_tower/serializers/auth/logout_response_serializer.rb +13 -0
  132. data/app/serializers/command_tower/serializers/auth/password_recovery_session_response_serializer.rb +16 -0
  133. data/app/serializers/command_tower/serializers/auth/password_reset/message_response_serializer.rb +15 -0
  134. data/app/serializers/command_tower/serializers/auth/password_reset/validate_response_serializer.rb +22 -0
  135. data/app/serializers/command_tower/serializers/auth/register_response_serializer.rb +16 -0
  136. data/app/serializers/command_tower/serializers/auth/session_response_serializer.rb +16 -0
  137. data/app/serializers/command_tower/serializers/auth/signup_session_response_serializer.rb +16 -0
  138. data/app/serializers/command_tower/serializers/auth/user_serializer.rb +21 -0
  139. data/app/serializers/command_tower/serializers/auth/username_availability_serializer.rb +17 -0
  140. data/app/serializers/command_tower/serializers/me/account_serializer.rb +45 -0
  141. data/app/serializers/command_tower/serializers/me/change_password_response_serializer.rb +13 -0
  142. data/app/serializers/command_tower/serializers/me/pushover_serializer.rb +59 -0
  143. data/app/serializers/command_tower/serializers/messaging/inbox.rb +45 -0
  144. data/app/serializers/command_tower/serializers/messaging/preferences/catalog_serializer.rb +17 -0
  145. data/app/serializers/command_tower/serializers/messaging/preferences/category_serializer.rb +23 -0
  146. data/app/serializers/command_tower/serializers/messaging/preferences/notification_serializer.rb +30 -0
  147. data/app/serializers/command_tower/serializers/profile/profile_serializer.rb +13 -0
  148. data/app/services/command_tower/README.md +22 -6
  149. data/app/services/command_tower/auth/request_context.rb +21 -0
  150. data/app/services/command_tower/authorize/validate.rb +54 -18
  151. data/app/services/command_tower/clients/client_base.rb +183 -0
  152. data/app/services/command_tower/clients/client_result.rb +45 -0
  153. data/app/services/command_tower/clients/const_resolution.rb +32 -0
  154. data/app/services/command_tower/clients/decoded_response.rb +16 -0
  155. data/app/services/command_tower/clients/endpoint_base.rb +242 -0
  156. data/app/services/command_tower/clients/endpoint_input.rb +18 -0
  157. data/app/services/command_tower/clients/errors/authentication_error.rb +26 -0
  158. data/app/services/command_tower/clients/errors/configuration_error.rb +10 -0
  159. data/app/services/command_tower/clients/errors/deserialization_error.rb +26 -0
  160. data/app/services/command_tower/clients/errors/discovery_error.rb +10 -0
  161. data/app/services/command_tower/clients/errors/upstream_error.rb +26 -0
  162. data/app/services/command_tower/clients/invocation.rb +61 -0
  163. data/app/services/command_tower/clients/namespace_proxy.rb +75 -0
  164. data/app/services/command_tower/clients/scoped_client.rb +88 -0
  165. data/app/services/command_tower/clients/serialized_request.rb +17 -0
  166. data/app/services/command_tower/clients/transport/error.rb +18 -0
  167. data/app/services/command_tower/clients/transport/faraday_adapter.rb +129 -0
  168. data/app/services/command_tower/clients/transport/faraday_config.rb +45 -0
  169. data/app/services/command_tower/clients/transport/request.rb +50 -0
  170. data/app/services/command_tower/clients/transport/response.rb +22 -0
  171. data/app/services/command_tower/clients/url.rb +56 -0
  172. data/app/services/command_tower/identity/phone/normalizer.rb +41 -0
  173. data/app/services/command_tower/identity/phone_verification/sms_configuration.rb +58 -0
  174. data/app/services/command_tower/identity/phone_verification/sms_transport/adapters/fake_adapter.rb +35 -0
  175. data/app/services/command_tower/identity/phone_verification/sms_transport/adapters/log_adapter.rb +34 -0
  176. data/app/services/command_tower/identity/phone_verification/sms_transport/adapters/twilio_adapter.rb +60 -0
  177. data/app/services/command_tower/identity/phone_verification/sms_transport.rb +42 -0
  178. data/app/services/command_tower/jwt/authenticate_user.rb +61 -34
  179. data/app/services/command_tower/jwt/authentication_outcome.rb +36 -0
  180. data/app/services/command_tower/jwt/decode.rb +27 -8
  181. data/app/services/command_tower/jwt/encode.rb +4 -6
  182. data/app/services/command_tower/jwt/login_create.rb +6 -7
  183. data/app/services/command_tower/login_strategy/plain_text/email_verification/required.rb +11 -9
  184. data/app/services/command_tower/messaging/accept/channel_delivery_result.rb +13 -0
  185. data/app/services/command_tower/messaging/accept/coordinator.rb +166 -0
  186. data/app/services/command_tower/messaging/accept/error.rb +9 -0
  187. data/app/services/command_tower/messaging/accept/excluded_destination.rb +24 -0
  188. data/app/services/command_tower/messaging/accept/handoff_scheduler.rb +40 -0
  189. data/app/services/command_tower/messaging/accept/idempotency_conflict_error.rb +9 -0
  190. data/app/services/command_tower/messaging/accept/illegal_override_error.rb +9 -0
  191. data/app/services/command_tower/messaging/accept/impossible_mandatory_plan_error.rb +9 -0
  192. data/app/services/command_tower/messaging/accept/invalid_preference_error.rb +9 -0
  193. data/app/services/command_tower/messaging/accept/invariant_error.rb +9 -0
  194. data/app/services/command_tower/messaging/accept/operation_logger.rb +97 -0
  195. data/app/services/command_tower/messaging/accept/persistence_error.rb +9 -0
  196. data/app/services/command_tower/messaging/accept/persister.rb +90 -0
  197. data/app/services/command_tower/messaging/accept/request_normalizer.rb +100 -0
  198. data/app/services/command_tower/messaging/accept/result.rb +99 -0
  199. data/app/services/command_tower/messaging/accept/unknown_type_error.rb +9 -0
  200. data/app/services/command_tower/messaging/accept/validation_error.rb +9 -0
  201. data/app/services/command_tower/messaging/channel_detectors.rb +52 -0
  202. data/app/services/command_tower/messaging/channels/definition.rb +24 -0
  203. data/app/services/command_tower/messaging/channels/error.rb +9 -0
  204. data/app/services/command_tower/messaging/channels/unknown_channel_error.rb +9 -0
  205. data/app/services/command_tower/messaging/channels.rb +85 -0
  206. data/app/services/command_tower/messaging/contract/communications.rb +29 -0
  207. data/app/services/command_tower/messaging/contract/error.rb +9 -0
  208. data/app/services/command_tower/messaging/contract/internal/finder.rb +43 -0
  209. data/app/services/command_tower/messaging/contract/invariant_error.rb +9 -0
  210. data/app/services/command_tower/messaging/contract/mappers/channel_delivery_mapper.rb +53 -0
  211. data/app/services/command_tower/messaging/contract/mappers/communication_mapper.rb +61 -0
  212. data/app/services/command_tower/messaging/contract/mappers/delivery_attempt_mapper.rb +27 -0
  213. data/app/services/command_tower/messaging/contract/mappers/destination_plan_mapper.rb +17 -0
  214. data/app/services/command_tower/messaging/contract/mappers/inbox_item_mapper.rb +17 -0
  215. data/app/services/command_tower/messaging/contract/not_found_error.rb +9 -0
  216. data/app/services/command_tower/messaging/contract/observability/correlation.rb +17 -0
  217. data/app/services/command_tower/messaging/contract/observability/operation_logger.rb +101 -0
  218. data/app/services/command_tower/messaging/contract/observability/structured_logger.rb +56 -0
  219. data/app/services/command_tower/messaging/contract/requests/find_communication.rb +21 -0
  220. data/app/services/command_tower/messaging/contract/results/channel_delivery_result.rb +25 -0
  221. data/app/services/command_tower/messaging/contract/results/communication_result.rb +22 -0
  222. data/app/services/command_tower/messaging/contract/results/delivery_attempt_result.rb +21 -0
  223. data/app/services/command_tower/messaging/contract/results/destination_plan_result.rb +11 -0
  224. data/app/services/command_tower/messaging/contract/results/inbox_item_result.rb +11 -0
  225. data/app/services/command_tower/messaging/contract/validation_error.rb +9 -0
  226. data/app/services/command_tower/messaging/delivery_retry_policy.rb +30 -0
  227. data/app/services/command_tower/messaging/endpoints/begin_verification.rb +13 -0
  228. data/app/services/command_tower/messaging/endpoints/channel_gate.rb +39 -0
  229. data/app/services/command_tower/messaging/endpoints/conflict_error.rb +9 -0
  230. data/app/services/command_tower/messaging/endpoints/create.rb +181 -0
  231. data/app/services/command_tower/messaging/endpoints/error.rb +9 -0
  232. data/app/services/command_tower/messaging/endpoints/fingerprinter.rb +50 -0
  233. data/app/services/command_tower/messaging/endpoints/invalid_transition_error.rb +9 -0
  234. data/app/services/command_tower/messaging/endpoints/lifecycle.rb +37 -0
  235. data/app/services/command_tower/messaging/endpoints/mark_invalid.rb +32 -0
  236. data/app/services/command_tower/messaging/endpoints/mark_verification_failed.rb +13 -0
  237. data/app/services/command_tower/messaging/endpoints/mark_verified.rb +13 -0
  238. data/app/services/command_tower/messaging/endpoints/not_found_error.rb +9 -0
  239. data/app/services/command_tower/messaging/endpoints/persistence.rb +91 -0
  240. data/app/services/command_tower/messaging/endpoints/pushover/verify.rb +101 -0
  241. data/app/services/command_tower/messaging/endpoints/query.rb +28 -0
  242. data/app/services/command_tower/messaging/endpoints/replace.rb +181 -0
  243. data/app/services/command_tower/messaging/endpoints/reset_verification.rb +13 -0
  244. data/app/services/command_tower/messaging/endpoints/revoke.rb +40 -0
  245. data/app/services/command_tower/messaging/endpoints/safe_view.rb +50 -0
  246. data/app/services/command_tower/messaging/endpoints/secret_box.rb +86 -0
  247. data/app/services/command_tower/messaging/endpoints/secret_reader.rb +72 -0
  248. data/app/services/command_tower/messaging/endpoints/validation_error.rb +9 -0
  249. data/app/services/command_tower/messaging/endpoints/validators/push.rb +24 -0
  250. data/app/services/command_tower/messaging/endpoints/validators/pushover.rb +68 -0
  251. data/app/services/command_tower/messaging/endpoints/validators.rb +36 -0
  252. data/app/services/command_tower/messaging/endpoints/verification.rb +39 -0
  253. data/app/services/command_tower/messaging/endpoints/verification_failed_error.rb +18 -0
  254. data/app/services/command_tower/messaging/endpoints/verification_transition.rb +20 -0
  255. data/app/services/command_tower/messaging/endpoints.rb +55 -0
  256. data/app/services/command_tower/messaging/execution/adapter_request.rb +45 -0
  257. data/app/services/command_tower/messaging/execution/adapter_result.rb +81 -0
  258. data/app/services/command_tower/messaging/execution/adapters/email/adapter.rb +78 -0
  259. data/app/services/command_tower/messaging/execution/adapters/email/configuration.rb +55 -0
  260. data/app/services/command_tower/messaging/execution/adapters/fake_adapter.rb +34 -0
  261. data/app/services/command_tower/messaging/execution/adapters/pushover/adapter.rb +107 -0
  262. data/app/services/command_tower/messaging/execution/adapters/pushover/configuration.rb +30 -0
  263. data/app/services/command_tower/messaging/execution/adapters/sms/adapter.rb +90 -0
  264. data/app/services/command_tower/messaging/execution/adapters/sms/configuration.rb +58 -0
  265. data/app/services/command_tower/messaging/execution/adapters/sms/log_adapter.rb +34 -0
  266. data/app/services/command_tower/messaging/execution/adapters/sms/twilio_http_client.rb +70 -0
  267. data/app/services/command_tower/messaging/execution/adapters/unconfigured_adapter.rb +20 -0
  268. data/app/services/command_tower/messaging/execution/attempt_ledger.rb +146 -0
  269. data/app/services/command_tower/messaging/execution/claim.rb +35 -0
  270. data/app/services/command_tower/messaging/execution/invalid_adapter_contract_error.rb +9 -0
  271. data/app/services/command_tower/messaging/execution/operation_logger.rb +237 -0
  272. data/app/services/command_tower/messaging/execution/readiness_terminal_mapping.rb +37 -0
  273. data/app/services/command_tower/messaging/execution/recovery.rb +78 -0
  274. data/app/services/command_tower/messaging/execution/resolve_recipient_address.rb +58 -0
  275. data/app/services/command_tower/messaging/execution/revalidate_readiness.rb +73 -0
  276. data/app/services/command_tower/messaging/execution/scheduler.rb +38 -0
  277. data/app/services/command_tower/messaging/execution/select_adapter.rb +63 -0
  278. data/app/services/command_tower/messaging/handoff/advance_communication.rb +39 -0
  279. data/app/services/command_tower/messaging/handoff/operation_logger.rb +78 -0
  280. data/app/services/command_tower/messaging/handoff/recovery.rb +26 -0
  281. data/app/services/command_tower/messaging/inbox/bulk_result.rb +19 -0
  282. data/app/services/command_tower/messaging/inbox/error.rb +9 -0
  283. data/app/services/command_tower/messaging/inbox/invalid_bulk_items_error.rb +19 -0
  284. data/app/services/command_tower/messaging/inbox/invariant_error.rb +9 -0
  285. data/app/services/command_tower/messaging/inbox/item_result.rb +64 -0
  286. data/app/services/command_tower/messaging/inbox/list_result.rb +18 -0
  287. data/app/services/command_tower/messaging/inbox/mutator.rb +252 -0
  288. data/app/services/command_tower/messaging/inbox/not_found_error.rb +9 -0
  289. data/app/services/command_tower/messaging/inbox/operation_logger.rb +37 -0
  290. data/app/services/command_tower/messaging/inbox/reader.rb +117 -0
  291. data/app/services/command_tower/messaging/inbox/scope.rb +24 -0
  292. data/app/services/command_tower/messaging/inbox/unread_count_result.rb +16 -0
  293. data/app/services/command_tower/messaging/inbox/validation_error.rb +9 -0
  294. data/app/services/command_tower/messaging/inbox.rb +61 -0
  295. data/app/services/command_tower/messaging/notification_types/catalog_category.rb +19 -0
  296. data/app/services/command_tower/messaging/notification_types/declaration.rb +96 -0
  297. data/app/services/command_tower/messaging/notification_types/declaration_validator.rb +152 -0
  298. data/app/services/command_tower/messaging/notification_types/duplicate_type_error.rb +9 -0
  299. data/app/services/command_tower/messaging/notification_types/error.rb +9 -0
  300. data/app/services/command_tower/messaging/notification_types/invalid_declaration_error.rb +9 -0
  301. data/app/services/command_tower/messaging/notification_types/not_found_error.rb +9 -0
  302. data/app/services/command_tower/messaging/notification_types/registry.rb +103 -0
  303. data/app/services/command_tower/messaging/notification_types/sealed_registry_error.rb +9 -0
  304. data/app/services/command_tower/messaging/notification_types.rb +37 -0
  305. data/app/services/command_tower/messaging/planner/destination_plan.rb +41 -0
  306. data/app/services/command_tower/messaging/planner/error.rb +9 -0
  307. data/app/services/command_tower/messaging/planner/excluded_destination.rb +28 -0
  308. data/app/services/command_tower/messaging/planner/illegal_override_error.rb +9 -0
  309. data/app/services/command_tower/messaging/planner/impossible_mandatory_plan_error.rb +9 -0
  310. data/app/services/command_tower/messaging/planner/invalid_evaluation_error.rb +9 -0
  311. data/app/services/command_tower/messaging/planner/message_overrides.rb +33 -0
  312. data/app/services/command_tower/messaging/planner/operation_logger.rb +28 -0
  313. data/app/services/command_tower/messaging/planner/planner.rb +261 -0
  314. data/app/services/command_tower/messaging/planner/unknown_type_error.rb +9 -0
  315. data/app/services/command_tower/messaging/planner.rb +25 -0
  316. data/app/services/command_tower/messaging/preferences/catalog.rb +96 -0
  317. data/app/services/command_tower/messaging/preferences/catalog_category_result.rb +19 -0
  318. data/app/services/command_tower/messaging/preferences/catalog_notification_result.rb +55 -0
  319. data/app/services/command_tower/messaging/preferences/catalog_result.rb +13 -0
  320. data/app/services/command_tower/messaging/preferences/error.rb +9 -0
  321. data/app/services/command_tower/messaging/preferences/evaluation_result.rb +61 -0
  322. data/app/services/command_tower/messaging/preferences/evaluator.rb +194 -0
  323. data/app/services/command_tower/messaging/preferences/invalid_preference_state_error.rb +9 -0
  324. data/app/services/command_tower/messaging/preferences/invalid_preference_write_error.rb +10 -0
  325. data/app/services/command_tower/messaging/preferences/not_settings_visible_error.rb +10 -0
  326. data/app/services/command_tower/messaging/preferences/preference_state.rb +61 -0
  327. data/app/services/command_tower/messaging/preferences/reason_classes.rb +17 -0
  328. data/app/services/command_tower/messaging/preferences/resolve.rb +50 -0
  329. data/app/services/command_tower/messaging/preferences/store.rb +126 -0
  330. data/app/services/command_tower/messaging/preferences/store_error.rb +10 -0
  331. data/app/services/command_tower/messaging/preferences/suppressed_destination.rb +24 -0
  332. data/app/services/command_tower/messaging/preferences/unknown_type_error.rb +9 -0
  333. data/app/services/command_tower/messaging/preferences/update.rb +248 -0
  334. data/app/services/command_tower/messaging/preferences.rb +68 -0
  335. data/app/services/command_tower/messaging/pushover/adapters/disabled_adapter.rb +33 -0
  336. data/app/services/command_tower/messaging/pushover/adapters/fake_adapter.rb +90 -0
  337. data/app/services/command_tower/messaging/pushover/adapters/http_adapter.rb +145 -0
  338. data/app/services/command_tower/messaging/pushover/adapters/log_adapter.rb +52 -0
  339. data/app/services/command_tower/messaging/pushover/result.rb +34 -0
  340. data/app/services/command_tower/messaging/pushover/transport.rb +64 -0
  341. data/app/services/command_tower/messaging/recipient_readiness/channel_result.rb +55 -0
  342. data/app/services/command_tower/messaging/recipient_readiness/error.rb +9 -0
  343. data/app/services/command_tower/messaging/recipient_readiness/evaluate.rb +319 -0
  344. data/app/services/command_tower/messaging/recipient_readiness/identity_facts.rb +54 -0
  345. data/app/services/command_tower/messaging/recipient_readiness/reason_codes.rb +33 -0
  346. data/app/services/command_tower/messaging/recipient_readiness/recipient_not_found_error.rb +9 -0
  347. data/app/services/command_tower/messaging/recipient_readiness/recipient_result.rb +38 -0
  348. data/app/services/command_tower/messaging/recipient_readiness/unknown_channel_error.rb +9 -0
  349. data/app/services/command_tower/messaging/recipient_readiness.rb +26 -0
  350. data/app/services/command_tower/messaging/rendering/channel_renderer.rb +127 -0
  351. data/app/services/command_tower/messaging/rendering/render_error.rb +24 -0
  352. data/app/services/command_tower/messaging/rendering/rendered_payload.rb +44 -0
  353. data/app/services/command_tower/messaging/rendering/rendered_pushover_payload.rb +43 -0
  354. data/app/services/command_tower/messaging/rendering/rendered_sms_payload.rb +40 -0
  355. data/app/services/command_tower/messaging.rb +35 -0
  356. data/app/services/command_tower/secrets/cleanse.rb +19 -5
  357. data/app/services/command_tower/secrets/generate.rb +62 -27
  358. data/app/services/command_tower/secrets/verify.rb +46 -12
  359. data/app/services/command_tower/secrets.rb +2 -0
  360. data/app/services/command_tower/services/account/clear_phone.rb +25 -0
  361. data/app/services/command_tower/services/account/phone_verification/send.rb +114 -0
  362. data/app/services/command_tower/services/account/phone_verification/verify.rb +88 -0
  363. data/app/services/command_tower/services/account/pushover/create.rb +28 -0
  364. data/app/services/command_tower/services/account/pushover/ct_support.rb +70 -0
  365. data/app/services/command_tower/services/account/pushover/destroy.rb +30 -0
  366. data/app/services/command_tower/services/account/pushover/replace.rb +28 -0
  367. data/app/services/command_tower/services/account/pushover/show.rb +19 -0
  368. data/app/services/command_tower/services/account/pushover/verify.rb +30 -0
  369. data/app/services/command_tower/services/account/update_phone.rb +50 -0
  370. data/app/services/command_tower/services/application_service.rb +21 -0
  371. data/app/services/command_tower/services/auth/authenticate_session.rb +105 -0
  372. data/app/services/command_tower/services/auth/authorize_request.rb +34 -0
  373. data/app/services/command_tower/services/auth/client_ip_resolver.rb +13 -0
  374. data/app/services/command_tower/services/auth/email_availability.rb +42 -0
  375. data/app/services/command_tower/services/auth/email_verification/send.rb +65 -0
  376. data/app/services/command_tower/services/auth/email_verification/verify.rb +51 -0
  377. data/app/services/command_tower/services/auth/identity_policy.rb +60 -0
  378. data/app/services/command_tower/services/auth/password_recovery/rate_limits/check_send.rb +48 -0
  379. data/app/services/command_tower/services/auth/password_recovery/rate_limits/check_token_issue.rb +35 -0
  380. data/app/services/command_tower/services/auth/password_recovery/rate_limits/enforcement.rb +53 -0
  381. data/app/services/command_tower/services/auth/password_recovery_session/create.rb +26 -0
  382. data/app/services/command_tower/services/auth/password_recovery_session/decode.rb +29 -0
  383. data/app/services/command_tower/services/auth/password_recovery_session/encode.rb +31 -0
  384. data/app/services/command_tower/services/auth/password_recovery_session/validate.rb +58 -0
  385. data/app/services/command_tower/services/auth/password_reset/reset.rb +65 -0
  386. data/app/services/command_tower/services/auth/password_reset/send.rb +77 -0
  387. data/app/services/command_tower/services/auth/password_reset/token_verification.rb +68 -0
  388. data/app/services/command_tower/services/auth/password_reset/validate.rb +29 -0
  389. data/app/services/command_tower/services/auth/plain_text/login.rb +44 -0
  390. data/app/services/command_tower/services/auth/register.rb +77 -0
  391. data/app/services/command_tower/services/auth/signup_rate_limits/check_availability.rb +52 -0
  392. data/app/services/command_tower/services/auth/signup_rate_limits/check_register.rb +24 -0
  393. data/app/services/command_tower/services/auth/signup_rate_limits/check_token_issue.rb +33 -0
  394. data/app/services/command_tower/services/auth/signup_rate_limits/enforcement.rb +50 -0
  395. data/app/services/command_tower/services/auth/signup_session/create.rb +26 -0
  396. data/app/services/command_tower/services/auth/signup_session/decode.rb +29 -0
  397. data/app/services/command_tower/services/auth/signup_session/encode.rb +31 -0
  398. data/app/services/command_tower/services/auth/signup_session/validate.rb +58 -0
  399. data/app/services/command_tower/services/auth/username_availability.rb +28 -0
  400. data/app/services/command_tower/services/me/capabilities.rb +43 -0
  401. data/app/services/command_tower/services/me/change_password.rb +84 -0
  402. data/app/services/command_tower/services/me/pushover_product_gate.rb +18 -0
  403. data/app/services/command_tower/services/me/sms_product_gate.rb +19 -0
  404. data/app/services/command_tower/services/me/update_name.rb +58 -0
  405. data/app/services/command_tower/services/messaging/communications/produce.rb +68 -0
  406. data/app/services/command_tower/services/messaging/communications/produce_many.rb +154 -0
  407. data/app/services/command_tower/services/messaging/inbox.rb +129 -0
  408. data/app/services/command_tower/services/messaging/preferences/platform_enabled_channels.rb +20 -0
  409. data/app/services/command_tower/services/messaging/preferences/show.rb +36 -0
  410. data/app/services/command_tower/services/messaging/preferences/update.rb +43 -0
  411. data/app/services/command_tower/services/messaging/recipients.rb +20 -0
  412. data/app/services/command_tower/services/rate_limits/check.rb +31 -0
  413. data/app/services/command_tower/services/service_result.rb +73 -0
  414. data/app/services/command_tower/user_attributes/mutate.rb +154 -0
  415. data/app/services/command_tower/username/available.rb +24 -11
  416. data/app/views/command_tower/email_verification_mailer/verify_email.html.erb +70 -22
  417. data/app/views/command_tower/messaging/rendering/email.html.erb +28 -0
  418. data/app/views/command_tower/messaging/rendering/email.text.erb +7 -0
  419. data/app/views/command_tower/messaging/rendering/pushover.text.erb +1 -0
  420. data/app/views/command_tower/messaging/rendering/sms.text.erb +1 -0
  421. data/app/views/command_tower/password_reset_mailer/reset_password.html.erb +107 -0
  422. data/app/views/layouts/mailer.html.erb +13 -0
  423. data/app/views/layouts/mailer.text.erb +1 -0
  424. data/app/workflows/command_tower/workflows/admin/messaging/create_announcement_workflow.rb +62 -0
  425. data/app/workflows/command_tower/workflows/application_workflow.rb +68 -0
  426. data/app/workflows/command_tower/workflows/auth/authenticate_request_workflow.rb +40 -0
  427. data/app/workflows/command_tower/workflows/auth/authentication_response_effects.rb +21 -0
  428. data/app/workflows/command_tower/workflows/auth/authorize_request_workflow.rb +28 -0
  429. data/app/workflows/command_tower/workflows/auth/email_availability_workflow.rb +39 -0
  430. data/app/workflows/command_tower/workflows/auth/email_verification/send_workflow.rb +32 -0
  431. data/app/workflows/command_tower/workflows/auth/email_verification/verify_workflow.rb +35 -0
  432. data/app/workflows/command_tower/workflows/auth/identity_error_status.rb +36 -0
  433. data/app/workflows/command_tower/workflows/auth/identity_policy_workflow.rb +26 -0
  434. data/app/workflows/command_tower/workflows/auth/logout_workflow.rb +19 -0
  435. data/app/workflows/command_tower/workflows/auth/password_recovery_session/authenticate_workflow.rb +49 -0
  436. data/app/workflows/command_tower/workflows/auth/password_recovery_session/create_workflow.rb +39 -0
  437. data/app/workflows/command_tower/workflows/auth/password_reset/reset_workflow.rb +40 -0
  438. data/app/workflows/command_tower/workflows/auth/password_reset/send_workflow.rb +45 -0
  439. data/app/workflows/command_tower/workflows/auth/password_reset/validate_workflow.rb +40 -0
  440. data/app/workflows/command_tower/workflows/auth/plain_text/login_workflow.rb +46 -0
  441. data/app/workflows/command_tower/workflows/auth/register_workflow.rb +83 -0
  442. data/app/workflows/command_tower/workflows/auth/session/show_workflow.rb +44 -0
  443. data/app/workflows/command_tower/workflows/auth/session_error_status.rb +30 -0
  444. data/app/workflows/command_tower/workflows/auth/signup_error_status.rb +31 -0
  445. data/app/workflows/command_tower/workflows/auth/signup_session/authenticate_workflow.rb +49 -0
  446. data/app/workflows/command_tower/workflows/auth/signup_session/create_workflow.rb +37 -0
  447. data/app/workflows/command_tower/workflows/auth/username_availability_workflow.rb +39 -0
  448. data/app/workflows/command_tower/workflows/me/change_password_workflow.rb +34 -0
  449. data/app/workflows/command_tower/workflows/me/clear_phone_workflow.rb +52 -0
  450. data/app/workflows/command_tower/workflows/me/error_mapping.rb +46 -0
  451. data/app/workflows/command_tower/workflows/me/error_status.rb +28 -0
  452. data/app/workflows/command_tower/workflows/me/phone_verification/send_workflow.rb +65 -0
  453. data/app/workflows/command_tower/workflows/me/phone_verification/verify_workflow.rb +57 -0
  454. data/app/workflows/command_tower/workflows/me/pushover/create_workflow.rb +38 -0
  455. data/app/workflows/command_tower/workflows/me/pushover/destroy_workflow.rb +34 -0
  456. data/app/workflows/command_tower/workflows/me/pushover/replace_workflow.rb +38 -0
  457. data/app/workflows/command_tower/workflows/me/pushover/show_workflow.rb +34 -0
  458. data/app/workflows/command_tower/workflows/me/pushover/verify_workflow.rb +34 -0
  459. data/app/workflows/command_tower/workflows/me/pushover/workflow_support.rb +31 -0
  460. data/app/workflows/command_tower/workflows/me/show_workflow.rb +33 -0
  461. data/app/workflows/command_tower/workflows/me/update_name_workflow.rb +48 -0
  462. data/app/workflows/command_tower/workflows/me/update_phone_workflow.rb +55 -0
  463. data/app/workflows/command_tower/workflows/messaging/communications/produce_recipient_workflow.rb +60 -0
  464. data/app/workflows/command_tower/workflows/messaging/error_mapping.rb +26 -0
  465. data/app/workflows/command_tower/workflows/messaging/execution/deliver_workflow.rb +234 -0
  466. data/app/workflows/command_tower/workflows/messaging/handoff/process_workflow.rb +90 -0
  467. data/app/workflows/command_tower/workflows/messaging/inbox.rb +97 -0
  468. data/app/workflows/command_tower/workflows/messaging/preferences/show_workflow.rb +31 -0
  469. data/app/workflows/command_tower/workflows/messaging/preferences/update_workflow.rb +37 -0
  470. data/app/workflows/command_tower/workflows/profile/show_workflow.rb +27 -0
  471. data/app/workflows/command_tower/workflows/workflow_result.rb +34 -0
  472. data/config/routes.rb +85 -37
  473. data/db/migrate/{20241117043720_create_command_tower_users.rb → 20260805000001_create_command_tower_users.rb} +7 -9
  474. data/db/migrate/{20241204065708_create_command_tower_user_secrets.rb → 20260805000002_create_command_tower_user_secrets.rb} +3 -0
  475. data/db/migrate/20260805000003_create_command_tower_messaging_core.rb +90 -0
  476. data/db/migrate/20260805000004_create_messaging_notification_preferences.rb +17 -0
  477. data/db/migrate/20260805000005_create_messaging_endpoints_and_pushover_credentials.rb +72 -0
  478. data/docs/api_reference.md +438 -0
  479. data/docs/architecture.md +30 -0
  480. data/docs/authentication.md +37 -0
  481. data/docs/authentication_authorization_guide.md +150 -0
  482. data/docs/authorization.md +34 -0
  483. data/docs/change_password_workflow.md +67 -0
  484. data/docs/controllers.md +35 -0
  485. data/docs/cookie_authentication_guide.md +167 -0
  486. data/docs/email_verification_workflow.md +58 -0
  487. data/docs/extending.md +105 -0
  488. data/docs/host_integration_guide.md +158 -0
  489. data/docs/initializing.md +169 -0
  490. data/docs/messaging_integration_guide.md +87 -0
  491. data/docs/models.md +51 -0
  492. data/docs/pagination.md +47 -0
  493. data/docs/password_reset_workflow.md +82 -0
  494. data/docs/sensitive_routes.md +47 -0
  495. data/docs/testing.md +74 -0
  496. data/docs/upgrades/0.10.0.md +58 -0
  497. data/docs/upgrades/README.md +9 -0
  498. data/lib/command_tower/authorization/default.yml +5 -33
  499. data/lib/command_tower/configuration/application/config.rb +2 -2
  500. data/lib/command_tower/configuration/base.rb +0 -1
  501. data/lib/command_tower/configuration/config.rb +41 -5
  502. data/lib/command_tower/configuration/credentials/config.rb +33 -0
  503. data/lib/command_tower/configuration/credentials/smtp.rb +33 -0
  504. data/lib/command_tower/configuration/credentials/twilio.rb +33 -0
  505. data/lib/command_tower/configuration/email/config.rb +1 -18
  506. data/lib/command_tower/configuration/identity/config.rb +19 -0
  507. data/lib/command_tower/configuration/identity/phone_verification.rb +54 -0
  508. data/lib/command_tower/configuration/jwt/config.rb +7 -0
  509. data/lib/command_tower/configuration/jwt/cookie/config.rb +64 -0
  510. data/lib/command_tower/configuration/jwt/cookie/csrf/config.rb +72 -0
  511. data/lib/command_tower/configuration/login/strategy/plain_text/config.rb +6 -0
  512. data/lib/command_tower/configuration/login/strategy/plain_text/email_verify.rb +5 -0
  513. data/lib/command_tower/configuration/login/strategy/plain_text/password_reset.rb +49 -0
  514. data/lib/command_tower/configuration/messaging/config.rb +60 -0
  515. data/lib/command_tower/configuration/messaging/pushover.rb +42 -0
  516. data/lib/command_tower/configuration/messaging/sms.rb +32 -0
  517. data/lib/command_tower/configuration/pagination/config.rb +16 -0
  518. data/lib/command_tower/configuration/password_recovery_session/config.rb +61 -0
  519. data/lib/command_tower/configuration/password_recovery_session/rate_limits.rb +33 -0
  520. data/lib/command_tower/configuration/signup_session/config.rb +67 -0
  521. data/lib/command_tower/configuration/signup_session/email_availability.rb +18 -0
  522. data/lib/command_tower/configuration/signup_session/rate_limits.rb +48 -0
  523. data/lib/command_tower/configuration/user/config.rb +6 -5
  524. data/lib/command_tower/credential_resolution/env_backend.rb +25 -0
  525. data/lib/command_tower/credential_resolution/smtp_action_mailer_bridge.rb +24 -0
  526. data/lib/command_tower/credential_resolution/smtp_credentials.rb +26 -0
  527. data/lib/command_tower/credential_resolution/twilio_credentials.rb +26 -0
  528. data/lib/command_tower/credential_resolution.rb +78 -0
  529. data/lib/command_tower/current.rb +7 -0
  530. data/lib/command_tower/engine.rb +4 -1
  531. data/lib/command_tower/install/baseline.rb +31 -0
  532. data/lib/command_tower/install/doctor.rb +227 -0
  533. data/lib/command_tower/jwt/authorization_helper.rb +136 -0
  534. data/lib/command_tower/jwt/csrf_helper.rb +138 -0
  535. data/lib/command_tower/password_recovery/authorization_helper.rb +25 -0
  536. data/lib/command_tower/redis_connection.rb +21 -0
  537. data/lib/command_tower/schema/error/email_validation_required.rb +15 -0
  538. data/lib/command_tower/schema/shared/user.rb +32 -0
  539. data/lib/command_tower/schema.rb +2 -25
  540. data/lib/command_tower/signup/authorization_helper.rb +25 -0
  541. data/lib/command_tower/spec_helper.rb +58 -1
  542. data/lib/command_tower/testing.rb +62 -0
  543. data/lib/command_tower/version.rb +1 -1
  544. data/lib/command_tower.rb +20 -0
  545. data/lib/generators/command_tower/configure/USAGE +20 -0
  546. data/lib/generators/command_tower/configure/configure_generator.rb +39 -0
  547. data/lib/tasks/auto_annotate_models.rake +23 -55
  548. data/lib/tasks/install.rake +81 -0
  549. data/lib/tasks/users.rake +119 -0
  550. data/spec/factories/entity.rb +37 -0
  551. data/spec/factories/messaging.rb +156 -0
  552. data/spec/factories/role.rb +29 -0
  553. data/spec/factories/user.rb +53 -0
  554. data/spec/factories/user_secret.rb +12 -0
  555. metadata +579 -53
  556. data/app/controllers/command_tower/admin_controller.rb +0 -104
  557. data/app/controllers/command_tower/auth/plain_text_controller.rb +0 -132
  558. data/app/controllers/command_tower/inbox/message_blast_controller.rb +0 -89
  559. data/app/controllers/command_tower/inbox/message_controller.rb +0 -79
  560. data/app/controllers/command_tower/user_controller.rb +0 -49
  561. data/app/controllers/command_tower/username_controller.rb +0 -26
  562. data/app/helpers/command_tower/schema_helper.rb +0 -29
  563. data/app/models/message.rb +0 -30
  564. data/app/models/message_blast.rb +0 -27
  565. data/app/services/command_tower/inbox_service/blast/delete.rb +0 -23
  566. data/app/services/command_tower/inbox_service/blast/metadata.rb +0 -26
  567. data/app/services/command_tower/inbox_service/blast/new_user_blaster.rb +0 -24
  568. data/app/services/command_tower/inbox_service/blast/retrieve.rb +0 -30
  569. data/app/services/command_tower/inbox_service/blast/upsert.rb +0 -67
  570. data/app/services/command_tower/inbox_service/message/metadata.rb +0 -35
  571. data/app/services/command_tower/inbox_service/message/modify.rb +0 -44
  572. data/app/services/command_tower/inbox_service/message/retrieve.rb +0 -36
  573. data/app/services/command_tower/inbox_service/message/send.rb +0 -33
  574. data/app/services/command_tower/jwt/time_delay_token.rb +0 -17
  575. data/app/services/command_tower/login_strategy/plain_text/create.rb +0 -43
  576. data/app/services/command_tower/login_strategy/plain_text/email_verification/generate.rb +0 -29
  577. data/app/services/command_tower/login_strategy/plain_text/email_verification/send.rb +0 -23
  578. data/app/services/command_tower/login_strategy/plain_text/email_verification/verify.rb +0 -24
  579. data/app/services/command_tower/login_strategy/plain_text/login.rb +0 -50
  580. data/app/services/command_tower/user_attributes/modify.rb +0 -68
  581. data/app/services/command_tower/user_attributes/roles.rb +0 -27
  582. data/db/migrate/20250223023306_create_command_tower_messages.rb +0 -12
  583. data/db/migrate/20250223023313_create_command_tower_message_blasts.rb +0 -14
  584. data/lib/command_tower/schema/admin/users.rb +0 -15
  585. data/lib/command_tower/schema/inbox/blast_request.rb +0 -15
  586. data/lib/command_tower/schema/inbox/blast_response.rb +0 -16
  587. data/lib/command_tower/schema/inbox/message_blast_entity.rb +0 -16
  588. data/lib/command_tower/schema/inbox/message_blast_metadata.rb +0 -16
  589. data/lib/command_tower/schema/inbox/message_entity.rb +0 -14
  590. data/lib/command_tower/schema/inbox/metadata.rb +0 -18
  591. data/lib/command_tower/schema/inbox/modified.rb +0 -13
  592. data/lib/command_tower/schema/page.rb +0 -14
  593. data/lib/command_tower/schema/plain_text/create_user_request.rb +0 -18
  594. data/lib/command_tower/schema/plain_text/create_user_response.rb +0 -17
  595. data/lib/command_tower/schema/plain_text/email_verify_request.rb +0 -11
  596. data/lib/command_tower/schema/plain_text/email_verify_response.rb +0 -11
  597. data/lib/command_tower/schema/plain_text/email_verify_send_request.rb +0 -9
  598. data/lib/command_tower/schema/plain_text/email_verify_send_response.rb +0 -11
  599. data/lib/command_tower/schema/plain_text/login_request.rb +0 -15
  600. data/lib/command_tower/schema/plain_text/login_response.rb +0 -13
  601. data/lib/command_tower/schema/user.rb +0 -28
  602. data/lib/generators/api_engine_base/configure/USAGE +0 -8
  603. data/lib/generators/api_engine_base/configure/configure_generator.rb +0 -12
@@ -0,0 +1,67 @@
1
+ # Authenticated Password Change Workflow
2
+
3
+ Authenticated password change lets a signed-in user replace their password by proving knowledge of the current password. On success, CommandTower rotates `verifier_token` in the same transaction as the password digest update, invalidating **all** existing JWT sessions (including the caller’s). The API does **not** re-issue a JWT; hosts must clear local auth and send the user through Sign In again.
4
+
5
+ This is distinct from [password recovery](password_reset_workflow.md), which is public and recovery-session/token-based.
6
+
7
+ ## Purpose and orchestration
8
+
9
+ | Item | Value |
10
+ |------|--------|
11
+ | Route | `PATCH /me/password` (engine-relative) |
12
+ | Auth | Authentication + authorization boundaries |
13
+ | Controller | `CommandTower::Me::PasswordController#update` |
14
+ | Workflow | `CommandTower::Workflows::Me::ChangePasswordWorkflow` (`ApplicationWorkflow`, `retry_strategy :none`) |
15
+ | Service | `CommandTower::Services::Me::ChangePassword` |
16
+ | Deserializer | `CommandTower::Deserializers::Me::ChangePasswordDeserializer` |
17
+ | Serializer | `CommandTower::Serializers::Me::ChangePasswordResponseSerializer` |
18
+ | Feature gate | Route always drawn (not constrained in `routes.rb`) |
19
+
20
+ **Boundary:** The controller deserializes input and runs **one** workflow. The workflow orchestrates the change-password service and maps failures to HTTP status. It does not implement password rules itself.
21
+
22
+ ## Request
23
+
24
+ ```json
25
+ {
26
+ "current_password": "string",
27
+ "password": "string",
28
+ "password_confirmation": "string"
29
+ }
30
+ ```
31
+
32
+ ## Success (200)
33
+
34
+ Serialized success payload (message only). Response effects include `clear_token: true` so cookie/header sessions are cleared. No JWT, verifier, or password material is returned.
35
+
36
+ ## Service flow (under the workflow)
37
+
38
+ 1. Authenticate `current_password`
39
+ 2. Confirm `password` matches `password_confirmation`
40
+ 3. Enforce configured password length bounds
41
+ 4. In one DB transaction: persist new password digest → `reset_verifier_token!`
42
+ 5. On failure: typed application errors → workflow HTTP mapping
43
+
44
+ ## Failures
45
+
46
+ | Condition | Typical status |
47
+ |-----------|----------------|
48
+ | Missing / invalid JWT | 401 |
49
+ | Validation / bad current password / confirmation | 4xx via Me error mapping |
50
+ | Unexpected infra failure | 5xx |
51
+
52
+ ## Contrast with recovery reset
53
+
54
+ | | Authenticated change | Forgot / reset |
55
+ |--|----------------------|----------------|
56
+ | Proof | Current password | Recovery session + reset token |
57
+ | Route | `PATCH /me/password` | `POST /auth/password-recovery-session` + `/auth/password-reset/*` |
58
+ | Auth | JWT | Public (+ recovery session) |
59
+ | Verifier | Rotated | See recovery guide |
60
+ | Post-success | All JWTs invalid; host → Sign In | Host-defined |
61
+
62
+ ## Related
63
+
64
+ - [Sensitive changes](sensitive_routes.md)
65
+ - [API reference](api_reference.md)
66
+ - [Password reset workflow](password_reset_workflow.md)
67
+ - [Extending](extending.md)
@@ -0,0 +1,35 @@
1
+ # Controllers and routes
2
+
3
+ CommandTower exposes platform HTTP through `CommandTower::Engine` routes. Hosts typically mount the engine (for example at `/api`) via the configure generator or a custom mount.
4
+
5
+ This page is an **index** of route areas. Detailed request/response contracts live in the [API reference](api_reference.md).
6
+
7
+ ## Route areas
8
+
9
+ | Area | Prefix (engine-relative) | Purpose |
10
+ |------|--------------------------|---------|
11
+ | Auth session | `/auth/*` | Login, logout, session, register, signup-session, identity policy, availability |
12
+ | Email verification | `/auth/email-verification/*` | Send / verify email codes |
13
+ | Password recovery | `/auth/password-recovery-session`, `/auth/password-reset/*` | Forgot / reset password |
14
+ | Me / profile | `/me`, `/profile`, `/me/name`, `/me/password` | Account reads and updates |
15
+ | Inbox | `/me/inbox*` | User inbox consume (list, open, archive, bulk ops) |
16
+ | Preferences | `/me/preferences*` | Notification preferences |
17
+ | Phone | `/me/phone*` | Phone endpoint + verification |
18
+ | Pushover | `/me/pushover*` | Pushover endpoint lifecycle + verification |
19
+ | Admin messaging | `/admin/messaging/announcements` | Cohort announcements |
20
+
21
+ Exact paths depend on where the host mounts the engine.
22
+
23
+ ## Controllers
24
+
25
+ Engine controllers are transport adapters: authenticate/authorize as required, deserialize, run **exactly one** workflow, render the application envelope. See [Architecture](architecture.md).
26
+
27
+ ## Related
28
+
29
+ - [API reference](api_reference.md) — endpoint catalog
30
+ - [Messaging](messaging_integration_guide.md) — messaging surfaces summary
31
+ - [Extending](extending.md) — host extension boundaries
32
+ - [Initializing](initializing.md) — mount and configure
33
+ - [README](../README.md)
34
+
35
+ HTTP request specs for the engine live under `spec/requests/`.
@@ -0,0 +1,167 @@
1
+ # Cookie Authentication Guide
2
+
3
+ HttpOnly cookie authentication for browser / SPA hosts. Mobile and API clients typically use Bearer tokens only.
4
+
5
+ Back to [README](../README.md). Endpoint contracts: [API reference](api_reference.md). Deep authn/RBAC: [authentication_authorization_guide.md](authentication_authorization_guide.md).
6
+
7
+ Journey coverage: `spec/integration_test/auth/cookie_*.rb`.
8
+
9
+ ## Enable cookies
10
+
11
+ ```ruby
12
+ CommandTower.configure do |config|
13
+ config.jwt.cookie.enabled = true
14
+ # Optional CSRF for cookie-authenticated unsafe methods:
15
+ # config.jwt.cookie.csrf.enabled = true
16
+ end
17
+ ```
18
+
19
+ ### Defaults
20
+
21
+ | Setting | Default |
22
+ |---------|---------|
23
+ | `jwt.ttl` | `7.days` |
24
+ | `jwt.cookie.enabled` | `false` |
25
+ | `jwt.cookie.name` | `"ct_jwt"` |
26
+ | `jwt.cookie.same_site` | `:lax` |
27
+ | `jwt.cookie.secure` | `false` (set `true` in production / HTTPS) |
28
+ | `jwt.cookie.httponly` | `true` |
29
+ | `jwt.cookie.path` | `"/"` |
30
+ | `jwt.cookie.domain` | `nil` (host-only) |
31
+ | `jwt.cookie.ttl` | `7.days` |
32
+ | `jwt.cookie.csrf.enabled` | `false` |
33
+ | `jwt.cookie.csrf.cookie_name` | `"ct_csrf"` |
34
+ | `jwt.cookie.csrf.header_name` | `"X-CSRF-Token"` |
35
+ | `jwt.cookie.csrf.rotate_on_login` | `true` |
36
+ | `jwt.cookie.csrf.rotate_on_reset` | `true` |
37
+ | CSRF `same_site` / `secure` / `path` / `domain` | `nil` (inherit JWT cookie) |
38
+ | CSRF `ttl` | `7.days` |
39
+
40
+ ## Token extraction order
41
+
42
+ 1. `Authorization: Bearer <token>` header (wins when present)
43
+ 2. HttpOnly JWT cookie when cookie mode is enabled
44
+
45
+ ## Login / logout examples
46
+
47
+ Paths are engine-relative. Prefix with your mount (generator often mounts at `/`; hosts may use `/api`).
48
+
49
+ Plain-text login is gated by `config.login.plain_text.enable?`.
50
+
51
+ ### Login
52
+
53
+ ```http
54
+ POST /auth/plain-text/login
55
+ Content-Type: application/json
56
+
57
+ { "identifier": "user@example.com", "password": "secret" }
58
+ ```
59
+
60
+ Success **201** envelope:
61
+
62
+ ```json
63
+ {
64
+ "data": {
65
+ "user": {
66
+ "id": 1,
67
+ "email": "user@example.com",
68
+ "username": "user",
69
+ "firstName": "Ada",
70
+ "lastName": "Lovelace",
71
+ "emailValidated": true,
72
+ "roles": ["member"]
73
+ },
74
+ "token": "<jwt>",
75
+ "tokenExpiresAt": "<iso8601>"
76
+ },
77
+ "meta": {},
78
+ "errors": []
79
+ }
80
+ ```
81
+
82
+ When cookies are enabled, the response also sets the JWT cookie (and may set/rotate CSRF cookie). Clients that rely on cookies should use `credentials: "include"` (fetch) / `withCredentials: true` (axios).
83
+
84
+ ### Current user
85
+
86
+ ```http
87
+ GET /me
88
+ Authorization: Bearer <jwt>
89
+ ```
90
+
91
+ Or rely on the JWT cookie when cookie mode is enabled and no Bearer header is sent.
92
+
93
+ ### Logout (this browser)
94
+
95
+ ```http
96
+ POST /auth/logout
97
+ ```
98
+
99
+ Success **200**:
100
+
101
+ ```json
102
+ {
103
+ "data": { "message": "logged_out" },
104
+ "meta": {},
105
+ "errors": []
106
+ }
107
+ ```
108
+
109
+ Clears the auth cookie for this client. It does **not** rotate `verifier_token`, so other devices’ JWTs remain valid until expiry or verifier rotation.
110
+
111
+ ### Logout everywhere
112
+
113
+ Rotate the verifier via authenticated password change:
114
+
115
+ ```http
116
+ PATCH /me/password
117
+ ```
118
+
119
+ Or call `user.reset_verifier_token!` from trusted host ops. There is no `POST /user/modify` engine route.
120
+
121
+ See [sensitive_routes.md](sensitive_routes.md).
122
+
123
+ ## CSRF (optional)
124
+
125
+ When `jwt.cookie.csrf.enabled` is true, cookie-authenticated **unsafe** methods (POST/PATCH/PUT/DELETE) require:
126
+
127
+ 1. Non-HttpOnly CSRF cookie (`ct_csrf` by default)
128
+ 2. Matching header (`X-CSRF-Token` by default)
129
+
130
+ Mismatch / missing → auth failure with codes such as `csrf_missing` / `csrf_mismatch` (envelope via modern auth boundaries).
131
+
132
+ Bearer-header requests do not require CSRF.
133
+
134
+ ## CORS
135
+
136
+ Browser SPA on another origin needs host CORS that allows credentials and your frontend origin. Example sketch (host-owned):
137
+
138
+ ```ruby
139
+ # Host rack-cors or equivalent — illustrative only
140
+ allow do
141
+ origins "https://app.example.com"
142
+ resource "*",
143
+ headers: :any,
144
+ methods: [:get, :post, :put, :patch, :delete, :options],
145
+ credentials: true,
146
+ expose: ["X-Authorization-Expire", "X-Authorization-Reset"]
147
+ end
148
+ ```
149
+
150
+ `SameSite=None` cookies require `Secure=true` (HTTPS). Prefer same-site deployments with `SameSite=Lax` when possible.
151
+
152
+ ## Production checklist
153
+
154
+ - [ ] `jwt.cookie.enabled = true` only when browsers need cookies
155
+ - [ ] `jwt.cookie.secure = true` on HTTPS
156
+ - [ ] Review `same_site` for cross-site SPAs
157
+ - [ ] Enable CSRF if cookies authenticate mutating requests from browsers
158
+ - [ ] CORS credentials + explicit origin (not `*`)
159
+ - [ ] Do not log tokens or CSRF secrets
160
+
161
+ ## Related
162
+
163
+ - [API reference](api_reference.md)
164
+ - [Authentication](authentication.md)
165
+ - [Authentication & authorization guide](authentication_authorization_guide.md)
166
+ - [Sensitive changes](sensitive_routes.md)
167
+ - [Initializing](initializing.md)
@@ -0,0 +1,58 @@
1
+ # Email Verification Workflow
2
+
3
+ Code-based email verification ensures the user can receive mail at their registered address. Users authenticate with JWT; a configurable grace period may allow API access before verification is mandatory.
4
+
5
+ ## Purpose and orchestration
6
+
7
+ | Step | Route | Workflow |
8
+ |------|-------|----------|
9
+ | Send code | `POST /auth/email-verification/send` | `Workflows::Auth::EmailVerification::SendWorkflow` |
10
+ | Verify code | `POST /auth/email-verification/verify` | `Workflows::Auth::EmailVerification::VerifyWorkflow` |
11
+
12
+ Both workflows inherit `ApplicationWorkflow` with `retry_strategy :none`.
13
+
14
+ | Item | Value |
15
+ |------|--------|
16
+ | Controllers | `CommandTower::Auth::EmailVerification::SendController` / `VerifyController` |
17
+ | Auth | Authentication + authorization boundaries; send bypasses email-validation precondition so unverified users can request codes |
18
+ | Feature gate | `CommandTower.config.login.plain_text.email_verify?` |
19
+
20
+ **Boundary:** Controllers authenticate/authorize, run **one** workflow, render results. Workflows orchestrate verification services. Hosts do not reopen JWT or email-verification framework internals — see [extending.md](extending.md).
21
+
22
+ ## Key characteristics
23
+
24
+ - **Method:** Numeric code (length configurable; commonly 6 digits)
25
+ - **Delivery:** Email to the registered address
26
+ - **Expiration:** Configurable (commonly ~10 minutes)
27
+ - **Authentication required:** Valid JWT
28
+ - **Grace period:** Configurable window before verification is enforced on other routes
29
+
30
+ ## Endpoints (engine-relative)
31
+
32
+ ### Send
33
+
34
+ `POST /auth/email-verification/send`
35
+
36
+ No body typically required (uses `current_user`). Returns a message payload on success.
37
+
38
+ ### Verify
39
+
40
+ `POST /auth/email-verification/verify`
41
+
42
+ **Body (typical):** `{ "code": "string" }`
43
+
44
+ On success, marks the user’s email validated.
45
+
46
+ ## Errors
47
+
48
+ Standard application envelope. Invalid codes and validation failures map through Auth identity error status helpers. See [API reference](api_reference.md) for envelope shape.
49
+
50
+ ## Configuration
51
+
52
+ Email verification options live on CommandTower config (enablement, code length, TTL, grace period). Hosts set secrets and product mail delivery via initializer — [initializing.md](initializing.md).
53
+
54
+ ## Related
55
+
56
+ - [API reference](api_reference.md)
57
+ - [Authentication](authentication.md)
58
+ - [Extending](extending.md)
data/docs/extending.md ADDED
@@ -0,0 +1,105 @@
1
+ # Extending CommandTower
2
+
3
+ How hosts customize and integrate with CommandTower **without forking platform internals**.
4
+
5
+ **New host?** Start with [Host integration](host_integration_guide.md).
6
+
7
+ Layer map: [architecture.md](architecture.md). Install/configure/migrate/doctor: [initializing.md](initializing.md). Testing API: [testing.md](testing.md). HTTP catalog: [api_reference.md](api_reference.md).
8
+
9
+ ## What hosts should extend
10
+
11
+ | Stable Extension Point | Purpose |
12
+ |------------------------|---------|
13
+ | Routes | Additional host endpoints |
14
+ | Controllers | Product-specific HTTP |
15
+ | Workflows | Product orchestration |
16
+ | Services | Product business logic |
17
+ | `Communications::Produce` / `ProduceMany` | Sending messaging |
18
+ | `FactoryBot.modify` | Extend shared factories |
19
+ | Model reopen | Product associations / behavior |
20
+ | Initializers | Configuration |
21
+ | Notification catalogs / channel policy | Host-owned messaging customization |
22
+
23
+ ## Internal platform — do not extend
24
+
25
+ | Internal Platform | Do Not Extend |
26
+ |-------------------|---------------|
27
+ | ApplicationWorkflow | Framework / shared orchestration base |
28
+ | ServiceBase | Shared service framework |
29
+ | Serializers | Platform response shaping |
30
+ | Deserializers | Platform request trust boundary |
31
+ | Messaging execution pipeline | Handoff / execution / accept internals |
32
+ | RequestContext | Framework request context |
33
+ | JWT primitives | Token issue / validate plumbing |
34
+ | Internal framework plumbing | Envelope renderer, workflow base mechanics, etc. |
35
+
36
+ Hosts **use** these via documented public APIs and configuration. Do not subclass, reopen, or fork them as product customization.
37
+
38
+ ## Generators and install flags
39
+
40
+ Full install narrative: [initializing.md](initializing.md).
41
+
42
+ | Surface | Notes |
43
+ |---------|--------|
44
+ | `bin/rails command_tower:install` | Migrations + optional configure |
45
+ | `SKIP_CONFIGURE=1` | Migrations only |
46
+ | `SKIP_MOUNT=1` | Initializer without mount |
47
+ | `FORCE=1` | Overwrite initializer |
48
+ | `rails g command_tower:configure` | `--skip-routes`, `--force` |
49
+
50
+ ## Mounting and configuration
51
+
52
+ Mount `CommandTower::Engine` at the path your product needs. Configuration and secrets belong in the host initializer. Details: [initializing.md](initializing.md).
53
+
54
+ ## Migrations
55
+
56
+ CommandTower authors CT-owned schema; hosts install via engine tasks (`command_tower:install:migrations` / `command_tower:install`) and run `db:migrate`. Do not dual-author CT schema in the host (**AD-SCH-01**). Details: [initializing.md](initializing.md).
57
+
58
+ ## Testing API and factories
59
+
60
+ Primary SST: [testing.md](testing.md).
61
+
62
+ | API | Role |
63
+ |-----|------|
64
+ | `CommandTower::Testing.install!` | Preferred host entry (loads factories) |
65
+ | `CommandTower::Testing.load_factories!` | Factories only / advanced |
66
+ | `CommandTower::Testing.ensure_endpoint_secret!` | Test helper for endpoint ciphertext when env unset |
67
+ | `FactoryBot.modify` | Host extension of shared factories |
68
+
69
+ Shipped factory files (under the gem `spec/factories/`): `user`, `user_secret`, messaging factories, `entity`, `role`.
70
+
71
+ ## RBAC on host controllers
72
+
73
+ Protect host controllers with `authenticate_user!` / `authorize_user!` (or modern Auth boundaries) and RBAC entities. See [authentication_authorization_guide.md](authentication_authorization_guide.md) and [api_reference.md](api_reference.md).
74
+
75
+ ## Model reopen
76
+
77
+ Prefer services/workflows for new behavior. Reopen patterns: [models.md](models.md).
78
+
79
+ ## Produce from product workflows
80
+
81
+ Product business events own **host** workflows that call:
82
+
83
+ - `CommandTower::Services::Messaging::Communications::Produce`
84
+ - `CommandTower::Services::Messaging::Communications::ProduceMany`
85
+
86
+ Do not create one Messaging workflow per message type. Do not call the messaging handoff/execution pipeline directly. Summary: [messaging_integration_guide.md](messaging_integration_guide.md).
87
+
88
+ ## Blank-host checklist
89
+
90
+ 1. Add gem → [initializing.md](initializing.md) quick start (`install`, `db:migrate`, `doctor`)
91
+ 2. Configure secrets and feature flags in the host initializer
92
+ 3. Mount the engine
93
+ 4. Load factories in the host test boot path → [testing.md](testing.md)
94
+ 5. Exercise shared surfaces via engine routes → [controllers.md](controllers.md) / [api_reference.md](api_reference.md)
95
+ 6. Add product routes/controllers/workflows/services only in the **stable extension** columns above
96
+ 7. Keep catalogs, channel policy, and adapter credentials host-owned
97
+
98
+ No DoubleFloor Me (or other product) source is required to use the platform.
99
+
100
+ ## Related
101
+
102
+ - [Architecture](architecture.md)
103
+ - [Controllers](controllers.md)
104
+ - [Sensitive changes](sensitive_routes.md)
105
+ - Workflow guides: [password reset](password_reset_workflow.md), [change password](change_password_workflow.md), [email verification](email_verification_workflow.md)
@@ -0,0 +1,158 @@
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
+ ## Step 3 — Confirm mount path
41
+
42
+ Ensure routes include something like:
43
+
44
+ ```ruby
45
+ mount CommandTower::Engine => "/" # or "/api"
46
+ ```
47
+
48
+ Engine paths below are **relative to that mount**. Route area index: [Controllers](controllers.md).
49
+
50
+ ## Step 4 — Host RBAC (required)
51
+
52
+ AuthorizeRequest **fails closed**. Without host entity mappings, authenticated calls to `/me`, `/auth/session`, inbox, etc. return **403**.
53
+
54
+ The configure generator does **not** create this file.
55
+
56
+ 1. Copy and adapt the dummy host file: [`rails_app/config/rbac_groups.yml`](../rails_app/config/rbac_groups.yml) → host `config/rbac_groups.yml`.
57
+ 2. Keep a host group such as `member` with entities for session, me, profile, inbox, preferences, phone, pushover, email verification.
58
+ 3. Do **not** redefine engine groups that already exist in `default.yml` (`owner`, `admin`).
59
+ 4. Point config at the file if needed:
60
+
61
+ ```ruby
62
+ CommandTower.configure do |c|
63
+ c.authorization.rbac_group_path = Rails.root.join("config/rbac_groups.yml")
64
+ end
65
+ ```
66
+
67
+ (Default path is already `config/rbac_groups.yml`.)
68
+
69
+ More: [Authorization](authorization.md), [Authentication & authorization guide](authentication_authorization_guide.md).
70
+
71
+ ## Step 5 — Roles on users
72
+
73
+ RBAC YAML defines what a role **may** do. Users still need that role assigned.
74
+
75
+ - Specs and the dummy pattern use role name **`member`** for Me/Auth surfaces.
76
+ - Engine register does **not** automatically attach `member`. Hosts must assign roles via product logic, ops (`command_tower:users:create`), or host hooks after account creation.
77
+ - Admin announcements need a role that includes `admin_messaging_announcements` (engine `admin` group, or an equivalent host mapping).
78
+
79
+ ## Step 6 — Enable feature gates you need
80
+
81
+ When a gate is off, the route is **not drawn** → **404**.
82
+
83
+ | Capability | Config |
84
+ |------------|--------|
85
+ | Plain-text login | `config.login.plain_text.enable = true` |
86
+ | Email verification routes | `config.login.plain_text.email_verify = true` |
87
+ | Password reset routes | `config.login.plain_text.password_reset = true` |
88
+ | Email availability | `config.signup_session.email_availability = true` |
89
+ | Username availability | `config.username.realtime_username_check = true` |
90
+
91
+ Full gate list: [API reference — Feature gates](api_reference.md#feature-gates).
92
+
93
+ ## Step 7 — Choose auth client path
94
+
95
+ - **API / mobile:** `Authorization: Bearer <jwt>` (default)
96
+ - **Browser / SPA cookies:** enable `config.jwt.cookie` (+ CSRF as needed) — [Cookie authentication](cookie_authentication_guide.md)
97
+
98
+ Engine HTTP success/error bodies use the application envelope `{ data, meta, errors }`. Host provisional helpers (`authenticate_user!`) can differ — [Authentication](authentication.md).
99
+
100
+ ## Step 8 — Smoke check
101
+
102
+ With gates and RBAC in place (paths relative to your mount):
103
+
104
+ 1. `POST /auth/register` (always drawn) — create a user, then **assign `member`** (Step 5) if not done by host logic.
105
+ 2. `POST /auth/plain-text/login` (if enabled) — receive `data.token`.
106
+ 3. `GET /me` with Bearer token — expect **200** and envelope `data` (account payload).
107
+
108
+ If you get **401**, authn failed. If you get **403**, fix Steps 4–5 before debugging clients.
109
+
110
+ Contracts: [API reference](api_reference.md).
111
+
112
+ ## Step 9 — Messaging (when needed)
113
+
114
+ Host owns:
115
+
116
+ - Notification catalog / types
117
+ - `platform_enabled_channels` / channel policy
118
+ - Adapter credentials (email / SMS / Pushover)
119
+
120
+ Emit from a **host product workflow** via `Communications::Produce` / `ProduceMany` — not by bypassing workflows. See [Messaging](messaging_integration_guide.md) and [Extending](extending.md).
121
+
122
+ Phone/Pushover routes are always drawn; missing product readiness returns **503** capability errors.
123
+
124
+ ## Step 10 — Host tests
125
+
126
+ ```ruby
127
+ require "command_tower/testing"
128
+ CommandTower::Testing.install!
129
+ ```
130
+
131
+ Details: [Testing](testing.md). Prefer `spec/requests/` patterns in the gem as HTTP contract proof.
132
+
133
+ ## Done when
134
+
135
+ - Doctor passes for secrets/migrations
136
+ - Host `rbac_groups.yml` maps Me/Auth entities
137
+ - Users who should use Me surfaces have the host `member` (or equivalent) role
138
+ - Needed feature gates are enabled
139
+ - `GET /me` returns **200** with a Bearer token for a member user
140
+
141
+ ## Common failures
142
+
143
+ | Symptom | Likely cause |
144
+ |---------|----------------|
145
+ | Doctor green, `GET /me` is **403** | Missing host RBAC YAML or user lacks `member` (Steps 4–5) |
146
+ | `POST /auth/plain-text/login` is **404** | `login.plain_text.enable?` off (Step 6) |
147
+ | Password-reset / availability **404** | Matching feature gate off |
148
+ | Phone / Pushover **503** | Capability / adapters not ready (Step 9) |
149
+ | Confused error JSON on host controllers | Provisional `authenticate_user!` vs engine envelope (Step 7) |
150
+
151
+ ## Related
152
+
153
+ - [Initializing](initializing.md)
154
+ - [Extending](extending.md)
155
+ - [API reference](api_reference.md)
156
+ - [Authentication & authorization guide](authentication_authorization_guide.md)
157
+ - [Messaging](messaging_integration_guide.md)
158
+ - [README](../README.md)