seams 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (414) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +335 -0
  3. data/LICENSE +21 -0
  4. data/README.md +104 -0
  5. data/lib/generators/seams/accounts/accounts_generator.rb +272 -0
  6. data/lib/generators/seams/accounts/templates/README.md.tt +219 -0
  7. data/lib/generators/seams/accounts/templates/app/models/account.rb.tt +124 -0
  8. data/lib/generators/seams/accounts/templates/app/models/application_record.rb.tt +7 -0
  9. data/lib/generators/seams/accounts/templates/app/models/current.rb.tt +38 -0
  10. data/lib/generators/seams/accounts/templates/app/models/membership.rb.tt +114 -0
  11. data/lib/generators/seams/accounts/templates/config/routes.rb.tt +8 -0
  12. data/lib/generators/seams/accounts/templates/db/migrate/create_accounts.rb.tt +29 -0
  13. data/lib/generators/seams/accounts/templates/db/migrate/create_accounts_memberships.rb.tt +49 -0
  14. data/lib/generators/seams/accounts/templates/lib/accounts.rb.tt +21 -0
  15. data/lib/generators/seams/accounts/templates/lib/concerns/account_scoped.rb.tt +97 -0
  16. data/lib/generators/seams/accounts/templates/lib/concerns/authorization.rb.tt +105 -0
  17. data/lib/generators/seams/accounts/templates/lib/configuration.rb.tt +26 -0
  18. data/lib/generators/seams/accounts/templates/lib/engine.rb.tt +55 -0
  19. data/lib/generators/seams/accounts/templates/spec/factories/accounts.rb.tt +49 -0
  20. data/lib/generators/seams/accounts/templates/spec/models/accounts/account_spec.rb.tt +64 -0
  21. data/lib/generators/seams/accounts/templates/spec/models/accounts/membership_spec.rb.tt +99 -0
  22. data/lib/generators/seams/accounts/templates/spec/runtime/accounts_boot_spec.rb.tt +181 -0
  23. data/lib/generators/seams/admin/admin_generator.rb +852 -0
  24. data/lib/generators/seams/admin/templates/README.md.tt +266 -0
  25. data/lib/generators/seams/admin/templates/app/controllers/admin/accounts_controller.rb.tt +16 -0
  26. data/lib/generators/seams/admin/templates/app/controllers/admin/accounts_memberships_controller.rb.tt +16 -0
  27. data/lib/generators/seams/admin/templates/app/controllers/admin/application_controller.rb.tt +282 -0
  28. data/lib/generators/seams/admin/templates/app/controllers/admin/identities_controller.rb.tt +26 -0
  29. data/lib/generators/seams/admin/templates/app/controllers/admin/invitations_controller.rb.tt +14 -0
  30. data/lib/generators/seams/admin/templates/app/controllers/admin/invoices_controller.rb.tt +14 -0
  31. data/lib/generators/seams/admin/templates/app/controllers/admin/lifetime_passes_controller.rb.tt +14 -0
  32. data/lib/generators/seams/admin/templates/app/controllers/admin/notification_preferences_controller.rb.tt +15 -0
  33. data/lib/generators/seams/admin/templates/app/controllers/admin/notifications_controller.rb.tt +18 -0
  34. data/lib/generators/seams/admin/templates/app/controllers/admin/plans_controller.rb.tt +14 -0
  35. data/lib/generators/seams/admin/templates/app/controllers/admin/subscriptions_controller.rb.tt +14 -0
  36. data/lib/generators/seams/admin/templates/app/controllers/admin/teams_controller.rb.tt +14 -0
  37. data/lib/generators/seams/admin/templates/app/controllers/admin/teams_memberships_controller.rb.tt +16 -0
  38. data/lib/generators/seams/admin/templates/app/dashboards/admin/account_dashboard.rb.tt +50 -0
  39. data/lib/generators/seams/admin/templates/app/dashboards/admin/accounts_membership_dashboard.rb.tt +58 -0
  40. data/lib/generators/seams/admin/templates/app/dashboards/admin/identity_dashboard.rb.tt +48 -0
  41. data/lib/generators/seams/admin/templates/app/dashboards/admin/invitation_dashboard.rb.tt +51 -0
  42. data/lib/generators/seams/admin/templates/app/dashboards/admin/invoice_dashboard.rb.tt +67 -0
  43. data/lib/generators/seams/admin/templates/app/dashboards/admin/lifetime_pass_dashboard.rb.tt +65 -0
  44. data/lib/generators/seams/admin/templates/app/dashboards/admin/notification_dashboard.rb.tt +58 -0
  45. data/lib/generators/seams/admin/templates/app/dashboards/admin/notification_preference_dashboard.rb.tt +43 -0
  46. data/lib/generators/seams/admin/templates/app/dashboards/admin/plan_dashboard.rb.tt +72 -0
  47. data/lib/generators/seams/admin/templates/app/dashboards/admin/subscription_dashboard.rb.tt +59 -0
  48. data/lib/generators/seams/admin/templates/app/dashboards/admin/team_dashboard.rb.tt +39 -0
  49. data/lib/generators/seams/admin/templates/app/dashboards/admin/teams_membership_dashboard.rb.tt +43 -0
  50. data/lib/generators/seams/admin/templates/app/policies/admin/platform/account_policy.rb.tt +10 -0
  51. data/lib/generators/seams/admin/templates/app/policies/admin/platform/accounts_membership_policy.rb.tt +10 -0
  52. data/lib/generators/seams/admin/templates/app/policies/admin/platform/application_policy.rb.tt +85 -0
  53. data/lib/generators/seams/admin/templates/app/policies/admin/platform/identity_policy.rb.tt +18 -0
  54. data/lib/generators/seams/admin/templates/app/policies/admin/platform/invitation_policy.rb.tt +9 -0
  55. data/lib/generators/seams/admin/templates/app/policies/admin/platform/invoice_policy.rb.tt +9 -0
  56. data/lib/generators/seams/admin/templates/app/policies/admin/platform/lifetime_pass_policy.rb.tt +9 -0
  57. data/lib/generators/seams/admin/templates/app/policies/admin/platform/notification_policy.rb.tt +9 -0
  58. data/lib/generators/seams/admin/templates/app/policies/admin/platform/notification_preference_policy.rb.tt +9 -0
  59. data/lib/generators/seams/admin/templates/app/policies/admin/platform/plan_policy.rb.tt +11 -0
  60. data/lib/generators/seams/admin/templates/app/policies/admin/platform/subscription_policy.rb.tt +9 -0
  61. data/lib/generators/seams/admin/templates/app/policies/admin/platform/team_policy.rb.tt +9 -0
  62. data/lib/generators/seams/admin/templates/app/policies/admin/platform/teams_membership_policy.rb.tt +9 -0
  63. data/lib/generators/seams/admin/templates/app/policies/admin/tenant/account_policy.rb.tt +33 -0
  64. data/lib/generators/seams/admin/templates/app/policies/admin/tenant/accounts_membership_policy.rb.tt +24 -0
  65. data/lib/generators/seams/admin/templates/app/policies/admin/tenant/application_policy.rb.tt +169 -0
  66. data/lib/generators/seams/admin/templates/app/policies/admin/tenant/identity_policy.rb.tt +67 -0
  67. data/lib/generators/seams/admin/templates/app/policies/admin/tenant/invitation_policy.rb.tt +24 -0
  68. data/lib/generators/seams/admin/templates/app/policies/admin/tenant/invoice_policy.rb.tt +21 -0
  69. data/lib/generators/seams/admin/templates/app/policies/admin/tenant/lifetime_pass_policy.rb.tt +21 -0
  70. data/lib/generators/seams/admin/templates/app/policies/admin/tenant/notification_policy.rb.tt +25 -0
  71. data/lib/generators/seams/admin/templates/app/policies/admin/tenant/notification_preference_policy.rb.tt +23 -0
  72. data/lib/generators/seams/admin/templates/app/policies/admin/tenant/plan_policy.rb.tt +47 -0
  73. data/lib/generators/seams/admin/templates/app/policies/admin/tenant/subscription_policy.rb.tt +22 -0
  74. data/lib/generators/seams/admin/templates/app/policies/admin/tenant/team_policy.rb.tt +28 -0
  75. data/lib/generators/seams/admin/templates/app/policies/admin/tenant/teams_membership_policy.rb.tt +24 -0
  76. data/lib/generators/seams/admin/templates/config/routes.rb.tt +38 -0
  77. data/lib/generators/seams/admin/templates/lib/admin.rb.tt +36 -0
  78. data/lib/generators/seams/admin/templates/lib/concerns/authenticator.rb.tt +66 -0
  79. data/lib/generators/seams/admin/templates/lib/configuration.rb.tt +90 -0
  80. data/lib/generators/seams/admin/templates/lib/context.rb.tt +44 -0
  81. data/lib/generators/seams/admin/templates/lib/engine.rb.tt +68 -0
  82. data/lib/generators/seams/admin/templates/spec/factories/admin.rb.tt +10 -0
  83. data/lib/generators/seams/admin/templates/spec/runtime/admin_boot_spec.rb.tt +604 -0
  84. data/lib/generators/seams/auth/add_oauth_provider/add_oauth_provider_generator.rb +157 -0
  85. data/lib/generators/seams/auth/add_oauth_provider/templates/adapter.rb.tt +95 -0
  86. data/lib/generators/seams/auth/add_oauth_provider/templates/adapter_spec.rb.tt +58 -0
  87. data/lib/generators/seams/auth/auth_generator.rb +311 -0
  88. data/lib/generators/seams/auth/templates/README.md.tt +289 -0
  89. data/lib/generators/seams/auth/templates/app/controllers/oauth/callbacks_controller.rb.tt +80 -0
  90. data/lib/generators/seams/auth/templates/app/controllers/password_resets_controller.rb.tt +44 -0
  91. data/lib/generators/seams/auth/templates/app/controllers/registrations_controller.rb.tt +34 -0
  92. data/lib/generators/seams/auth/templates/app/controllers/sessions_controller.rb.tt +49 -0
  93. data/lib/generators/seams/auth/templates/app/jobs/application_job.rb.tt +7 -0
  94. data/lib/generators/seams/auth/templates/app/jobs/cleanup_expired_sessions_job.rb.tt +30 -0
  95. data/lib/generators/seams/auth/templates/app/mailers/passwords_mailer.rb.tt +15 -0
  96. data/lib/generators/seams/auth/templates/app/models/api_token.rb.tt +62 -0
  97. data/lib/generators/seams/auth/templates/app/models/application_record.rb.tt +7 -0
  98. data/lib/generators/seams/auth/templates/app/models/current.rb.tt +15 -0
  99. data/lib/generators/seams/auth/templates/app/models/identity.rb.tt +74 -0
  100. data/lib/generators/seams/auth/templates/app/models/oauth/provider.rb.tt +48 -0
  101. data/lib/generators/seams/auth/templates/app/models/session.rb.tt +28 -0
  102. data/lib/generators/seams/auth/templates/app/services/authenticate_identity.rb.tt +31 -0
  103. data/lib/generators/seams/auth/templates/app/services/generate_api_token.rb.tt +35 -0
  104. data/lib/generators/seams/auth/templates/app/services/oauth/authenticator.rb.tt +94 -0
  105. data/lib/generators/seams/auth/templates/app/services/register_identity.rb.tt +57 -0
  106. data/lib/generators/seams/auth/templates/app/services/reset_password.rb.tt +41 -0
  107. data/lib/generators/seams/auth/templates/app/services/revoke_api_token.rb.tt +38 -0
  108. data/lib/generators/seams/auth/templates/app/views/password_resets/edit.html.erb.tt +12 -0
  109. data/lib/generators/seams/auth/templates/app/views/password_resets/new.html.erb.tt +11 -0
  110. data/lib/generators/seams/auth/templates/app/views/passwords_mailer/reset_email.html.erb.tt +7 -0
  111. data/lib/generators/seams/auth/templates/app/views/registrations/new.html.erb.tt +26 -0
  112. data/lib/generators/seams/auth/templates/app/views/sessions/_oauth_buttons.html.erb.tt +18 -0
  113. data/lib/generators/seams/auth/templates/app/views/sessions/new.html.erb.tt +17 -0
  114. data/lib/generators/seams/auth/templates/config/routes.rb.tt +21 -0
  115. data/lib/generators/seams/auth/templates/db/migrate/create_auth_api_tokens.rb.tt +26 -0
  116. data/lib/generators/seams/auth/templates/db/migrate/create_auth_identities.rb.tt +29 -0
  117. data/lib/generators/seams/auth/templates/db/migrate/create_auth_oauth_providers.rb.tt +35 -0
  118. data/lib/generators/seams/auth/templates/db/migrate/create_auth_sessions.rb.tt +19 -0
  119. data/lib/generators/seams/auth/templates/lib/auth.rb.tt +39 -0
  120. data/lib/generators/seams/auth/templates/lib/concerns/api_authenticatable.rb.tt +58 -0
  121. data/lib/generators/seams/auth/templates/lib/concerns/authenticatable.rb.tt +32 -0
  122. data/lib/generators/seams/auth/templates/lib/concerns/authentication.rb.tt +60 -0
  123. data/lib/generators/seams/auth/templates/lib/configuration.rb.tt +45 -0
  124. data/lib/generators/seams/auth/templates/lib/engine.rb.tt +46 -0
  125. data/lib/generators/seams/auth/templates/lib/oauth/abstract.rb.tt +87 -0
  126. data/lib/generators/seams/auth/templates/lib/oauth/github.rb.tt +112 -0
  127. data/lib/generators/seams/auth/templates/lib/oauth/google.rb.tt +78 -0
  128. data/lib/generators/seams/auth/templates/lib/tasks/auth_pii.rake.tt +68 -0
  129. data/lib/generators/seams/auth/templates/spec/factories/auth.rb.tt +38 -0
  130. data/lib/generators/seams/auth/templates/spec/mailers/passwords_mailer_spec.rb.tt +37 -0
  131. data/lib/generators/seams/auth/templates/spec/models/api_token_spec.rb.tt +84 -0
  132. data/lib/generators/seams/auth/templates/spec/models/identity_spec.rb.tt +56 -0
  133. data/lib/generators/seams/auth/templates/spec/models/oauth/provider_spec.rb.tt +64 -0
  134. data/lib/generators/seams/auth/templates/spec/models/session_spec.rb.tt +34 -0
  135. data/lib/generators/seams/auth/templates/spec/runtime/boot_spec.rb.tt +30 -0
  136. data/lib/generators/seams/auth/templates/spec/runtime/event_payload_spec.rb.tt +29 -0
  137. data/lib/generators/seams/auth/templates/spec/runtime/login_flow_spec.rb.tt +45 -0
  138. data/lib/generators/seams/billing/billing_generator.rb +476 -0
  139. data/lib/generators/seams/billing/templates/README.md.tt +355 -0
  140. data/lib/generators/seams/billing/templates/app/controllers/admin/lifetime_passes_controller.rb.tt +84 -0
  141. data/lib/generators/seams/billing/templates/app/controllers/checkout_controller.rb.tt +92 -0
  142. data/lib/generators/seams/billing/templates/app/controllers/invoices_controller.rb.tt +63 -0
  143. data/lib/generators/seams/billing/templates/app/controllers/plans_controller.rb.tt +14 -0
  144. data/lib/generators/seams/billing/templates/app/controllers/portal_controller.rb.tt +45 -0
  145. data/lib/generators/seams/billing/templates/app/controllers/subscriptions_controller.rb.tt +119 -0
  146. data/lib/generators/seams/billing/templates/app/controllers/webhooks_controller.rb.tt +98 -0
  147. data/lib/generators/seams/billing/templates/app/helpers/currency_helper.rb.tt +44 -0
  148. data/lib/generators/seams/billing/templates/app/jobs/application_job.rb.tt +6 -0
  149. data/lib/generators/seams/billing/templates/app/jobs/cancel_subscription_job.rb.tt +39 -0
  150. data/lib/generators/seams/billing/templates/app/jobs/start_subscription_job.rb.tt +32 -0
  151. data/lib/generators/seams/billing/templates/app/jobs/webhooks/process_event_job.rb.tt +37 -0
  152. data/lib/generators/seams/billing/templates/app/models/application_record.rb.tt +7 -0
  153. data/lib/generators/seams/billing/templates/app/models/invoice.rb.tt +35 -0
  154. data/lib/generators/seams/billing/templates/app/models/lifetime_pass.rb.tt +60 -0
  155. data/lib/generators/seams/billing/templates/app/models/plan.rb.tt +95 -0
  156. data/lib/generators/seams/billing/templates/app/models/subscription.rb.tt +31 -0
  157. data/lib/generators/seams/billing/templates/app/models/webhook_event.rb.tt +13 -0
  158. data/lib/generators/seams/billing/templates/app/services/checkout_session_service.rb.tt +25 -0
  159. data/lib/generators/seams/billing/templates/app/services/customers/find_or_create_service.rb.tt +73 -0
  160. data/lib/generators/seams/billing/templates/app/services/invoices/sync_service.rb.tt +50 -0
  161. data/lib/generators/seams/billing/templates/app/services/lifetime/create_lifetime_session_service.rb.tt +82 -0
  162. data/lib/generators/seams/billing/templates/app/services/lifetime/create_pass_from_checkout_service.rb.tt +88 -0
  163. data/lib/generators/seams/billing/templates/app/services/lifetime/grant_pass_service.rb.tt +80 -0
  164. data/lib/generators/seams/billing/templates/app/services/lifetime/revoke_pass_service.rb.tt +59 -0
  165. data/lib/generators/seams/billing/templates/app/services/portal_session_service.rb.tt +23 -0
  166. data/lib/generators/seams/billing/templates/app/services/service_result.rb.tt +38 -0
  167. data/lib/generators/seams/billing/templates/app/services/stripe_service.rb.tt +67 -0
  168. data/lib/generators/seams/billing/templates/app/services/subscriptions/cancel_service.rb.tt +42 -0
  169. data/lib/generators/seams/billing/templates/app/services/subscriptions/change_plan_service.rb.tt +48 -0
  170. data/lib/generators/seams/billing/templates/app/services/subscriptions/reactivate_service.rb.tt +28 -0
  171. data/lib/generators/seams/billing/templates/app/services/webhooks/event_router.rb.tt +54 -0
  172. data/lib/generators/seams/billing/templates/app/services/webhooks/handler.rb.tt +93 -0
  173. data/lib/generators/seams/billing/templates/app/services/webhooks/handlers/charge_refunded_handler.rb.tt +18 -0
  174. data/lib/generators/seams/billing/templates/app/services/webhooks/handlers/checkout_session_completed_handler.rb.tt +58 -0
  175. data/lib/generators/seams/billing/templates/app/services/webhooks/handlers/invoice_created_handler.rb.tt +16 -0
  176. data/lib/generators/seams/billing/templates/app/services/webhooks/handlers/invoice_finalized_handler.rb.tt +14 -0
  177. data/lib/generators/seams/billing/templates/app/services/webhooks/handlers/invoice_handler_base.rb.tt +80 -0
  178. data/lib/generators/seams/billing/templates/app/services/webhooks/handlers/invoice_paid_handler.rb.tt +12 -0
  179. data/lib/generators/seams/billing/templates/app/services/webhooks/handlers/invoice_payment_failed_handler.rb.tt +12 -0
  180. data/lib/generators/seams/billing/templates/app/services/webhooks/handlers/invoice_voided_handler.rb.tt +12 -0
  181. data/lib/generators/seams/billing/templates/app/services/webhooks/handlers/payment_failed_handler.rb.tt +15 -0
  182. data/lib/generators/seams/billing/templates/app/services/webhooks/handlers/payment_succeeded_handler.rb.tt +19 -0
  183. data/lib/generators/seams/billing/templates/app/services/webhooks/handlers/subscription_created_handler.rb.tt +11 -0
  184. data/lib/generators/seams/billing/templates/app/services/webhooks/handlers/subscription_deleted_handler.rb.tt +15 -0
  185. data/lib/generators/seams/billing/templates/app/services/webhooks/handlers/subscription_handler_base.rb.tt +92 -0
  186. data/lib/generators/seams/billing/templates/app/services/webhooks/handlers/subscription_trial_will_end_handler.rb.tt +15 -0
  187. data/lib/generators/seams/billing/templates/app/services/webhooks/handlers/subscription_updated_handler.rb.tt +11 -0
  188. data/lib/generators/seams/billing/templates/app/views/admin/lifetime_passes/index.html.erb.tt +36 -0
  189. data/lib/generators/seams/billing/templates/app/views/admin/lifetime_passes/new.html.erb.tt +37 -0
  190. data/lib/generators/seams/billing/templates/app/views/checkout/success.html.erb.tt +5 -0
  191. data/lib/generators/seams/billing/templates/app/views/invoices/index.html.erb.tt +22 -0
  192. data/lib/generators/seams/billing/templates/app/views/invoices/show.html.erb.tt +14 -0
  193. data/lib/generators/seams/billing/templates/app/views/plans/index.html.erb.tt +51 -0
  194. data/lib/generators/seams/billing/templates/app/views/subscriptions/index.html.erb.tt +16 -0
  195. data/lib/generators/seams/billing/templates/app/views/subscriptions/show.html.erb.tt +25 -0
  196. data/lib/generators/seams/billing/templates/config/routes.rb.tt +39 -0
  197. data/lib/generators/seams/billing/templates/db/migrate/create_billing_invoices.rb.tt +32 -0
  198. data/lib/generators/seams/billing/templates/db/migrate/create_billing_lifetime_passes.rb.tt +43 -0
  199. data/lib/generators/seams/billing/templates/db/migrate/create_billing_plans.rb.tt +31 -0
  200. data/lib/generators/seams/billing/templates/db/migrate/create_billing_subscriptions.rb.tt +33 -0
  201. data/lib/generators/seams/billing/templates/db/migrate/create_billing_webhook_events.rb.tt +24 -0
  202. data/lib/generators/seams/billing/templates/lib/billing.rb.tt +34 -0
  203. data/lib/generators/seams/billing/templates/lib/concerns/billable.rb.tt +100 -0
  204. data/lib/generators/seams/billing/templates/lib/configuration.rb.tt +52 -0
  205. data/lib/generators/seams/billing/templates/lib/engine.rb.tt +72 -0
  206. data/lib/generators/seams/billing/templates/lib/gateways/abstract.rb.tt +65 -0
  207. data/lib/generators/seams/billing/templates/lib/gateways/adyen.rb.tt +16 -0
  208. data/lib/generators/seams/billing/templates/lib/gateways/paddle.rb.tt +22 -0
  209. data/lib/generators/seams/billing/templates/lib/gateways/stripe.rb.tt +155 -0
  210. data/lib/generators/seams/billing/templates/lib/stripe/client.rb.tt +101 -0
  211. data/lib/generators/seams/billing/templates/lib/stripe/webhook_signature.rb.tt +43 -0
  212. data/lib/generators/seams/billing/templates/lib/tasks/billing_check.rake.tt +34 -0
  213. data/lib/generators/seams/billing/templates/spec/factories/billing.rb.tt +65 -0
  214. data/lib/generators/seams/billing/templates/spec/fixtures/stripe/charge_refunded.json.tt +19 -0
  215. data/lib/generators/seams/billing/templates/spec/fixtures/stripe/checkout_session_completed.json.tt +17 -0
  216. data/lib/generators/seams/billing/templates/spec/fixtures/stripe/customer_subscription_created.json.tt +25 -0
  217. data/lib/generators/seams/billing/templates/spec/fixtures/stripe/customer_subscription_deleted.json.tt +17 -0
  218. data/lib/generators/seams/billing/templates/spec/fixtures/stripe/customer_subscription_trial_will_end.json.tt +17 -0
  219. data/lib/generators/seams/billing/templates/spec/fixtures/stripe/customer_subscription_updated.json.tt +28 -0
  220. data/lib/generators/seams/billing/templates/spec/fixtures/stripe/invoice_created.json.tt +18 -0
  221. data/lib/generators/seams/billing/templates/spec/fixtures/stripe/invoice_finalized.json.tt +18 -0
  222. data/lib/generators/seams/billing/templates/spec/fixtures/stripe/invoice_paid.json.tt +19 -0
  223. data/lib/generators/seams/billing/templates/spec/fixtures/stripe/invoice_payment_failed.json.tt +20 -0
  224. data/lib/generators/seams/billing/templates/spec/fixtures/stripe/invoice_voided.json.tt +18 -0
  225. data/lib/generators/seams/billing/templates/spec/fixtures/stripe/payment_intent_payment_failed.json.tt +21 -0
  226. data/lib/generators/seams/billing/templates/spec/fixtures/stripe/payment_intent_succeeded.json.tt +17 -0
  227. data/lib/generators/seams/billing/templates/spec/gateways/contract_spec.rb.tt +11 -0
  228. data/lib/generators/seams/billing/templates/spec/gateways/stripe_spec.rb.tt +53 -0
  229. data/lib/generators/seams/billing/templates/spec/models/plan_spec.rb.tt +81 -0
  230. data/lib/generators/seams/billing/templates/spec/models/subscription_spec.rb.tt +43 -0
  231. data/lib/generators/seams/billing/templates/spec/runtime/boot_spec.rb.tt +38 -0
  232. data/lib/generators/seams/billing/templates/spec/runtime/webhook_handlers_spec.rb.tt +382 -0
  233. data/lib/generators/seams/billing/templates/spec/support/shared_examples/a_billing_gateway.rb.tt +100 -0
  234. data/lib/generators/seams/billing/templates/spec/support/stripe_helpers.rb.tt +59 -0
  235. data/lib/generators/seams/core/core_generator.rb +191 -0
  236. data/lib/generators/seams/core/templates/README.md.tt +45 -0
  237. data/lib/generators/seams/core/templates/app/controllers/concerns/has_current_attributes.rb.tt +71 -0
  238. data/lib/generators/seams/core/templates/app/models/application_record.rb.tt +7 -0
  239. data/lib/generators/seams/core/templates/app/models/audit_log.rb.tt +19 -0
  240. data/lib/generators/seams/core/templates/app/models/concerns/auditable.rb.tt +64 -0
  241. data/lib/generators/seams/core/templates/app/models/concerns/sluggable.rb.tt +53 -0
  242. data/lib/generators/seams/core/templates/app/models/concerns/soft_deletable.rb.tt +37 -0
  243. data/lib/generators/seams/core/templates/app/models/concerns/tenant_scoped.rb.tt +39 -0
  244. data/lib/generators/seams/core/templates/app/models/current.rb.tt +16 -0
  245. data/lib/generators/seams/core/templates/app/services/event_publisher.rb.tt +23 -0
  246. data/lib/generators/seams/core/templates/app/validators/email_format_validator.rb.tt +21 -0
  247. data/lib/generators/seams/core/templates/db/migrate/create_core_audit_logs.rb.tt +29 -0
  248. data/lib/generators/seams/core/templates/lib/core.rb.tt +8 -0
  249. data/lib/generators/seams/core/templates/lib/engine.rb.tt +28 -0
  250. data/lib/generators/seams/core/templates/spec/concerns/auditable_spec.rb.tt +39 -0
  251. data/lib/generators/seams/core/templates/spec/concerns/sluggable_spec.rb.tt +29 -0
  252. data/lib/generators/seams/core/templates/spec/models/audit_log_spec.rb.tt +22 -0
  253. data/lib/generators/seams/core/templates/spec/runtime/boot_spec.rb.tt +25 -0
  254. data/lib/generators/seams/core/templates/spec/validators/email_format_validator_spec.rb.tt +29 -0
  255. data/lib/generators/seams/engine/engine_generator.rb +165 -0
  256. data/lib/generators/seams/engine/templates/Gemfile.tt +19 -0
  257. data/lib/generators/seams/engine/templates/LICENSE.tt +21 -0
  258. data/lib/generators/seams/engine/templates/README.md.tt +40 -0
  259. data/lib/generators/seams/engine/templates/Rakefile.tt +14 -0
  260. data/lib/generators/seams/engine/templates/app/application_controller.rb.tt +6 -0
  261. data/lib/generators/seams/engine/templates/app/application_record.rb.tt +16 -0
  262. data/lib/generators/seams/engine/templates/config/locales/en.yml.tt +14 -0
  263. data/lib/generators/seams/engine/templates/config/routes.rb.tt +4 -0
  264. data/lib/generators/seams/engine/templates/gemspec.tt +20 -0
  265. data/lib/generators/seams/engine/templates/host_initializer.rb.tt +13 -0
  266. data/lib/generators/seams/engine/templates/lib/engine.rb.tt +27 -0
  267. data/lib/generators/seams/engine/templates/lib/root.rb.tt +7 -0
  268. data/lib/generators/seams/engine/templates/lib/version.rb.tt +5 -0
  269. data/lib/generators/seams/engine/templates/rubocop.yml.tt +55 -0
  270. data/lib/generators/seams/engine/templates/spec/example_spec.rb.tt +16 -0
  271. data/lib/generators/seams/engine/templates/spec/spec_helper.rb.tt +23 -0
  272. data/lib/generators/seams/install/install_generator.rb +211 -0
  273. data/lib/generators/seams/install/templates/Dockerfile.tt +52 -0
  274. data/lib/generators/seams/install/templates/Procfile.tt +14 -0
  275. data/lib/generators/seams/install/templates/bin_seams.tt +107 -0
  276. data/lib/generators/seams/install/templates/ci.yml.tt +123 -0
  277. data/lib/generators/seams/install/templates/deploy.yml.tt +63 -0
  278. data/lib/generators/seams/install/templates/doc/ARCHITECTURE.md.tt +86 -0
  279. data/lib/generators/seams/install/templates/docker-entrypoint.tt +27 -0
  280. data/lib/generators/seams/install/templates/rubocop.yml.tt +33 -0
  281. data/lib/generators/seams/install/templates/ruby-version.tt +1 -0
  282. data/lib/generators/seams/install/templates/script/collate_coverage.rb.tt +33 -0
  283. data/lib/generators/seams/install/templates/script/run_affected_tests.sh.tt +64 -0
  284. data/lib/generators/seams/install/templates/seams.rake.tt +65 -0
  285. data/lib/generators/seams/install/templates/seams.rb.tt +9 -0
  286. data/lib/generators/seams/install/templates/seams_engines.rb.tt +15 -0
  287. data/lib/generators/seams/notifications/notifications_generator.rb +395 -0
  288. data/lib/generators/seams/notifications/templates/README.md.tt +269 -0
  289. data/lib/generators/seams/notifications/templates/app/channels/notification_channel.rb.tt +36 -0
  290. data/lib/generators/seams/notifications/templates/app/controllers/notifications_controller.rb.tt +58 -0
  291. data/lib/generators/seams/notifications/templates/app/controllers/preferences_controller.rb.tt +54 -0
  292. data/lib/generators/seams/notifications/templates/app/javascript/controllers/notification_bell_controller.js.tt +34 -0
  293. data/lib/generators/seams/notifications/templates/app/jobs/application_job.rb.tt +6 -0
  294. data/lib/generators/seams/notifications/templates/app/jobs/create_notification_job.rb.tt +31 -0
  295. data/lib/generators/seams/notifications/templates/app/jobs/send_due_notifications_job.rb.tt +22 -0
  296. data/lib/generators/seams/notifications/templates/app/jobs/send_notification_job.rb.tt +13 -0
  297. data/lib/generators/seams/notifications/templates/app/mailers/application_mailer.rb.tt +12 -0
  298. data/lib/generators/seams/notifications/templates/app/mailers/notification_mailer.rb.tt +23 -0
  299. data/lib/generators/seams/notifications/templates/app/models/application_record.rb.tt +7 -0
  300. data/lib/generators/seams/notifications/templates/app/models/delivery.rb.tt +13 -0
  301. data/lib/generators/seams/notifications/templates/app/models/notification.rb.tt +218 -0
  302. data/lib/generators/seams/notifications/templates/app/models/notification_preference.rb.tt +29 -0
  303. data/lib/generators/seams/notifications/templates/app/models/strategies/email.rb.tt +38 -0
  304. data/lib/generators/seams/notifications/templates/app/models/strategies/in_app.rb.tt +26 -0
  305. data/lib/generators/seams/notifications/templates/app/models/strategies/sms.rb.tt +33 -0
  306. data/lib/generators/seams/notifications/templates/app/subscribers/auth_subscriber.rb.tt +71 -0
  307. data/lib/generators/seams/notifications/templates/app/subscribers/billing_subscriber.rb.tt +127 -0
  308. data/lib/generators/seams/notifications/templates/app/views/layouts/notifications/mailer.html.erb.tt +22 -0
  309. data/lib/generators/seams/notifications/templates/app/views/layouts/notifications/mailer.text.erb.tt +4 -0
  310. data/lib/generators/seams/notifications/templates/app/views/notifications/_bell.html.erb.tt +15 -0
  311. data/lib/generators/seams/notifications/templates/app/views/notifications/index.html.erb.tt +15 -0
  312. data/lib/generators/seams/notifications/templates/app/views/templates/billing/invoice_failed.html.erb.tt +4 -0
  313. data/lib/generators/seams/notifications/templates/app/views/templates/billing/invoice_failed.text.erb.tt +4 -0
  314. data/lib/generators/seams/notifications/templates/app/views/templates/billing/invoice_paid.html.erb.tt +3 -0
  315. data/lib/generators/seams/notifications/templates/app/views/templates/billing/invoice_paid.text.erb.tt +3 -0
  316. data/lib/generators/seams/notifications/templates/app/views/templates/billing/lifetime_granted.html.erb.tt +5 -0
  317. data/lib/generators/seams/notifications/templates/app/views/templates/billing/lifetime_granted.text.erb.tt +5 -0
  318. data/lib/generators/seams/notifications/templates/app/views/templates/billing/lifetime_purchased.html.erb.tt +5 -0
  319. data/lib/generators/seams/notifications/templates/app/views/templates/billing/lifetime_purchased.text.erb.tt +5 -0
  320. data/lib/generators/seams/notifications/templates/app/views/templates/billing/subscription_canceled.html.erb.tt +4 -0
  321. data/lib/generators/seams/notifications/templates/app/views/templates/billing/subscription_canceled.text.erb.tt +4 -0
  322. data/lib/generators/seams/notifications/templates/app/views/templates/billing/subscription_started.html.erb.tt +4 -0
  323. data/lib/generators/seams/notifications/templates/app/views/templates/billing/subscription_started.text.erb.tt +5 -0
  324. data/lib/generators/seams/notifications/templates/app/views/templates/billing/subscription_updated.html.erb.tt +3 -0
  325. data/lib/generators/seams/notifications/templates/app/views/templates/billing/subscription_updated.text.erb.tt +3 -0
  326. data/lib/generators/seams/notifications/templates/app/views/templates/default.html.erb.tt +10 -0
  327. data/lib/generators/seams/notifications/templates/app/views/templates/default.text.erb.tt +11 -0
  328. data/lib/generators/seams/notifications/templates/app/views/templates/welcome.html.erb.tt +6 -0
  329. data/lib/generators/seams/notifications/templates/app/views/templates/welcome.text.erb.tt +6 -0
  330. data/lib/generators/seams/notifications/templates/config/initializers/notifications.rb.tt +58 -0
  331. data/lib/generators/seams/notifications/templates/config/routes.rb.tt +17 -0
  332. data/lib/generators/seams/notifications/templates/db/migrate/create_notification_deliveries.rb.tt +16 -0
  333. data/lib/generators/seams/notifications/templates/db/migrate/create_notification_preferences.rb.tt +25 -0
  334. data/lib/generators/seams/notifications/templates/db/migrate/create_notifications.rb.tt +35 -0
  335. data/lib/generators/seams/notifications/templates/lib/adapters/abstract.rb.tt +20 -0
  336. data/lib/generators/seams/notifications/templates/lib/adapters/action_mailer.rb.tt +17 -0
  337. data/lib/generators/seams/notifications/templates/lib/adapters/null_sms.rb.tt +23 -0
  338. data/lib/generators/seams/notifications/templates/lib/concerns/notifiable.rb.tt +135 -0
  339. data/lib/generators/seams/notifications/templates/lib/configuration.rb.tt +24 -0
  340. data/lib/generators/seams/notifications/templates/lib/engine.rb.tt +35 -0
  341. data/lib/generators/seams/notifications/templates/lib/notifications.rb.tt +75 -0
  342. data/lib/generators/seams/notifications/templates/lib/type_registry.rb.tt +74 -0
  343. data/lib/generators/seams/notifications/templates/spec/factories/notifications.rb.tt +53 -0
  344. data/lib/generators/seams/notifications/templates/spec/models/delivery_spec.rb.tt +28 -0
  345. data/lib/generators/seams/notifications/templates/spec/models/notification_preference_spec.rb.tt +46 -0
  346. data/lib/generators/seams/notifications/templates/spec/models/notification_spec.rb.tt +60 -0
  347. data/lib/generators/seams/notifications/templates/spec/runtime/bell_broadcast_spec.rb.tt +59 -0
  348. data/lib/generators/seams/notifications/templates/spec/runtime/billing_subscriber_skip_spec.rb.tt +87 -0
  349. data/lib/generators/seams/notifications/templates/spec/runtime/boot_spec.rb.tt +39 -0
  350. data/lib/generators/seams/notifications/templates/spec/runtime/schedule_round_trip_spec.rb.tt +55 -0
  351. data/lib/generators/seams/remove/remove_generator.rb +259 -0
  352. data/lib/generators/seams/teams/teams_generator.rb +298 -0
  353. data/lib/generators/seams/teams/templates/README.md.tt +88 -0
  354. data/lib/generators/seams/teams/templates/app/controllers/invitations_controller.rb.tt +102 -0
  355. data/lib/generators/seams/teams/templates/app/controllers/memberships_controller.rb.tt +54 -0
  356. data/lib/generators/seams/teams/templates/app/controllers/teams_controller.rb.tt +68 -0
  357. data/lib/generators/seams/teams/templates/app/jobs/application_job.rb.tt +6 -0
  358. data/lib/generators/seams/teams/templates/app/mailers/invitation_mailer.rb.tt +34 -0
  359. data/lib/generators/seams/teams/templates/app/models/application_record.rb.tt +7 -0
  360. data/lib/generators/seams/teams/templates/app/models/current.rb.tt +30 -0
  361. data/lib/generators/seams/teams/templates/app/models/invitation.rb.tt +36 -0
  362. data/lib/generators/seams/teams/templates/app/models/membership.rb.tt +36 -0
  363. data/lib/generators/seams/teams/templates/app/models/team.rb.tt +32 -0
  364. data/lib/generators/seams/teams/templates/app/subscribers/invitation_subscriber.rb.tt +36 -0
  365. data/lib/generators/seams/teams/templates/app/views/invitation_mailer/invite.text.erb.tt +8 -0
  366. data/lib/generators/seams/teams/templates/app/views/invitations/index.html.erb.tt +44 -0
  367. data/lib/generators/seams/teams/templates/app/views/memberships/index.html.erb.tt +32 -0
  368. data/lib/generators/seams/teams/templates/app/views/teams/edit.html.erb.tt +28 -0
  369. data/lib/generators/seams/teams/templates/app/views/teams/index.html.erb.tt +15 -0
  370. data/lib/generators/seams/teams/templates/app/views/teams/new.html.erb.tt +24 -0
  371. data/lib/generators/seams/teams/templates/app/views/teams/show.html.erb.tt +17 -0
  372. data/lib/generators/seams/teams/templates/config/routes.rb.tt +19 -0
  373. data/lib/generators/seams/teams/templates/db/migrate/create_team_invitations.rb.tt +24 -0
  374. data/lib/generators/seams/teams/templates/db/migrate/create_team_memberships.rb.tt +25 -0
  375. data/lib/generators/seams/teams/templates/db/migrate/create_teams.rb.tt +18 -0
  376. data/lib/generators/seams/teams/templates/lib/concerns/account_scoped.rb.tt +79 -0
  377. data/lib/generators/seams/teams/templates/lib/concerns/authorization.rb.tt +55 -0
  378. data/lib/generators/seams/teams/templates/lib/configuration.rb.tt +45 -0
  379. data/lib/generators/seams/teams/templates/lib/engine.rb.tt +51 -0
  380. data/lib/generators/seams/teams/templates/lib/teams.rb.tt +22 -0
  381. data/lib/generators/seams/teams/templates/spec/factories/teams.rb.tt +47 -0
  382. data/lib/generators/seams/teams/templates/spec/models/invitation_spec.rb.tt +25 -0
  383. data/lib/generators/seams/teams/templates/spec/models/membership_spec.rb.tt +29 -0
  384. data/lib/generators/seams/teams/templates/spec/models/team_spec.rb.tt +23 -0
  385. data/lib/generators/seams/teams/templates/spec/runtime/boot_spec.rb.tt +32 -0
  386. data/lib/seams/cli/list.rb +111 -0
  387. data/lib/seams/cli/quality.rb +99 -0
  388. data/lib/seams/cli/resolve.rb +276 -0
  389. data/lib/seams/cli/test_changed.rb +116 -0
  390. data/lib/seams/cli.rb +48 -0
  391. data/lib/seams/configuration.rb +19 -0
  392. data/lib/seams/cops/known_queue_names.rb +42 -0
  393. data/lib/seams/cops/migration_comments.rb +68 -0
  394. data/lib/seams/cops/no_cross_engine_dependency.rb +58 -0
  395. data/lib/seams/cops/no_cross_engine_model_access.rb +153 -0
  396. data/lib/seams/cops.rb +18 -0
  397. data/lib/seams/event_registry.rb +49 -0
  398. data/lib/seams/events/adapter.rb +24 -0
  399. data/lib/seams/events/adapters/active_support.rb +31 -0
  400. data/lib/seams/events/publisher.rb +178 -0
  401. data/lib/seams/events.rb +39 -0
  402. data/lib/seams/generators/dummy_app_writer.rb +424 -0
  403. data/lib/seams/generators/eject_aware.rb +102 -0
  404. data/lib/seams/generators/follow_up_generator.rb +148 -0
  405. data/lib/seams/generators/host_injector.rb +124 -0
  406. data/lib/seams/generators/sibling_rubocop_writer.rb +77 -0
  407. data/lib/seams/generators/splicer.rb +217 -0
  408. data/lib/seams/observability/adapter.rb +33 -0
  409. data/lib/seams/observability/adapters/rails_logger.rb +59 -0
  410. data/lib/seams/observability.rb +34 -0
  411. data/lib/seams/runtime.rb +23 -0
  412. data/lib/seams/version.rb +5 -0
  413. data/lib/seams.rb +23 -0
  414. metadata +493 -0
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Administrate controller for the Notifications::Notification
4
+ # dashboard. Note: Notification is an STI base — the table contains
5
+ # rows for InApp / Email / Sms subclasses. The admin index lists
6
+ # every subclass; the form lets admins set `type` to any of the
7
+ # permitted STI subclasses.
8
+ module Admin
9
+ class NotificationsController < ::Seams::Admin::ApplicationController
10
+ def resource_class
11
+ ::Notifications::Notification
12
+ end
13
+
14
+ def dashboard
15
+ @dashboard ||= NotificationDashboard.new
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Administrate controller for the Billing::Plan dashboard.
4
+ module Admin
5
+ class PlansController < ::Seams::Admin::ApplicationController
6
+ def resource_class
7
+ ::Billing::Plan
8
+ end
9
+
10
+ def dashboard
11
+ @dashboard ||= PlanDashboard.new
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Administrate controller for the Billing::Subscription dashboard.
4
+ module Admin
5
+ class SubscriptionsController < ::Seams::Admin::ApplicationController
6
+ def resource_class
7
+ ::Billing::Subscription
8
+ end
9
+
10
+ def dashboard
11
+ @dashboard ||= SubscriptionDashboard.new
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Administrate controller for the Teams::Team dashboard.
4
+ module Admin
5
+ class TeamsController < ::Seams::Admin::ApplicationController
6
+ def resource_class
7
+ ::Teams::Team
8
+ end
9
+
10
+ def dashboard
11
+ @dashboard ||= TeamDashboard.new
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Administrate controller for the Teams::Membership dashboard.
4
+ # Routed under `teams_memberships` (engine-prefixed) to disambiguate
5
+ # from `accounts_memberships`.
6
+ module Admin
7
+ class TeamsMembershipsController < ::Seams::Admin::ApplicationController
8
+ def resource_class
9
+ ::Teams::Membership
10
+ end
11
+
12
+ def dashboard
13
+ @dashboard ||= TeamsMembershipDashboard.new
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "administrate/base_dashboard"
4
+
5
+ # Administrate dashboard for Accounts::Account — the tenant boundary.
6
+ #
7
+ # Account uses a UUID primary key (so account ids can appear in
8
+ # shareable URLs without leaking row counts). Administrate's default
9
+ # Field::Number doesn't render UUIDs cleanly, so `id` is rendered as
10
+ # Field::String. The bigint `external_account_id` is a slug-friendly
11
+ # secondary identifier and renders fine as Field::Number.
12
+ module Admin
13
+ class AccountDashboard < Administrate::BaseDashboard
14
+ ATTRIBUTE_TYPES = {
15
+ # UUID PK — Field::String, not Field::Number.
16
+ id: Field::String,
17
+ name: Field::String,
18
+ external_account_id: Field::Number,
19
+ cancelled_at: Field::DateTime,
20
+ incinerated_at: Field::DateTime,
21
+ memberships: Field::HasMany,
22
+ created_at: Field::DateTime,
23
+ updated_at: Field::DateTime
24
+ }.freeze
25
+
26
+ COLLECTION_ATTRIBUTES = %i[id name external_account_id cancelled_at created_at].freeze
27
+
28
+ SHOW_PAGE_ATTRIBUTES = %i[
29
+ id
30
+ name
31
+ external_account_id
32
+ cancelled_at
33
+ incinerated_at
34
+ memberships
35
+ created_at
36
+ updated_at
37
+ ].freeze
38
+
39
+ FORM_ATTRIBUTES = %i[name].freeze
40
+
41
+ COLLECTION_FILTERS = {
42
+ active: ->(resources) { resources.where(cancelled_at: nil) },
43
+ cancelled: ->(resources) { resources.where.not(cancelled_at: nil) }
44
+ }.freeze
45
+
46
+ def display_resource(account)
47
+ account.name.presence || "Account ##{account.id}"
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "administrate/base_dashboard"
4
+
5
+ # Administrate dashboard for Accounts::Membership — joins an
6
+ # Auth::Identity to an Accounts::Account with a role.
7
+ #
8
+ # Class name is `Admin::AccountsMembershipDashboard` (with the engine
9
+ # prefix) to disambiguate from `Admin::TeamsMembershipDashboard` —
10
+ # both engines ship a Membership model and Administrate resolves
11
+ # dashboards by class name, so the prefixed form is necessary to keep
12
+ # them distinct in the same admin namespace.
13
+ #
14
+ # UUID primary key (matches Accounts::Account). identity_id is a bare
15
+ # bigint FK with no DB-level FK because cross-engine model access is
16
+ # forbidden by the seams architecture (NoCrossEngineModelAccess cop) —
17
+ # the admin surface treats identity_id as a typed integer reference.
18
+ module Admin
19
+ class AccountsMembershipDashboard < Administrate::BaseDashboard
20
+ ATTRIBUTE_TYPES = {
21
+ # UUID PK — Field::String, not Field::Number.
22
+ id: Field::String,
23
+ account: Field::BelongsTo.with_options(class_name: "Accounts::Account"),
24
+ identity_id: Field::Number,
25
+ name: Field::String,
26
+ role: Field::Select.with_options(collection: %w[owner admin member system]),
27
+ active: Field::Boolean,
28
+ verified_at: Field::DateTime,
29
+ created_at: Field::DateTime,
30
+ updated_at: Field::DateTime
31
+ }.freeze
32
+
33
+ COLLECTION_ATTRIBUTES = %i[id account name role active created_at].freeze
34
+
35
+ SHOW_PAGE_ATTRIBUTES = %i[
36
+ id
37
+ account
38
+ identity_id
39
+ name
40
+ role
41
+ active
42
+ verified_at
43
+ created_at
44
+ updated_at
45
+ ].freeze
46
+
47
+ FORM_ATTRIBUTES = %i[account identity_id name role active].freeze
48
+
49
+ COLLECTION_FILTERS = {
50
+ active: ->(resources) { resources.where(active: true).where.not(role: "system") },
51
+ system: ->(resources) { resources.where(role: "system") }
52
+ }.freeze
53
+
54
+ def display_resource(membership)
55
+ "#{membership.role}: #{membership.name}"
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "administrate/base_dashboard"
4
+
5
+ # Administrate dashboard for Auth::Identity. Identity is the canonical
6
+ # "who is logging in" record — credentials only, no customer-facing
7
+ # concerns. The encrypted email column is rendered with truncation and
8
+ # an "(encrypted at rest)" annotation so admins know they are looking
9
+ # at a column ActiveRecord::Encryption decrypts on read.
10
+ #
11
+ # Form fields deliberately exclude `password_digest` — admin should
12
+ # never see or set the bcrypt hash. Password resets go through the
13
+ # auth engine's reset flow, not through the admin surface.
14
+ module Admin
15
+ class IdentityDashboard < Administrate::BaseDashboard
16
+ # ATTRIBUTE_TYPES describes how Administrate renders each column.
17
+ # Administrate auto-discovers attributes from the model; declaring
18
+ # them explicitly here makes the rendering deterministic and lets
19
+ # us mark encrypted columns specially.
20
+ ATTRIBUTE_TYPES = {
21
+ id: Field::Number,
22
+ # email is encrypted at rest via ActiveRecord::Encryption (see
23
+ # Auth::Identity#encrypts). Truncated to 32 chars so a long
24
+ # ciphertext-padded email doesn't blow up the index column.
25
+ email: Field::String.with_options(searchable: true, truncate: 32), # (encrypted at rest)
26
+ staff: Field::Boolean,
27
+ created_at: Field::DateTime,
28
+ updated_at: Field::DateTime
29
+ }.freeze
30
+
31
+ COLLECTION_ATTRIBUTES = %i[id email staff created_at].freeze
32
+
33
+ SHOW_PAGE_ATTRIBUTES = %i[id email staff created_at updated_at].freeze
34
+
35
+ # password is intentionally absent — admin must not set the password
36
+ # directly. Hosts that need a "force-reset" admin action ship it as
37
+ # a custom action, not as a form field.
38
+ FORM_ATTRIBUTES = %i[email staff].freeze
39
+
40
+ COLLECTION_FILTERS = {
41
+ staff: ->(resources) { resources.where(staff: true) }
42
+ }.freeze
43
+
44
+ def display_resource(identity)
45
+ "Identity ##{identity.id}"
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "administrate/base_dashboard"
4
+
5
+ # Administrate dashboard for Teams::Invitation — the lifecycle record
6
+ # for a pending team invite. Token is rendered with truncation since
7
+ # it's a 32-byte URL-safe base64 secret; admins should not need to
8
+ # read the full token (they re-issue if lost).
9
+ module Admin
10
+ class InvitationDashboard < Administrate::BaseDashboard
11
+ ATTRIBUTE_TYPES = {
12
+ id: Field::Number,
13
+ team: Field::BelongsTo.with_options(class_name: "Teams::Team"),
14
+ email: Field::String.with_options(searchable: true),
15
+ # Truncated to 16 chars so the table view doesn't get blown up
16
+ # by the 43-char base64 token. Full value still available on the
17
+ # show page (truncate doesn't apply there).
18
+ token: Field::String.with_options(truncate: 16),
19
+ role: Field::Select.with_options(collection: %w[owner admin member]),
20
+ expires_at: Field::DateTime,
21
+ accepted_at: Field::DateTime,
22
+ created_at: Field::DateTime,
23
+ updated_at: Field::DateTime
24
+ }.freeze
25
+
26
+ COLLECTION_ATTRIBUTES = %i[id team email role expires_at accepted_at].freeze
27
+
28
+ SHOW_PAGE_ATTRIBUTES = %i[
29
+ id
30
+ team
31
+ email
32
+ token
33
+ role
34
+ expires_at
35
+ accepted_at
36
+ created_at
37
+ updated_at
38
+ ].freeze
39
+
40
+ FORM_ATTRIBUTES = %i[team email role expires_at].freeze
41
+
42
+ COLLECTION_FILTERS = {
43
+ pending: ->(resources) { resources.where(accepted_at: nil).where("expires_at > ?", Time.current) },
44
+ accepted: ->(resources) { resources.where.not(accepted_at: nil) }
45
+ }.freeze
46
+
47
+ def display_resource(invitation)
48
+ "Invitation to #{invitation.email}"
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,67 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "administrate/base_dashboard"
4
+
5
+ # Administrate dashboard for Billing::Invoice — local mirror of a
6
+ # gateway invoice. account_id is a UUID; rendered as Field::String.
7
+ #
8
+ # `amount_cents` is rendered as Field::Number for now; a custom
9
+ # Money field that formats "$12.34" with currency awareness is
10
+ # deferred to Wave 12 polish.
11
+ # TODO: Wave 12 — Field::Money custom field reading the `currency`
12
+ # column on the same row.
13
+ module Admin
14
+ class InvoiceDashboard < Administrate::BaseDashboard
15
+ ATTRIBUTE_TYPES = {
16
+ id: Field::Number,
17
+ # UUID — Field::String, not Field::Number.
18
+ account_id: Field::String,
19
+ gateway_ref: Field::String,
20
+ customer_ref: Field::String,
21
+ subscription_ref: Field::String,
22
+ # TODO: format as currency (Wave 12 — custom Money field)
23
+ amount_cents: Field::Number,
24
+ currency: Field::String,
25
+ status: Field::Select.with_options(collection: %w[draft open paid void uncollectible]),
26
+ paid_at: Field::DateTime,
27
+ created_at: Field::DateTime,
28
+ updated_at: Field::DateTime
29
+ }.freeze
30
+
31
+ COLLECTION_ATTRIBUTES = %i[id account_id gateway_ref status amount_cents paid_at].freeze
32
+
33
+ SHOW_PAGE_ATTRIBUTES = %i[
34
+ id
35
+ account_id
36
+ gateway_ref
37
+ customer_ref
38
+ subscription_ref
39
+ amount_cents
40
+ currency
41
+ status
42
+ paid_at
43
+ created_at
44
+ updated_at
45
+ ].freeze
46
+
47
+ FORM_ATTRIBUTES = %i[
48
+ account_id
49
+ gateway_ref
50
+ customer_ref
51
+ subscription_ref
52
+ amount_cents
53
+ currency
54
+ status
55
+ paid_at
56
+ ].freeze
57
+
58
+ COLLECTION_FILTERS = {
59
+ paid: ->(resources) { resources.where(status: "paid") },
60
+ open: ->(resources) { resources.where(status: "open") }
61
+ }.freeze
62
+
63
+ def display_resource(invoice)
64
+ "Invoice #{invoice.gateway_ref} (#{invoice.status})"
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "administrate/base_dashboard"
4
+
5
+ # Administrate dashboard for Billing::LifetimePass — one-time-paid OR
6
+ # privately-granted permanent access record. account_id is a UUID
7
+ # (Field::String). granted_by_identity_id / revoked_by_identity_id
8
+ # track the human (Auth::Identity bigint) who pressed the button.
9
+ module Admin
10
+ class LifetimePassDashboard < Administrate::BaseDashboard
11
+ ATTRIBUTE_TYPES = {
12
+ id: Field::Number,
13
+ # UUID — Field::String, not Field::Number.
14
+ account_id: Field::String,
15
+ customer_ref: Field::String,
16
+ plan_ref: Field::String,
17
+ gateway_ref: Field::String,
18
+ granted_by_identity_id: Field::Number,
19
+ granted_at: Field::DateTime,
20
+ revoked_at: Field::DateTime,
21
+ revoked_by_identity_id: Field::Number,
22
+ notes: Field::Text,
23
+ created_at: Field::DateTime,
24
+ updated_at: Field::DateTime
25
+ }.freeze
26
+
27
+ COLLECTION_ATTRIBUTES = %i[id account_id plan_ref granted_at revoked_at].freeze
28
+
29
+ SHOW_PAGE_ATTRIBUTES = %i[
30
+ id
31
+ account_id
32
+ customer_ref
33
+ plan_ref
34
+ gateway_ref
35
+ granted_by_identity_id
36
+ granted_at
37
+ revoked_at
38
+ revoked_by_identity_id
39
+ notes
40
+ created_at
41
+ updated_at
42
+ ].freeze
43
+
44
+ FORM_ATTRIBUTES = %i[
45
+ account_id
46
+ customer_ref
47
+ plan_ref
48
+ gateway_ref
49
+ granted_by_identity_id
50
+ granted_at
51
+ revoked_at
52
+ revoked_by_identity_id
53
+ notes
54
+ ].freeze
55
+
56
+ COLLECTION_FILTERS = {
57
+ active: ->(resources) { resources.where(revoked_at: nil) },
58
+ revoked: ->(resources) { resources.where.not(revoked_at: nil) }
59
+ }.freeze
60
+
61
+ def display_resource(pass)
62
+ "LifetimePass ##{pass.id} (#{pass.plan_ref})"
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "administrate/base_dashboard"
4
+
5
+ # Administrate dashboard for Notifications::Notification — the STI
6
+ # base. The `owner` association is polymorphic (Auth::Identity bigint
7
+ # OR Accounts::Account UUID OR a host model) and rendered via
8
+ # Field::Polymorphic so Administrate can handle both PK shapes.
9
+ #
10
+ # `schedule_data` is a jsonb cache of the IceCube::Schedule hash; it's
11
+ # verbose and rarely actionable in admin, so it's hidden from the
12
+ # collection view and only shown on the show page.
13
+ module Admin
14
+ class NotificationDashboard < Administrate::BaseDashboard
15
+ ATTRIBUTE_TYPES = {
16
+ id: Field::Number,
17
+ type: Field::String,
18
+ # Polymorphic owner — Field::Polymorphic resolves owner_type +
19
+ # owner_id, regardless of whether the owning row has a bigint or
20
+ # UUID PK (notification.owner_id is a string column).
21
+ owner: Field::Polymorphic,
22
+ recipient: Field::String,
23
+ template: Field::String,
24
+ next_delivery_at: Field::DateTime,
25
+ read_at: Field::DateTime,
26
+ schedule_data: Field::String.with_options(searchable: false),
27
+ created_at: Field::DateTime,
28
+ updated_at: Field::DateTime
29
+ }.freeze
30
+
31
+ COLLECTION_ATTRIBUTES = %i[id type owner template next_delivery_at read_at].freeze
32
+
33
+ SHOW_PAGE_ATTRIBUTES = %i[
34
+ id
35
+ type
36
+ owner
37
+ recipient
38
+ template
39
+ schedule_data
40
+ next_delivery_at
41
+ read_at
42
+ created_at
43
+ updated_at
44
+ ].freeze
45
+
46
+ FORM_ATTRIBUTES = %i[type owner recipient template].freeze
47
+
48
+ COLLECTION_FILTERS = {
49
+ due: ->(resources) { resources.where(next_delivery_at: ..Time.current) },
50
+ unread: ->(resources) { resources.where(read_at: nil) },
51
+ completed: ->(resources) { resources.where(next_delivery_at: nil) }
52
+ }.freeze
53
+
54
+ def display_resource(notification)
55
+ "#{notification.type&.demodulize}: #{notification.template}"
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "administrate/base_dashboard"
4
+
5
+ # Administrate dashboard for Notifications::NotificationPreference —
6
+ # per-Identity channel + notification-type toggle. Absence of a row
7
+ # means "use defaults" (everything enabled); a row with `enabled:
8
+ # false` is an explicit opt-out.
9
+ module Admin
10
+ class NotificationPreferenceDashboard < Administrate::BaseDashboard
11
+ ATTRIBUTE_TYPES = {
12
+ id: Field::Number,
13
+ identity_id: Field::Number,
14
+ channel: Field::Select.with_options(collection: %w[in_app email sms]),
15
+ notification_type: Field::String,
16
+ enabled: Field::Boolean,
17
+ created_at: Field::DateTime,
18
+ updated_at: Field::DateTime
19
+ }.freeze
20
+
21
+ COLLECTION_ATTRIBUTES = %i[id identity_id channel notification_type enabled].freeze
22
+
23
+ SHOW_PAGE_ATTRIBUTES = %i[
24
+ id
25
+ identity_id
26
+ channel
27
+ notification_type
28
+ enabled
29
+ created_at
30
+ updated_at
31
+ ].freeze
32
+
33
+ FORM_ATTRIBUTES = %i[identity_id channel notification_type enabled].freeze
34
+
35
+ COLLECTION_FILTERS = {
36
+ disabled: ->(resources) { resources.where(enabled: false) }
37
+ }.freeze
38
+
39
+ def display_resource(preference)
40
+ "Identity #{preference.identity_id} / #{preference.channel}"
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "administrate/base_dashboard"
4
+
5
+ # Administrate dashboard for Billing::Plan — local mirror of a Stripe
6
+ # Price (or other gateway's recurring billable thing).
7
+ #
8
+ # `amount_cents` is rendered as Field::Number for now; a custom
9
+ # Money field that formats "$12.34" with currency awareness is
10
+ # deferred to Wave 12 polish.
11
+ # TODO: Wave 12 — ship a Field::Money custom field that reads
12
+ # `currency` from the same row and formats accordingly.
13
+ module Admin
14
+ class PlanDashboard < Administrate::BaseDashboard
15
+ ATTRIBUTE_TYPES = {
16
+ id: Field::Number,
17
+ gateway_ref: Field::String,
18
+ name: Field::String,
19
+ description: Field::Text,
20
+ # TODO: format as currency (Wave 12 — custom Money field)
21
+ amount_cents: Field::Number,
22
+ currency: Field::String,
23
+ interval: Field::Select.with_options(collection: %w[day week month year lifetime]),
24
+ trial_period_days: Field::Number,
25
+ max_lifetime_units: Field::Number,
26
+ active: Field::Boolean,
27
+ features: Field::String.with_options(searchable: false),
28
+ created_at: Field::DateTime,
29
+ updated_at: Field::DateTime
30
+ }.freeze
31
+
32
+ COLLECTION_ATTRIBUTES = %i[id name gateway_ref interval amount_cents active].freeze
33
+
34
+ SHOW_PAGE_ATTRIBUTES = %i[
35
+ id
36
+ gateway_ref
37
+ name
38
+ description
39
+ amount_cents
40
+ currency
41
+ interval
42
+ trial_period_days
43
+ max_lifetime_units
44
+ active
45
+ features
46
+ created_at
47
+ updated_at
48
+ ].freeze
49
+
50
+ FORM_ATTRIBUTES = %i[
51
+ gateway_ref
52
+ name
53
+ description
54
+ amount_cents
55
+ currency
56
+ interval
57
+ trial_period_days
58
+ max_lifetime_units
59
+ active
60
+ ].freeze
61
+
62
+ COLLECTION_FILTERS = {
63
+ active: ->(resources) { resources.where(active: true) },
64
+ lifetime: ->(resources) { resources.where(interval: "lifetime") },
65
+ recurring: ->(resources) { resources.where.not(interval: "lifetime") }
66
+ }.freeze
67
+
68
+ def display_resource(plan)
69
+ plan.name.presence || plan.gateway_ref
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "administrate/base_dashboard"
4
+
5
+ # Administrate dashboard for Billing::Subscription — local mirror of a
6
+ # gateway subscription. account_id is a UUID (Accounts::Account#id) —
7
+ # rendered as Field::String since Field::Number truncates UUID strings.
8
+ # No belongs_to declaration on the model: cross-engine model access is
9
+ # forbidden by NoCrossEngineModelAccess, so the admin surface treats
10
+ # account_id as an opaque tenant reference rather than a belongs_to.
11
+ module Admin
12
+ class SubscriptionDashboard < Administrate::BaseDashboard
13
+ ATTRIBUTE_TYPES = {
14
+ id: Field::Number,
15
+ # UUID — Field::String, not Field::Number.
16
+ account_id: Field::String,
17
+ customer_ref: Field::String,
18
+ plan_ref: Field::String,
19
+ gateway_ref: Field::String,
20
+ status: Field::Select.with_options(
21
+ collection: %w[trialing active past_due canceled unpaid incomplete incomplete_expired paused]
22
+ ),
23
+ current_period_end: Field::DateTime,
24
+ created_at: Field::DateTime,
25
+ updated_at: Field::DateTime
26
+ }.freeze
27
+
28
+ COLLECTION_ATTRIBUTES = %i[id account_id status plan_ref current_period_end].freeze
29
+
30
+ SHOW_PAGE_ATTRIBUTES = %i[
31
+ id
32
+ account_id
33
+ customer_ref
34
+ plan_ref
35
+ gateway_ref
36
+ status
37
+ current_period_end
38
+ created_at
39
+ updated_at
40
+ ].freeze
41
+
42
+ FORM_ATTRIBUTES = %i[
43
+ account_id
44
+ customer_ref
45
+ plan_ref
46
+ gateway_ref
47
+ status
48
+ current_period_end
49
+ ].freeze
50
+
51
+ COLLECTION_FILTERS = {
52
+ active_or_trialing: ->(resources) { resources.where(status: %w[active trialing]) }
53
+ }.freeze
54
+
55
+ def display_resource(subscription)
56
+ "Subscription #{subscription.gateway_ref} (#{subscription.status})"
57
+ end
58
+ end
59
+ end