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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +335 -0
- data/LICENSE +21 -0
- data/README.md +104 -0
- data/lib/generators/seams/accounts/accounts_generator.rb +272 -0
- data/lib/generators/seams/accounts/templates/README.md.tt +219 -0
- data/lib/generators/seams/accounts/templates/app/models/account.rb.tt +124 -0
- data/lib/generators/seams/accounts/templates/app/models/application_record.rb.tt +7 -0
- data/lib/generators/seams/accounts/templates/app/models/current.rb.tt +38 -0
- data/lib/generators/seams/accounts/templates/app/models/membership.rb.tt +114 -0
- data/lib/generators/seams/accounts/templates/config/routes.rb.tt +8 -0
- data/lib/generators/seams/accounts/templates/db/migrate/create_accounts.rb.tt +29 -0
- data/lib/generators/seams/accounts/templates/db/migrate/create_accounts_memberships.rb.tt +49 -0
- data/lib/generators/seams/accounts/templates/lib/accounts.rb.tt +21 -0
- data/lib/generators/seams/accounts/templates/lib/concerns/account_scoped.rb.tt +97 -0
- data/lib/generators/seams/accounts/templates/lib/concerns/authorization.rb.tt +105 -0
- data/lib/generators/seams/accounts/templates/lib/configuration.rb.tt +26 -0
- data/lib/generators/seams/accounts/templates/lib/engine.rb.tt +55 -0
- data/lib/generators/seams/accounts/templates/spec/factories/accounts.rb.tt +49 -0
- data/lib/generators/seams/accounts/templates/spec/models/accounts/account_spec.rb.tt +64 -0
- data/lib/generators/seams/accounts/templates/spec/models/accounts/membership_spec.rb.tt +99 -0
- data/lib/generators/seams/accounts/templates/spec/runtime/accounts_boot_spec.rb.tt +181 -0
- data/lib/generators/seams/admin/admin_generator.rb +852 -0
- data/lib/generators/seams/admin/templates/README.md.tt +266 -0
- data/lib/generators/seams/admin/templates/app/controllers/admin/accounts_controller.rb.tt +16 -0
- data/lib/generators/seams/admin/templates/app/controllers/admin/accounts_memberships_controller.rb.tt +16 -0
- data/lib/generators/seams/admin/templates/app/controllers/admin/application_controller.rb.tt +282 -0
- data/lib/generators/seams/admin/templates/app/controllers/admin/identities_controller.rb.tt +26 -0
- data/lib/generators/seams/admin/templates/app/controllers/admin/invitations_controller.rb.tt +14 -0
- data/lib/generators/seams/admin/templates/app/controllers/admin/invoices_controller.rb.tt +14 -0
- data/lib/generators/seams/admin/templates/app/controllers/admin/lifetime_passes_controller.rb.tt +14 -0
- data/lib/generators/seams/admin/templates/app/controllers/admin/notification_preferences_controller.rb.tt +15 -0
- data/lib/generators/seams/admin/templates/app/controllers/admin/notifications_controller.rb.tt +18 -0
- data/lib/generators/seams/admin/templates/app/controllers/admin/plans_controller.rb.tt +14 -0
- data/lib/generators/seams/admin/templates/app/controllers/admin/subscriptions_controller.rb.tt +14 -0
- data/lib/generators/seams/admin/templates/app/controllers/admin/teams_controller.rb.tt +14 -0
- data/lib/generators/seams/admin/templates/app/controllers/admin/teams_memberships_controller.rb.tt +16 -0
- data/lib/generators/seams/admin/templates/app/dashboards/admin/account_dashboard.rb.tt +50 -0
- data/lib/generators/seams/admin/templates/app/dashboards/admin/accounts_membership_dashboard.rb.tt +58 -0
- data/lib/generators/seams/admin/templates/app/dashboards/admin/identity_dashboard.rb.tt +48 -0
- data/lib/generators/seams/admin/templates/app/dashboards/admin/invitation_dashboard.rb.tt +51 -0
- data/lib/generators/seams/admin/templates/app/dashboards/admin/invoice_dashboard.rb.tt +67 -0
- data/lib/generators/seams/admin/templates/app/dashboards/admin/lifetime_pass_dashboard.rb.tt +65 -0
- data/lib/generators/seams/admin/templates/app/dashboards/admin/notification_dashboard.rb.tt +58 -0
- data/lib/generators/seams/admin/templates/app/dashboards/admin/notification_preference_dashboard.rb.tt +43 -0
- data/lib/generators/seams/admin/templates/app/dashboards/admin/plan_dashboard.rb.tt +72 -0
- data/lib/generators/seams/admin/templates/app/dashboards/admin/subscription_dashboard.rb.tt +59 -0
- data/lib/generators/seams/admin/templates/app/dashboards/admin/team_dashboard.rb.tt +39 -0
- data/lib/generators/seams/admin/templates/app/dashboards/admin/teams_membership_dashboard.rb.tt +43 -0
- data/lib/generators/seams/admin/templates/app/policies/admin/platform/account_policy.rb.tt +10 -0
- data/lib/generators/seams/admin/templates/app/policies/admin/platform/accounts_membership_policy.rb.tt +10 -0
- data/lib/generators/seams/admin/templates/app/policies/admin/platform/application_policy.rb.tt +85 -0
- data/lib/generators/seams/admin/templates/app/policies/admin/platform/identity_policy.rb.tt +18 -0
- data/lib/generators/seams/admin/templates/app/policies/admin/platform/invitation_policy.rb.tt +9 -0
- data/lib/generators/seams/admin/templates/app/policies/admin/platform/invoice_policy.rb.tt +9 -0
- data/lib/generators/seams/admin/templates/app/policies/admin/platform/lifetime_pass_policy.rb.tt +9 -0
- data/lib/generators/seams/admin/templates/app/policies/admin/platform/notification_policy.rb.tt +9 -0
- data/lib/generators/seams/admin/templates/app/policies/admin/platform/notification_preference_policy.rb.tt +9 -0
- data/lib/generators/seams/admin/templates/app/policies/admin/platform/plan_policy.rb.tt +11 -0
- data/lib/generators/seams/admin/templates/app/policies/admin/platform/subscription_policy.rb.tt +9 -0
- data/lib/generators/seams/admin/templates/app/policies/admin/platform/team_policy.rb.tt +9 -0
- data/lib/generators/seams/admin/templates/app/policies/admin/platform/teams_membership_policy.rb.tt +9 -0
- data/lib/generators/seams/admin/templates/app/policies/admin/tenant/account_policy.rb.tt +33 -0
- data/lib/generators/seams/admin/templates/app/policies/admin/tenant/accounts_membership_policy.rb.tt +24 -0
- data/lib/generators/seams/admin/templates/app/policies/admin/tenant/application_policy.rb.tt +169 -0
- data/lib/generators/seams/admin/templates/app/policies/admin/tenant/identity_policy.rb.tt +67 -0
- data/lib/generators/seams/admin/templates/app/policies/admin/tenant/invitation_policy.rb.tt +24 -0
- data/lib/generators/seams/admin/templates/app/policies/admin/tenant/invoice_policy.rb.tt +21 -0
- data/lib/generators/seams/admin/templates/app/policies/admin/tenant/lifetime_pass_policy.rb.tt +21 -0
- data/lib/generators/seams/admin/templates/app/policies/admin/tenant/notification_policy.rb.tt +25 -0
- data/lib/generators/seams/admin/templates/app/policies/admin/tenant/notification_preference_policy.rb.tt +23 -0
- data/lib/generators/seams/admin/templates/app/policies/admin/tenant/plan_policy.rb.tt +47 -0
- data/lib/generators/seams/admin/templates/app/policies/admin/tenant/subscription_policy.rb.tt +22 -0
- data/lib/generators/seams/admin/templates/app/policies/admin/tenant/team_policy.rb.tt +28 -0
- data/lib/generators/seams/admin/templates/app/policies/admin/tenant/teams_membership_policy.rb.tt +24 -0
- data/lib/generators/seams/admin/templates/config/routes.rb.tt +38 -0
- data/lib/generators/seams/admin/templates/lib/admin.rb.tt +36 -0
- data/lib/generators/seams/admin/templates/lib/concerns/authenticator.rb.tt +66 -0
- data/lib/generators/seams/admin/templates/lib/configuration.rb.tt +90 -0
- data/lib/generators/seams/admin/templates/lib/context.rb.tt +44 -0
- data/lib/generators/seams/admin/templates/lib/engine.rb.tt +68 -0
- data/lib/generators/seams/admin/templates/spec/factories/admin.rb.tt +10 -0
- data/lib/generators/seams/admin/templates/spec/runtime/admin_boot_spec.rb.tt +604 -0
- data/lib/generators/seams/auth/add_oauth_provider/add_oauth_provider_generator.rb +157 -0
- data/lib/generators/seams/auth/add_oauth_provider/templates/adapter.rb.tt +95 -0
- data/lib/generators/seams/auth/add_oauth_provider/templates/adapter_spec.rb.tt +58 -0
- data/lib/generators/seams/auth/auth_generator.rb +311 -0
- data/lib/generators/seams/auth/templates/README.md.tt +289 -0
- data/lib/generators/seams/auth/templates/app/controllers/oauth/callbacks_controller.rb.tt +80 -0
- data/lib/generators/seams/auth/templates/app/controllers/password_resets_controller.rb.tt +44 -0
- data/lib/generators/seams/auth/templates/app/controllers/registrations_controller.rb.tt +34 -0
- data/lib/generators/seams/auth/templates/app/controllers/sessions_controller.rb.tt +49 -0
- data/lib/generators/seams/auth/templates/app/jobs/application_job.rb.tt +7 -0
- data/lib/generators/seams/auth/templates/app/jobs/cleanup_expired_sessions_job.rb.tt +30 -0
- data/lib/generators/seams/auth/templates/app/mailers/passwords_mailer.rb.tt +15 -0
- data/lib/generators/seams/auth/templates/app/models/api_token.rb.tt +62 -0
- data/lib/generators/seams/auth/templates/app/models/application_record.rb.tt +7 -0
- data/lib/generators/seams/auth/templates/app/models/current.rb.tt +15 -0
- data/lib/generators/seams/auth/templates/app/models/identity.rb.tt +74 -0
- data/lib/generators/seams/auth/templates/app/models/oauth/provider.rb.tt +48 -0
- data/lib/generators/seams/auth/templates/app/models/session.rb.tt +28 -0
- data/lib/generators/seams/auth/templates/app/services/authenticate_identity.rb.tt +31 -0
- data/lib/generators/seams/auth/templates/app/services/generate_api_token.rb.tt +35 -0
- data/lib/generators/seams/auth/templates/app/services/oauth/authenticator.rb.tt +94 -0
- data/lib/generators/seams/auth/templates/app/services/register_identity.rb.tt +57 -0
- data/lib/generators/seams/auth/templates/app/services/reset_password.rb.tt +41 -0
- data/lib/generators/seams/auth/templates/app/services/revoke_api_token.rb.tt +38 -0
- data/lib/generators/seams/auth/templates/app/views/password_resets/edit.html.erb.tt +12 -0
- data/lib/generators/seams/auth/templates/app/views/password_resets/new.html.erb.tt +11 -0
- data/lib/generators/seams/auth/templates/app/views/passwords_mailer/reset_email.html.erb.tt +7 -0
- data/lib/generators/seams/auth/templates/app/views/registrations/new.html.erb.tt +26 -0
- data/lib/generators/seams/auth/templates/app/views/sessions/_oauth_buttons.html.erb.tt +18 -0
- data/lib/generators/seams/auth/templates/app/views/sessions/new.html.erb.tt +17 -0
- data/lib/generators/seams/auth/templates/config/routes.rb.tt +21 -0
- data/lib/generators/seams/auth/templates/db/migrate/create_auth_api_tokens.rb.tt +26 -0
- data/lib/generators/seams/auth/templates/db/migrate/create_auth_identities.rb.tt +29 -0
- data/lib/generators/seams/auth/templates/db/migrate/create_auth_oauth_providers.rb.tt +35 -0
- data/lib/generators/seams/auth/templates/db/migrate/create_auth_sessions.rb.tt +19 -0
- data/lib/generators/seams/auth/templates/lib/auth.rb.tt +39 -0
- data/lib/generators/seams/auth/templates/lib/concerns/api_authenticatable.rb.tt +58 -0
- data/lib/generators/seams/auth/templates/lib/concerns/authenticatable.rb.tt +32 -0
- data/lib/generators/seams/auth/templates/lib/concerns/authentication.rb.tt +60 -0
- data/lib/generators/seams/auth/templates/lib/configuration.rb.tt +45 -0
- data/lib/generators/seams/auth/templates/lib/engine.rb.tt +46 -0
- data/lib/generators/seams/auth/templates/lib/oauth/abstract.rb.tt +87 -0
- data/lib/generators/seams/auth/templates/lib/oauth/github.rb.tt +112 -0
- data/lib/generators/seams/auth/templates/lib/oauth/google.rb.tt +78 -0
- data/lib/generators/seams/auth/templates/lib/tasks/auth_pii.rake.tt +68 -0
- data/lib/generators/seams/auth/templates/spec/factories/auth.rb.tt +38 -0
- data/lib/generators/seams/auth/templates/spec/mailers/passwords_mailer_spec.rb.tt +37 -0
- data/lib/generators/seams/auth/templates/spec/models/api_token_spec.rb.tt +84 -0
- data/lib/generators/seams/auth/templates/spec/models/identity_spec.rb.tt +56 -0
- data/lib/generators/seams/auth/templates/spec/models/oauth/provider_spec.rb.tt +64 -0
- data/lib/generators/seams/auth/templates/spec/models/session_spec.rb.tt +34 -0
- data/lib/generators/seams/auth/templates/spec/runtime/boot_spec.rb.tt +30 -0
- data/lib/generators/seams/auth/templates/spec/runtime/event_payload_spec.rb.tt +29 -0
- data/lib/generators/seams/auth/templates/spec/runtime/login_flow_spec.rb.tt +45 -0
- data/lib/generators/seams/billing/billing_generator.rb +476 -0
- data/lib/generators/seams/billing/templates/README.md.tt +355 -0
- data/lib/generators/seams/billing/templates/app/controllers/admin/lifetime_passes_controller.rb.tt +84 -0
- data/lib/generators/seams/billing/templates/app/controllers/checkout_controller.rb.tt +92 -0
- data/lib/generators/seams/billing/templates/app/controllers/invoices_controller.rb.tt +63 -0
- data/lib/generators/seams/billing/templates/app/controllers/plans_controller.rb.tt +14 -0
- data/lib/generators/seams/billing/templates/app/controllers/portal_controller.rb.tt +45 -0
- data/lib/generators/seams/billing/templates/app/controllers/subscriptions_controller.rb.tt +119 -0
- data/lib/generators/seams/billing/templates/app/controllers/webhooks_controller.rb.tt +98 -0
- data/lib/generators/seams/billing/templates/app/helpers/currency_helper.rb.tt +44 -0
- data/lib/generators/seams/billing/templates/app/jobs/application_job.rb.tt +6 -0
- data/lib/generators/seams/billing/templates/app/jobs/cancel_subscription_job.rb.tt +39 -0
- data/lib/generators/seams/billing/templates/app/jobs/start_subscription_job.rb.tt +32 -0
- data/lib/generators/seams/billing/templates/app/jobs/webhooks/process_event_job.rb.tt +37 -0
- data/lib/generators/seams/billing/templates/app/models/application_record.rb.tt +7 -0
- data/lib/generators/seams/billing/templates/app/models/invoice.rb.tt +35 -0
- data/lib/generators/seams/billing/templates/app/models/lifetime_pass.rb.tt +60 -0
- data/lib/generators/seams/billing/templates/app/models/plan.rb.tt +95 -0
- data/lib/generators/seams/billing/templates/app/models/subscription.rb.tt +31 -0
- data/lib/generators/seams/billing/templates/app/models/webhook_event.rb.tt +13 -0
- data/lib/generators/seams/billing/templates/app/services/checkout_session_service.rb.tt +25 -0
- data/lib/generators/seams/billing/templates/app/services/customers/find_or_create_service.rb.tt +73 -0
- data/lib/generators/seams/billing/templates/app/services/invoices/sync_service.rb.tt +50 -0
- data/lib/generators/seams/billing/templates/app/services/lifetime/create_lifetime_session_service.rb.tt +82 -0
- data/lib/generators/seams/billing/templates/app/services/lifetime/create_pass_from_checkout_service.rb.tt +88 -0
- data/lib/generators/seams/billing/templates/app/services/lifetime/grant_pass_service.rb.tt +80 -0
- data/lib/generators/seams/billing/templates/app/services/lifetime/revoke_pass_service.rb.tt +59 -0
- data/lib/generators/seams/billing/templates/app/services/portal_session_service.rb.tt +23 -0
- data/lib/generators/seams/billing/templates/app/services/service_result.rb.tt +38 -0
- data/lib/generators/seams/billing/templates/app/services/stripe_service.rb.tt +67 -0
- data/lib/generators/seams/billing/templates/app/services/subscriptions/cancel_service.rb.tt +42 -0
- data/lib/generators/seams/billing/templates/app/services/subscriptions/change_plan_service.rb.tt +48 -0
- data/lib/generators/seams/billing/templates/app/services/subscriptions/reactivate_service.rb.tt +28 -0
- data/lib/generators/seams/billing/templates/app/services/webhooks/event_router.rb.tt +54 -0
- data/lib/generators/seams/billing/templates/app/services/webhooks/handler.rb.tt +93 -0
- data/lib/generators/seams/billing/templates/app/services/webhooks/handlers/charge_refunded_handler.rb.tt +18 -0
- data/lib/generators/seams/billing/templates/app/services/webhooks/handlers/checkout_session_completed_handler.rb.tt +58 -0
- data/lib/generators/seams/billing/templates/app/services/webhooks/handlers/invoice_created_handler.rb.tt +16 -0
- data/lib/generators/seams/billing/templates/app/services/webhooks/handlers/invoice_finalized_handler.rb.tt +14 -0
- data/lib/generators/seams/billing/templates/app/services/webhooks/handlers/invoice_handler_base.rb.tt +80 -0
- data/lib/generators/seams/billing/templates/app/services/webhooks/handlers/invoice_paid_handler.rb.tt +12 -0
- data/lib/generators/seams/billing/templates/app/services/webhooks/handlers/invoice_payment_failed_handler.rb.tt +12 -0
- data/lib/generators/seams/billing/templates/app/services/webhooks/handlers/invoice_voided_handler.rb.tt +12 -0
- data/lib/generators/seams/billing/templates/app/services/webhooks/handlers/payment_failed_handler.rb.tt +15 -0
- data/lib/generators/seams/billing/templates/app/services/webhooks/handlers/payment_succeeded_handler.rb.tt +19 -0
- data/lib/generators/seams/billing/templates/app/services/webhooks/handlers/subscription_created_handler.rb.tt +11 -0
- data/lib/generators/seams/billing/templates/app/services/webhooks/handlers/subscription_deleted_handler.rb.tt +15 -0
- data/lib/generators/seams/billing/templates/app/services/webhooks/handlers/subscription_handler_base.rb.tt +92 -0
- data/lib/generators/seams/billing/templates/app/services/webhooks/handlers/subscription_trial_will_end_handler.rb.tt +15 -0
- data/lib/generators/seams/billing/templates/app/services/webhooks/handlers/subscription_updated_handler.rb.tt +11 -0
- data/lib/generators/seams/billing/templates/app/views/admin/lifetime_passes/index.html.erb.tt +36 -0
- data/lib/generators/seams/billing/templates/app/views/admin/lifetime_passes/new.html.erb.tt +37 -0
- data/lib/generators/seams/billing/templates/app/views/checkout/success.html.erb.tt +5 -0
- data/lib/generators/seams/billing/templates/app/views/invoices/index.html.erb.tt +22 -0
- data/lib/generators/seams/billing/templates/app/views/invoices/show.html.erb.tt +14 -0
- data/lib/generators/seams/billing/templates/app/views/plans/index.html.erb.tt +51 -0
- data/lib/generators/seams/billing/templates/app/views/subscriptions/index.html.erb.tt +16 -0
- data/lib/generators/seams/billing/templates/app/views/subscriptions/show.html.erb.tt +25 -0
- data/lib/generators/seams/billing/templates/config/routes.rb.tt +39 -0
- data/lib/generators/seams/billing/templates/db/migrate/create_billing_invoices.rb.tt +32 -0
- data/lib/generators/seams/billing/templates/db/migrate/create_billing_lifetime_passes.rb.tt +43 -0
- data/lib/generators/seams/billing/templates/db/migrate/create_billing_plans.rb.tt +31 -0
- data/lib/generators/seams/billing/templates/db/migrate/create_billing_subscriptions.rb.tt +33 -0
- data/lib/generators/seams/billing/templates/db/migrate/create_billing_webhook_events.rb.tt +24 -0
- data/lib/generators/seams/billing/templates/lib/billing.rb.tt +34 -0
- data/lib/generators/seams/billing/templates/lib/concerns/billable.rb.tt +100 -0
- data/lib/generators/seams/billing/templates/lib/configuration.rb.tt +52 -0
- data/lib/generators/seams/billing/templates/lib/engine.rb.tt +72 -0
- data/lib/generators/seams/billing/templates/lib/gateways/abstract.rb.tt +65 -0
- data/lib/generators/seams/billing/templates/lib/gateways/adyen.rb.tt +16 -0
- data/lib/generators/seams/billing/templates/lib/gateways/paddle.rb.tt +22 -0
- data/lib/generators/seams/billing/templates/lib/gateways/stripe.rb.tt +155 -0
- data/lib/generators/seams/billing/templates/lib/stripe/client.rb.tt +101 -0
- data/lib/generators/seams/billing/templates/lib/stripe/webhook_signature.rb.tt +43 -0
- data/lib/generators/seams/billing/templates/lib/tasks/billing_check.rake.tt +34 -0
- data/lib/generators/seams/billing/templates/spec/factories/billing.rb.tt +65 -0
- data/lib/generators/seams/billing/templates/spec/fixtures/stripe/charge_refunded.json.tt +19 -0
- data/lib/generators/seams/billing/templates/spec/fixtures/stripe/checkout_session_completed.json.tt +17 -0
- data/lib/generators/seams/billing/templates/spec/fixtures/stripe/customer_subscription_created.json.tt +25 -0
- data/lib/generators/seams/billing/templates/spec/fixtures/stripe/customer_subscription_deleted.json.tt +17 -0
- data/lib/generators/seams/billing/templates/spec/fixtures/stripe/customer_subscription_trial_will_end.json.tt +17 -0
- data/lib/generators/seams/billing/templates/spec/fixtures/stripe/customer_subscription_updated.json.tt +28 -0
- data/lib/generators/seams/billing/templates/spec/fixtures/stripe/invoice_created.json.tt +18 -0
- data/lib/generators/seams/billing/templates/spec/fixtures/stripe/invoice_finalized.json.tt +18 -0
- data/lib/generators/seams/billing/templates/spec/fixtures/stripe/invoice_paid.json.tt +19 -0
- data/lib/generators/seams/billing/templates/spec/fixtures/stripe/invoice_payment_failed.json.tt +20 -0
- data/lib/generators/seams/billing/templates/spec/fixtures/stripe/invoice_voided.json.tt +18 -0
- data/lib/generators/seams/billing/templates/spec/fixtures/stripe/payment_intent_payment_failed.json.tt +21 -0
- data/lib/generators/seams/billing/templates/spec/fixtures/stripe/payment_intent_succeeded.json.tt +17 -0
- data/lib/generators/seams/billing/templates/spec/gateways/contract_spec.rb.tt +11 -0
- data/lib/generators/seams/billing/templates/spec/gateways/stripe_spec.rb.tt +53 -0
- data/lib/generators/seams/billing/templates/spec/models/plan_spec.rb.tt +81 -0
- data/lib/generators/seams/billing/templates/spec/models/subscription_spec.rb.tt +43 -0
- data/lib/generators/seams/billing/templates/spec/runtime/boot_spec.rb.tt +38 -0
- data/lib/generators/seams/billing/templates/spec/runtime/webhook_handlers_spec.rb.tt +382 -0
- data/lib/generators/seams/billing/templates/spec/support/shared_examples/a_billing_gateway.rb.tt +100 -0
- data/lib/generators/seams/billing/templates/spec/support/stripe_helpers.rb.tt +59 -0
- data/lib/generators/seams/core/core_generator.rb +191 -0
- data/lib/generators/seams/core/templates/README.md.tt +45 -0
- data/lib/generators/seams/core/templates/app/controllers/concerns/has_current_attributes.rb.tt +71 -0
- data/lib/generators/seams/core/templates/app/models/application_record.rb.tt +7 -0
- data/lib/generators/seams/core/templates/app/models/audit_log.rb.tt +19 -0
- data/lib/generators/seams/core/templates/app/models/concerns/auditable.rb.tt +64 -0
- data/lib/generators/seams/core/templates/app/models/concerns/sluggable.rb.tt +53 -0
- data/lib/generators/seams/core/templates/app/models/concerns/soft_deletable.rb.tt +37 -0
- data/lib/generators/seams/core/templates/app/models/concerns/tenant_scoped.rb.tt +39 -0
- data/lib/generators/seams/core/templates/app/models/current.rb.tt +16 -0
- data/lib/generators/seams/core/templates/app/services/event_publisher.rb.tt +23 -0
- data/lib/generators/seams/core/templates/app/validators/email_format_validator.rb.tt +21 -0
- data/lib/generators/seams/core/templates/db/migrate/create_core_audit_logs.rb.tt +29 -0
- data/lib/generators/seams/core/templates/lib/core.rb.tt +8 -0
- data/lib/generators/seams/core/templates/lib/engine.rb.tt +28 -0
- data/lib/generators/seams/core/templates/spec/concerns/auditable_spec.rb.tt +39 -0
- data/lib/generators/seams/core/templates/spec/concerns/sluggable_spec.rb.tt +29 -0
- data/lib/generators/seams/core/templates/spec/models/audit_log_spec.rb.tt +22 -0
- data/lib/generators/seams/core/templates/spec/runtime/boot_spec.rb.tt +25 -0
- data/lib/generators/seams/core/templates/spec/validators/email_format_validator_spec.rb.tt +29 -0
- data/lib/generators/seams/engine/engine_generator.rb +165 -0
- data/lib/generators/seams/engine/templates/Gemfile.tt +19 -0
- data/lib/generators/seams/engine/templates/LICENSE.tt +21 -0
- data/lib/generators/seams/engine/templates/README.md.tt +40 -0
- data/lib/generators/seams/engine/templates/Rakefile.tt +14 -0
- data/lib/generators/seams/engine/templates/app/application_controller.rb.tt +6 -0
- data/lib/generators/seams/engine/templates/app/application_record.rb.tt +16 -0
- data/lib/generators/seams/engine/templates/config/locales/en.yml.tt +14 -0
- data/lib/generators/seams/engine/templates/config/routes.rb.tt +4 -0
- data/lib/generators/seams/engine/templates/gemspec.tt +20 -0
- data/lib/generators/seams/engine/templates/host_initializer.rb.tt +13 -0
- data/lib/generators/seams/engine/templates/lib/engine.rb.tt +27 -0
- data/lib/generators/seams/engine/templates/lib/root.rb.tt +7 -0
- data/lib/generators/seams/engine/templates/lib/version.rb.tt +5 -0
- data/lib/generators/seams/engine/templates/rubocop.yml.tt +55 -0
- data/lib/generators/seams/engine/templates/spec/example_spec.rb.tt +16 -0
- data/lib/generators/seams/engine/templates/spec/spec_helper.rb.tt +23 -0
- data/lib/generators/seams/install/install_generator.rb +211 -0
- data/lib/generators/seams/install/templates/Dockerfile.tt +52 -0
- data/lib/generators/seams/install/templates/Procfile.tt +14 -0
- data/lib/generators/seams/install/templates/bin_seams.tt +107 -0
- data/lib/generators/seams/install/templates/ci.yml.tt +123 -0
- data/lib/generators/seams/install/templates/deploy.yml.tt +63 -0
- data/lib/generators/seams/install/templates/doc/ARCHITECTURE.md.tt +86 -0
- data/lib/generators/seams/install/templates/docker-entrypoint.tt +27 -0
- data/lib/generators/seams/install/templates/rubocop.yml.tt +33 -0
- data/lib/generators/seams/install/templates/ruby-version.tt +1 -0
- data/lib/generators/seams/install/templates/script/collate_coverage.rb.tt +33 -0
- data/lib/generators/seams/install/templates/script/run_affected_tests.sh.tt +64 -0
- data/lib/generators/seams/install/templates/seams.rake.tt +65 -0
- data/lib/generators/seams/install/templates/seams.rb.tt +9 -0
- data/lib/generators/seams/install/templates/seams_engines.rb.tt +15 -0
- data/lib/generators/seams/notifications/notifications_generator.rb +395 -0
- data/lib/generators/seams/notifications/templates/README.md.tt +269 -0
- data/lib/generators/seams/notifications/templates/app/channels/notification_channel.rb.tt +36 -0
- data/lib/generators/seams/notifications/templates/app/controllers/notifications_controller.rb.tt +58 -0
- data/lib/generators/seams/notifications/templates/app/controllers/preferences_controller.rb.tt +54 -0
- data/lib/generators/seams/notifications/templates/app/javascript/controllers/notification_bell_controller.js.tt +34 -0
- data/lib/generators/seams/notifications/templates/app/jobs/application_job.rb.tt +6 -0
- data/lib/generators/seams/notifications/templates/app/jobs/create_notification_job.rb.tt +31 -0
- data/lib/generators/seams/notifications/templates/app/jobs/send_due_notifications_job.rb.tt +22 -0
- data/lib/generators/seams/notifications/templates/app/jobs/send_notification_job.rb.tt +13 -0
- data/lib/generators/seams/notifications/templates/app/mailers/application_mailer.rb.tt +12 -0
- data/lib/generators/seams/notifications/templates/app/mailers/notification_mailer.rb.tt +23 -0
- data/lib/generators/seams/notifications/templates/app/models/application_record.rb.tt +7 -0
- data/lib/generators/seams/notifications/templates/app/models/delivery.rb.tt +13 -0
- data/lib/generators/seams/notifications/templates/app/models/notification.rb.tt +218 -0
- data/lib/generators/seams/notifications/templates/app/models/notification_preference.rb.tt +29 -0
- data/lib/generators/seams/notifications/templates/app/models/strategies/email.rb.tt +38 -0
- data/lib/generators/seams/notifications/templates/app/models/strategies/in_app.rb.tt +26 -0
- data/lib/generators/seams/notifications/templates/app/models/strategies/sms.rb.tt +33 -0
- data/lib/generators/seams/notifications/templates/app/subscribers/auth_subscriber.rb.tt +71 -0
- data/lib/generators/seams/notifications/templates/app/subscribers/billing_subscriber.rb.tt +127 -0
- data/lib/generators/seams/notifications/templates/app/views/layouts/notifications/mailer.html.erb.tt +22 -0
- data/lib/generators/seams/notifications/templates/app/views/layouts/notifications/mailer.text.erb.tt +4 -0
- data/lib/generators/seams/notifications/templates/app/views/notifications/_bell.html.erb.tt +15 -0
- data/lib/generators/seams/notifications/templates/app/views/notifications/index.html.erb.tt +15 -0
- data/lib/generators/seams/notifications/templates/app/views/templates/billing/invoice_failed.html.erb.tt +4 -0
- data/lib/generators/seams/notifications/templates/app/views/templates/billing/invoice_failed.text.erb.tt +4 -0
- data/lib/generators/seams/notifications/templates/app/views/templates/billing/invoice_paid.html.erb.tt +3 -0
- data/lib/generators/seams/notifications/templates/app/views/templates/billing/invoice_paid.text.erb.tt +3 -0
- data/lib/generators/seams/notifications/templates/app/views/templates/billing/lifetime_granted.html.erb.tt +5 -0
- data/lib/generators/seams/notifications/templates/app/views/templates/billing/lifetime_granted.text.erb.tt +5 -0
- data/lib/generators/seams/notifications/templates/app/views/templates/billing/lifetime_purchased.html.erb.tt +5 -0
- data/lib/generators/seams/notifications/templates/app/views/templates/billing/lifetime_purchased.text.erb.tt +5 -0
- data/lib/generators/seams/notifications/templates/app/views/templates/billing/subscription_canceled.html.erb.tt +4 -0
- data/lib/generators/seams/notifications/templates/app/views/templates/billing/subscription_canceled.text.erb.tt +4 -0
- data/lib/generators/seams/notifications/templates/app/views/templates/billing/subscription_started.html.erb.tt +4 -0
- data/lib/generators/seams/notifications/templates/app/views/templates/billing/subscription_started.text.erb.tt +5 -0
- data/lib/generators/seams/notifications/templates/app/views/templates/billing/subscription_updated.html.erb.tt +3 -0
- data/lib/generators/seams/notifications/templates/app/views/templates/billing/subscription_updated.text.erb.tt +3 -0
- data/lib/generators/seams/notifications/templates/app/views/templates/default.html.erb.tt +10 -0
- data/lib/generators/seams/notifications/templates/app/views/templates/default.text.erb.tt +11 -0
- data/lib/generators/seams/notifications/templates/app/views/templates/welcome.html.erb.tt +6 -0
- data/lib/generators/seams/notifications/templates/app/views/templates/welcome.text.erb.tt +6 -0
- data/lib/generators/seams/notifications/templates/config/initializers/notifications.rb.tt +58 -0
- data/lib/generators/seams/notifications/templates/config/routes.rb.tt +17 -0
- data/lib/generators/seams/notifications/templates/db/migrate/create_notification_deliveries.rb.tt +16 -0
- data/lib/generators/seams/notifications/templates/db/migrate/create_notification_preferences.rb.tt +25 -0
- data/lib/generators/seams/notifications/templates/db/migrate/create_notifications.rb.tt +35 -0
- data/lib/generators/seams/notifications/templates/lib/adapters/abstract.rb.tt +20 -0
- data/lib/generators/seams/notifications/templates/lib/adapters/action_mailer.rb.tt +17 -0
- data/lib/generators/seams/notifications/templates/lib/adapters/null_sms.rb.tt +23 -0
- data/lib/generators/seams/notifications/templates/lib/concerns/notifiable.rb.tt +135 -0
- data/lib/generators/seams/notifications/templates/lib/configuration.rb.tt +24 -0
- data/lib/generators/seams/notifications/templates/lib/engine.rb.tt +35 -0
- data/lib/generators/seams/notifications/templates/lib/notifications.rb.tt +75 -0
- data/lib/generators/seams/notifications/templates/lib/type_registry.rb.tt +74 -0
- data/lib/generators/seams/notifications/templates/spec/factories/notifications.rb.tt +53 -0
- data/lib/generators/seams/notifications/templates/spec/models/delivery_spec.rb.tt +28 -0
- data/lib/generators/seams/notifications/templates/spec/models/notification_preference_spec.rb.tt +46 -0
- data/lib/generators/seams/notifications/templates/spec/models/notification_spec.rb.tt +60 -0
- data/lib/generators/seams/notifications/templates/spec/runtime/bell_broadcast_spec.rb.tt +59 -0
- data/lib/generators/seams/notifications/templates/spec/runtime/billing_subscriber_skip_spec.rb.tt +87 -0
- data/lib/generators/seams/notifications/templates/spec/runtime/boot_spec.rb.tt +39 -0
- data/lib/generators/seams/notifications/templates/spec/runtime/schedule_round_trip_spec.rb.tt +55 -0
- data/lib/generators/seams/remove/remove_generator.rb +259 -0
- data/lib/generators/seams/teams/teams_generator.rb +298 -0
- data/lib/generators/seams/teams/templates/README.md.tt +88 -0
- data/lib/generators/seams/teams/templates/app/controllers/invitations_controller.rb.tt +102 -0
- data/lib/generators/seams/teams/templates/app/controllers/memberships_controller.rb.tt +54 -0
- data/lib/generators/seams/teams/templates/app/controllers/teams_controller.rb.tt +68 -0
- data/lib/generators/seams/teams/templates/app/jobs/application_job.rb.tt +6 -0
- data/lib/generators/seams/teams/templates/app/mailers/invitation_mailer.rb.tt +34 -0
- data/lib/generators/seams/teams/templates/app/models/application_record.rb.tt +7 -0
- data/lib/generators/seams/teams/templates/app/models/current.rb.tt +30 -0
- data/lib/generators/seams/teams/templates/app/models/invitation.rb.tt +36 -0
- data/lib/generators/seams/teams/templates/app/models/membership.rb.tt +36 -0
- data/lib/generators/seams/teams/templates/app/models/team.rb.tt +32 -0
- data/lib/generators/seams/teams/templates/app/subscribers/invitation_subscriber.rb.tt +36 -0
- data/lib/generators/seams/teams/templates/app/views/invitation_mailer/invite.text.erb.tt +8 -0
- data/lib/generators/seams/teams/templates/app/views/invitations/index.html.erb.tt +44 -0
- data/lib/generators/seams/teams/templates/app/views/memberships/index.html.erb.tt +32 -0
- data/lib/generators/seams/teams/templates/app/views/teams/edit.html.erb.tt +28 -0
- data/lib/generators/seams/teams/templates/app/views/teams/index.html.erb.tt +15 -0
- data/lib/generators/seams/teams/templates/app/views/teams/new.html.erb.tt +24 -0
- data/lib/generators/seams/teams/templates/app/views/teams/show.html.erb.tt +17 -0
- data/lib/generators/seams/teams/templates/config/routes.rb.tt +19 -0
- data/lib/generators/seams/teams/templates/db/migrate/create_team_invitations.rb.tt +24 -0
- data/lib/generators/seams/teams/templates/db/migrate/create_team_memberships.rb.tt +25 -0
- data/lib/generators/seams/teams/templates/db/migrate/create_teams.rb.tt +18 -0
- data/lib/generators/seams/teams/templates/lib/concerns/account_scoped.rb.tt +79 -0
- data/lib/generators/seams/teams/templates/lib/concerns/authorization.rb.tt +55 -0
- data/lib/generators/seams/teams/templates/lib/configuration.rb.tt +45 -0
- data/lib/generators/seams/teams/templates/lib/engine.rb.tt +51 -0
- data/lib/generators/seams/teams/templates/lib/teams.rb.tt +22 -0
- data/lib/generators/seams/teams/templates/spec/factories/teams.rb.tt +47 -0
- data/lib/generators/seams/teams/templates/spec/models/invitation_spec.rb.tt +25 -0
- data/lib/generators/seams/teams/templates/spec/models/membership_spec.rb.tt +29 -0
- data/lib/generators/seams/teams/templates/spec/models/team_spec.rb.tt +23 -0
- data/lib/generators/seams/teams/templates/spec/runtime/boot_spec.rb.tt +32 -0
- data/lib/seams/cli/list.rb +111 -0
- data/lib/seams/cli/quality.rb +99 -0
- data/lib/seams/cli/resolve.rb +276 -0
- data/lib/seams/cli/test_changed.rb +116 -0
- data/lib/seams/cli.rb +48 -0
- data/lib/seams/configuration.rb +19 -0
- data/lib/seams/cops/known_queue_names.rb +42 -0
- data/lib/seams/cops/migration_comments.rb +68 -0
- data/lib/seams/cops/no_cross_engine_dependency.rb +58 -0
- data/lib/seams/cops/no_cross_engine_model_access.rb +153 -0
- data/lib/seams/cops.rb +18 -0
- data/lib/seams/event_registry.rb +49 -0
- data/lib/seams/events/adapter.rb +24 -0
- data/lib/seams/events/adapters/active_support.rb +31 -0
- data/lib/seams/events/publisher.rb +178 -0
- data/lib/seams/events.rb +39 -0
- data/lib/seams/generators/dummy_app_writer.rb +424 -0
- data/lib/seams/generators/eject_aware.rb +102 -0
- data/lib/seams/generators/follow_up_generator.rb +148 -0
- data/lib/seams/generators/host_injector.rb +124 -0
- data/lib/seams/generators/sibling_rubocop_writer.rb +77 -0
- data/lib/seams/generators/splicer.rb +217 -0
- data/lib/seams/observability/adapter.rb +33 -0
- data/lib/seams/observability/adapters/rails_logger.rb +59 -0
- data/lib/seams/observability.rb +34 -0
- data/lib/seams/runtime.rb +23 -0
- data/lib/seams/version.rb +5 -0
- data/lib/seams.rb +23 -0
- metadata +493 -0
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Host application RuboCop config.
|
|
2
|
+
#
|
|
3
|
+
# Engines under engines/<name>/ ship their own self-contained
|
|
4
|
+
# .rubocop.yml — they do NOT inherit from this file (this is
|
|
5
|
+
# intentional so a host using rubocop-rails-omakase doesn't force
|
|
6
|
+
# engine code through application-style rules).
|
|
7
|
+
#
|
|
8
|
+
# Add your own host rules here; the engine boundary cops are loaded
|
|
9
|
+
# per-engine via engines/<name>/.rubocop.yml, not globally.
|
|
10
|
+
|
|
11
|
+
AllCops:
|
|
12
|
+
TargetRubyVersion: 4.0
|
|
13
|
+
NewCops: enable
|
|
14
|
+
SuggestExtensions: false
|
|
15
|
+
Exclude:
|
|
16
|
+
- "bin/**/*"
|
|
17
|
+
- "db/schema.rb"
|
|
18
|
+
- "tmp/**/*"
|
|
19
|
+
- "vendor/**/*"
|
|
20
|
+
- "engines/**/*" # engines lint themselves
|
|
21
|
+
- "lib/tasks/seams.rake" # gem-generated; uses default rubocop array style
|
|
22
|
+
|
|
23
|
+
Style/Documentation:
|
|
24
|
+
Enabled: false
|
|
25
|
+
|
|
26
|
+
Style/StringLiterals:
|
|
27
|
+
EnforcedStyle: double_quotes
|
|
28
|
+
|
|
29
|
+
Layout/LineLength:
|
|
30
|
+
Max: 120
|
|
31
|
+
|
|
32
|
+
Metrics/MethodLength:
|
|
33
|
+
Max: 25
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
4.0.3
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Aggregates SimpleCov result files from every engine spec run into
|
|
4
|
+
# one combined report at coverage/.
|
|
5
|
+
#
|
|
6
|
+
# Each engine writes its own coverage/.resultset.json when its specs
|
|
7
|
+
# run. CI runs the engines in parallel (each on its own dummy app), so
|
|
8
|
+
# we end up with N partial reports. SimpleCov.collate merges them.
|
|
9
|
+
#
|
|
10
|
+
# Usage:
|
|
11
|
+
#
|
|
12
|
+
# bin/rails seams:test # writes per-engine coverage/.resultset.json
|
|
13
|
+
# ruby script/collate_coverage.rb
|
|
14
|
+
# open coverage/index.html
|
|
15
|
+
#
|
|
16
|
+
# Idempotent — re-running overwrites the merged report.
|
|
17
|
+
require "simplecov"
|
|
18
|
+
|
|
19
|
+
# Glob every engine's resultset, plus the host's, into one collation.
|
|
20
|
+
result_files = Dir.glob("engines/*/coverage/.resultset.json")
|
|
21
|
+
result_files << "coverage/.resultset.json" if File.exist?("coverage/.resultset.json")
|
|
22
|
+
|
|
23
|
+
if result_files.empty?
|
|
24
|
+
warn "No coverage/.resultset.json files found. Run specs first."
|
|
25
|
+
exit 1
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
puts "Collating #{result_files.size} resultset(s)..."
|
|
29
|
+
SimpleCov.collate(result_files) do
|
|
30
|
+
formatter SimpleCov::Formatter::HTMLFormatter
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
puts "Merged report: coverage/index.html"
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Detects which engines changed vs the merge base with `main` and runs
|
|
3
|
+
# only those engines' specs. Falls back to running every engine when
|
|
4
|
+
# the diff is empty (a noop branch) or when invoked with --all.
|
|
5
|
+
#
|
|
6
|
+
# Usage:
|
|
7
|
+
#
|
|
8
|
+
# script/run_affected_tests.sh # diff against main
|
|
9
|
+
# script/run_affected_tests.sh --all # run every engine
|
|
10
|
+
# BASE_BRANCH=develop script/run_affected_tests.sh
|
|
11
|
+
#
|
|
12
|
+
# Exit code is the OR of every engine spec run — first failure aborts.
|
|
13
|
+
|
|
14
|
+
set -euo pipefail
|
|
15
|
+
|
|
16
|
+
BASE_BRANCH="${BASE_BRANCH:-main}"
|
|
17
|
+
RUN_ALL=0
|
|
18
|
+
|
|
19
|
+
if [[ "${1:-}" == "--all" ]]; then
|
|
20
|
+
RUN_ALL=1
|
|
21
|
+
fi
|
|
22
|
+
|
|
23
|
+
# Resolve the merge base so we ignore commits already on main.
|
|
24
|
+
merge_base="$(git merge-base "$BASE_BRANCH" HEAD 2>/dev/null || echo "")"
|
|
25
|
+
if [[ -z "$merge_base" ]]; then
|
|
26
|
+
echo "Could not resolve merge base with $BASE_BRANCH — running all engines."
|
|
27
|
+
RUN_ALL=1
|
|
28
|
+
fi
|
|
29
|
+
|
|
30
|
+
if [[ "$RUN_ALL" == "1" ]]; then
|
|
31
|
+
changed_engines=$(ls -1 engines/ 2>/dev/null || true)
|
|
32
|
+
else
|
|
33
|
+
changed_engines=$(git diff --name-only "$merge_base" HEAD -- 'engines/*' \
|
|
34
|
+
| awk -F/ '{print $2}' | sort -u)
|
|
35
|
+
fi
|
|
36
|
+
|
|
37
|
+
if [[ -z "$changed_engines" ]]; then
|
|
38
|
+
echo "No engines changed since $BASE_BRANCH. Nothing to test."
|
|
39
|
+
exit 0
|
|
40
|
+
fi
|
|
41
|
+
|
|
42
|
+
echo "Engines to test:"
|
|
43
|
+
echo "$changed_engines" | sed 's/^/ - /'
|
|
44
|
+
echo
|
|
45
|
+
|
|
46
|
+
failed=()
|
|
47
|
+
for engine in $changed_engines; do
|
|
48
|
+
if [[ ! -d "engines/$engine" ]]; then
|
|
49
|
+
continue
|
|
50
|
+
fi
|
|
51
|
+
echo "=== running engines/$engine specs ==="
|
|
52
|
+
if ! bundle exec rspec "engines/$engine/spec"; then
|
|
53
|
+
failed+=("$engine")
|
|
54
|
+
fi
|
|
55
|
+
done
|
|
56
|
+
|
|
57
|
+
if (( ${#failed[@]} > 0 )); then
|
|
58
|
+
echo
|
|
59
|
+
echo "Failed engines: ${failed[*]}"
|
|
60
|
+
exit 1
|
|
61
|
+
fi
|
|
62
|
+
|
|
63
|
+
echo
|
|
64
|
+
echo "All affected engine specs passed."
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
namespace :seams do
|
|
4
|
+
ENGINE_NAME_PATTERN = /\A[a-z][a-z0-9_]*\z/
|
|
5
|
+
|
|
6
|
+
desc "List installed engines, the events they emit, and their dependencies"
|
|
7
|
+
task list: :environment do
|
|
8
|
+
require "seams/cli/list"
|
|
9
|
+
Seams::CLI::List.new.call
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
desc "Run RSpec for a single engine: rake seams:test[billing]"
|
|
13
|
+
task :test, [:engine] => :environment do |_t, args|
|
|
14
|
+
name = args[:engine] or abort("Usage: rake seams:test[billing]")
|
|
15
|
+
abort("Invalid engine name: #{name.inspect}") unless ENGINE_NAME_PATTERN.match?(name)
|
|
16
|
+
# Array form: no shell interpolation, no injection.
|
|
17
|
+
sh "bundle", "exec", "rspec", "engines/#{name}/spec"
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
desc "Run RuboCop for a single engine: rake seams:quality[billing]"
|
|
21
|
+
task :quality, [:engine] => :environment do |_t, args|
|
|
22
|
+
name = args[:engine] or abort("Usage: rake seams:quality[billing]")
|
|
23
|
+
abort("Invalid engine name: #{name.inspect}") unless ENGINE_NAME_PATTERN.match?(name)
|
|
24
|
+
sh "bundle", "exec", "rubocop", "engines/#{name}"
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
namespace :test do
|
|
28
|
+
desc "Run specs only for engines changed vs $BASE (default: main)"
|
|
29
|
+
task changed: :environment do
|
|
30
|
+
require "seams/cli"
|
|
31
|
+
base = ENV.fetch("BASE", "main")
|
|
32
|
+
abort("seams:test:changed failed.") unless Seams::CLI.test_changed(base: base)
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
namespace :quality do
|
|
37
|
+
desc "Aggregate RuboCop + Brakeman + bundle-audit + SimpleCov collation across the host"
|
|
38
|
+
task all: :environment do
|
|
39
|
+
require "seams/cli"
|
|
40
|
+
abort("seams:quality:all reported failures.") unless Seams::CLI.quality
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
desc "Pre-push verification: rubocop, host + per-engine specs, brakeman, bundle-audit, orphan-event check"
|
|
45
|
+
task audit: :environment do
|
|
46
|
+
Rake::Task["environment"].invoke
|
|
47
|
+
sh "bundle", "exec", "rubocop", "--parallel"
|
|
48
|
+
sh "bundle", "exec", "rspec", "spec"
|
|
49
|
+
Dir["engines/*"].select { |d| File.directory?(d) }.sort.each do |dir|
|
|
50
|
+
next if Dir.glob("#{dir}/spec/**/*_spec.rb").empty?
|
|
51
|
+
|
|
52
|
+
engine_name = File.basename(dir)
|
|
53
|
+
sh "bundle", "exec", "rspec",
|
|
54
|
+
"--default-path", "engines/#{engine_name}/spec",
|
|
55
|
+
"engines/#{engine_name}/spec"
|
|
56
|
+
end
|
|
57
|
+
sh "bundle", "exec", "brakeman", "--no-pager", "--no-progress", "--quiet"
|
|
58
|
+
sh "bundle", "exec", "bundle-audit", "check", "--update"
|
|
59
|
+
|
|
60
|
+
orphans = Seams::Events::Publisher.orphan_subscriptions
|
|
61
|
+
abort "orphan event subscriptions detected: #{orphans.inspect}" unless orphans.empty?
|
|
62
|
+
|
|
63
|
+
puts "All audit checks passed."
|
|
64
|
+
end
|
|
65
|
+
end
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Seams configuration. Both adapters can be replaced with custom
|
|
4
|
+
# implementations — see https://github.com/Davidslv/seams for details.
|
|
5
|
+
Seams.configure do |config|
|
|
6
|
+
config.event_bus_adapter = "Seams::Events::Adapters::ActiveSupport"
|
|
7
|
+
config.observability_adapter = "Seams::Observability::Adapters::RailsLogger"
|
|
8
|
+
config.host_app_name = (Rails.application.class.module_parent_name rescue nil)
|
|
9
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Load every engine under engines/ as if it were a Gemfile entry. Must
|
|
4
|
+
# run before Rails.application.initialize! so each engine's Railtie
|
|
5
|
+
# registers its initializers + paths (db/migrate, app/*) with the host.
|
|
6
|
+
# Required from config/application.rb after Bundler.require.
|
|
7
|
+
Dir[File.expand_path("../engines/*", __dir__)].sort.each do |engine_path|
|
|
8
|
+
next unless File.directory?(engine_path)
|
|
9
|
+
|
|
10
|
+
$LOAD_PATH.unshift File.join(engine_path, "lib")
|
|
11
|
+
|
|
12
|
+
engine_name = File.basename(engine_path)
|
|
13
|
+
main = File.join(engine_path, "lib", "#{engine_name}.rb")
|
|
14
|
+
require engine_name if File.exist?(main)
|
|
15
|
+
end
|
|
@@ -0,0 +1,395 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "fileutils"
|
|
4
|
+
require "rails/generators"
|
|
5
|
+
require "seams"
|
|
6
|
+
require "generators/seams/engine/engine_generator"
|
|
7
|
+
require "seams/generators/host_injector"
|
|
8
|
+
require "seams/generators/eject_aware"
|
|
9
|
+
require "seams/generators/dummy_app_writer"
|
|
10
|
+
|
|
11
|
+
module Seams
|
|
12
|
+
module Generators
|
|
13
|
+
# Generates a canonical Notifications engine on top of the generic
|
|
14
|
+
# engine scaffold.
|
|
15
|
+
#
|
|
16
|
+
# Notifications uses STI: a single +Notifications::Notification+
|
|
17
|
+
# base with three concrete subclasses under +Strategies+ — InApp,
|
|
18
|
+
# Email, Sms — each implementing its own +#dispatch!+. The
|
|
19
|
+
# schedule lives in a jsonb column populated by ice_cube;
|
|
20
|
+
# +next_delivery_at+ is the indexed cache the recurring sweeper
|
|
21
|
+
# reads from.
|
|
22
|
+
#
|
|
23
|
+
# Run with: bin/rails generate seams:notifications
|
|
24
|
+
# rubocop:disable Metrics/ClassLength
|
|
25
|
+
class NotificationsGenerator < Rails::Generators::Base
|
|
26
|
+
include Seams::Generators::HostInjector
|
|
27
|
+
include Seams::Generators::EjectAware
|
|
28
|
+
|
|
29
|
+
source_root File.expand_path("templates", __dir__)
|
|
30
|
+
|
|
31
|
+
ENGINE_NAME = "notifications"
|
|
32
|
+
DEFAULT_CHANNELS = %w[in_app email sms].freeze
|
|
33
|
+
BILLING_TEMPLATES = %w[
|
|
34
|
+
subscription_started
|
|
35
|
+
subscription_updated
|
|
36
|
+
subscription_canceled
|
|
37
|
+
invoice_paid
|
|
38
|
+
invoice_failed
|
|
39
|
+
lifetime_granted
|
|
40
|
+
lifetime_purchased
|
|
41
|
+
].freeze
|
|
42
|
+
|
|
43
|
+
class_option :channels, type: :string, default: "all",
|
|
44
|
+
desc: "Comma-separated channels to enable: in_app,email,sms (or 'all')"
|
|
45
|
+
|
|
46
|
+
def create_base_engine
|
|
47
|
+
EngineGenerator.start([ENGINE_NAME], destination_root: destination_root)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def overwrite_engine_entry_point
|
|
51
|
+
# engine.rb stays framework-managed.
|
|
52
|
+
template "lib/engine.rb.tt", engine_path("lib/notifications/engine.rb"), force: true
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def overwrite_routes
|
|
56
|
+
# Routes ship with an explicit Engine.routes.draw block — the
|
|
57
|
+
# generic engine scaffold leaves it empty, but notifications
|
|
58
|
+
# needs the canonical /notifications + /preferences surface +
|
|
59
|
+
# the Wave 10 `notifications.routes.after_preferences`
|
|
60
|
+
# insertion-point marker so follow-up generators can splice
|
|
61
|
+
# admin-side digest / opt-out routes.
|
|
62
|
+
template_unless_ejected "config/routes.rb.tt", engine_path("config/routes.rb"), force: true
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def create_configuration
|
|
66
|
+
template_unless_ejected "lib/configuration.rb.tt",
|
|
67
|
+
engine_path("lib/notifications/configuration.rb")
|
|
68
|
+
template_unless_ejected "lib/type_registry.rb.tt",
|
|
69
|
+
engine_path("lib/notifications/type_registry.rb")
|
|
70
|
+
# lib/notifications.rb stays framework-managed (root require file).
|
|
71
|
+
template "lib/notifications.rb.tt", engine_path("lib/notifications.rb"), force: true
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def create_adapters
|
|
75
|
+
template_unless_ejected "lib/adapters/abstract.rb.tt",
|
|
76
|
+
engine_path("lib/notifications/adapters/abstract.rb")
|
|
77
|
+
template_unless_ejected "lib/adapters/action_mailer.rb.tt",
|
|
78
|
+
engine_path("lib/notifications/adapters/action_mailer.rb")
|
|
79
|
+
# SMS adapter only ships when the sms channel is enabled.
|
|
80
|
+
return unless channels.include?("sms")
|
|
81
|
+
|
|
82
|
+
template_unless_ejected "lib/adapters/null_sms.rb.tt",
|
|
83
|
+
engine_path("lib/notifications/adapters/null_sms.rb")
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def create_concern
|
|
87
|
+
template_unless_ejected "lib/concerns/notifiable.rb.tt",
|
|
88
|
+
engine_path("lib/notifications/concerns/notifiable.rb")
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def create_models
|
|
92
|
+
template_unless_ejected "app/models/application_record.rb.tt",
|
|
93
|
+
engine_path("app/models/notifications/application_record.rb")
|
|
94
|
+
template_unless_ejected "app/models/notification.rb.tt",
|
|
95
|
+
engine_path("app/models/notifications/notification.rb")
|
|
96
|
+
template_unless_ejected "app/models/notification_preference.rb.tt",
|
|
97
|
+
engine_path("app/models/notifications/notification_preference.rb")
|
|
98
|
+
template_unless_ejected "app/models/delivery.rb.tt",
|
|
99
|
+
engine_path("app/models/notifications/delivery.rb")
|
|
100
|
+
create_strategy_models
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def create_strategy_models
|
|
104
|
+
# STI strategy subclasses ship per --channels selection.
|
|
105
|
+
# STRATEGY_CLASSES in the Notifiable concern is conditionally
|
|
106
|
+
# rendered (in_app/email/sms) to match.
|
|
107
|
+
channels.each do |channel|
|
|
108
|
+
template_unless_ejected "app/models/strategies/#{channel}.rb.tt",
|
|
109
|
+
engine_path("app/models/notifications/strategies/#{channel}.rb")
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def create_jobs
|
|
114
|
+
template_unless_ejected "app/jobs/application_job.rb.tt",
|
|
115
|
+
engine_path("app/jobs/notifications/application_job.rb")
|
|
116
|
+
template_unless_ejected "app/jobs/send_due_notifications_job.rb.tt",
|
|
117
|
+
engine_path("app/jobs/notifications/send_due_notifications_job.rb")
|
|
118
|
+
template_unless_ejected "app/jobs/send_notification_job.rb.tt",
|
|
119
|
+
engine_path("app/jobs/notifications/send_notification_job.rb")
|
|
120
|
+
template_unless_ejected "app/jobs/create_notification_job.rb.tt",
|
|
121
|
+
engine_path("app/jobs/notifications/create_notification_job.rb")
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def create_subscriber
|
|
125
|
+
template_unless_ejected "app/subscribers/auth_subscriber.rb.tt",
|
|
126
|
+
engine_path("app/subscribers/notifications/auth_subscriber.rb")
|
|
127
|
+
template_unless_ejected "app/subscribers/billing_subscriber.rb.tt",
|
|
128
|
+
engine_path("app/subscribers/notifications/billing_subscriber.rb")
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def create_controllers
|
|
132
|
+
template_unless_ejected "app/controllers/notifications_controller.rb.tt",
|
|
133
|
+
engine_path("app/controllers/notifications/notifications_controller.rb")
|
|
134
|
+
template_unless_ejected "app/controllers/preferences_controller.rb.tt",
|
|
135
|
+
engine_path("app/controllers/notifications/preferences_controller.rb")
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def create_views
|
|
139
|
+
template_unless_ejected "app/views/notifications/_bell.html.erb.tt",
|
|
140
|
+
engine_path("app/views/notifications/notifications/_bell.html.erb")
|
|
141
|
+
template_unless_ejected "app/views/notifications/index.html.erb.tt",
|
|
142
|
+
engine_path("app/views/notifications/notifications/index.html.erb")
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def create_channel_and_stimulus
|
|
146
|
+
template_unless_ejected "app/channels/notification_channel.rb.tt",
|
|
147
|
+
engine_path("app/channels/notifications/notification_channel.rb")
|
|
148
|
+
template_unless_ejected "app/javascript/controllers/notification_bell_controller.js.tt",
|
|
149
|
+
engine_path("app/javascript/notifications/controllers/notification_bell_controller.js")
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
def create_mailer
|
|
153
|
+
template_unless_ejected "app/mailers/application_mailer.rb.tt",
|
|
154
|
+
engine_path("app/mailers/notifications/application_mailer.rb")
|
|
155
|
+
template_unless_ejected "app/mailers/notification_mailer.rb.tt",
|
|
156
|
+
engine_path("app/mailers/notifications/notification_mailer.rb")
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
def create_default_templates
|
|
160
|
+
# Each notification template ships in two formats — .text.erb
|
|
161
|
+
# for SMS / plain-text email + .html.erb for HTML email and
|
|
162
|
+
# in-app rendering. Hosts override either or both by dropping
|
|
163
|
+
# files at app/views/notifications/templates/<name>.<format>.erb.
|
|
164
|
+
%i[text html].each do |format|
|
|
165
|
+
template_unless_ejected "app/views/templates/default.#{format}.erb.tt",
|
|
166
|
+
engine_path("app/views/notifications/templates/default.#{format}.erb")
|
|
167
|
+
template_unless_ejected "app/views/templates/welcome.#{format}.erb.tt",
|
|
168
|
+
engine_path("app/views/notifications/templates/welcome.#{format}.erb")
|
|
169
|
+
BILLING_TEMPLATES.each do |name|
|
|
170
|
+
template_unless_ejected "app/views/templates/billing/#{name}.#{format}.erb.tt",
|
|
171
|
+
engine_path("app/views/notifications/templates/billing/#{name}.#{format}.erb")
|
|
172
|
+
end
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
# Mailer layout — wraps every notification email so hosts get
|
|
176
|
+
# consistent header/footer chrome without per-template repetition.
|
|
177
|
+
template_unless_ejected "app/views/layouts/notifications/mailer.html.erb.tt",
|
|
178
|
+
engine_path("app/views/layouts/notifications/mailer.html.erb")
|
|
179
|
+
template_unless_ejected "app/views/layouts/notifications/mailer.text.erb.tt",
|
|
180
|
+
engine_path("app/views/layouts/notifications/mailer.text.erb")
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
def create_migrations
|
|
184
|
+
template "db/migrate/create_notifications.rb.tt",
|
|
185
|
+
engine_path("db/migrate/#{timestamp(0)}_create_notifications.rb")
|
|
186
|
+
template "db/migrate/create_notification_preferences.rb.tt",
|
|
187
|
+
engine_path("db/migrate/#{timestamp(1)}_create_notification_preferences.rb")
|
|
188
|
+
template "db/migrate/create_notification_deliveries.rb.tt",
|
|
189
|
+
engine_path("db/migrate/#{timestamp(2)}_create_notification_deliveries.rb")
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
def create_specs
|
|
193
|
+
# Phase 2B finish — coverage for the engine's three core models.
|
|
194
|
+
template_unless_ejected "spec/factories/notifications.rb.tt",
|
|
195
|
+
engine_path("spec/factories/notifications.rb")
|
|
196
|
+
template_unless_ejected "spec/models/notification_spec.rb.tt",
|
|
197
|
+
engine_path("spec/models/notifications/notification_spec.rb")
|
|
198
|
+
template_unless_ejected "spec/models/delivery_spec.rb.tt",
|
|
199
|
+
engine_path("spec/models/notifications/delivery_spec.rb")
|
|
200
|
+
template_unless_ejected "spec/models/notification_preference_spec.rb.tt",
|
|
201
|
+
engine_path("spec/models/notifications/notification_preference_spec.rb")
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
def create_dummy_app
|
|
205
|
+
Seams::Generators::DummyAppWriter.write!(
|
|
206
|
+
engine_path: File.join(destination_root, "engines", ENGINE_NAME),
|
|
207
|
+
engine_module: "Notifications",
|
|
208
|
+
mount_at: "/notifications",
|
|
209
|
+
schema: dummy_schema,
|
|
210
|
+
host_user: dummy_host_user,
|
|
211
|
+
host_user_path: "app/models/auth/identity.rb"
|
|
212
|
+
)
|
|
213
|
+
# Wire the runtime spec templates into the generator output —
|
|
214
|
+
# they were orphaned in templates/ pre-Wave-12 (the integration
|
|
215
|
+
# test silently skipped them).
|
|
216
|
+
template "spec/runtime/boot_spec.rb.tt",
|
|
217
|
+
engine_path("spec/runtime/notifications_boot_spec.rb")
|
|
218
|
+
template "spec/runtime/schedule_round_trip_spec.rb.tt",
|
|
219
|
+
engine_path("spec/runtime/notifications_schedule_round_trip_spec.rb")
|
|
220
|
+
# The BillingSubscriber emits a deliberately-loud
|
|
221
|
+
# `notifications.billing_subscriber.skip` warn line when a
|
|
222
|
+
# billing event arrives without an `account_id` — that's the
|
|
223
|
+
# only signal a host operator gets that notifications are
|
|
224
|
+
# silently failing for that tenant. Spec it.
|
|
225
|
+
template "spec/runtime/billing_subscriber_skip_spec.rb.tt",
|
|
226
|
+
engine_path("spec/runtime/notifications_billing_subscriber_skip_spec.rb")
|
|
227
|
+
# Phase 2B (3/3) — bell + ActionCable broadcast verification.
|
|
228
|
+
return unless channels.include?("in_app")
|
|
229
|
+
|
|
230
|
+
template "spec/runtime/bell_broadcast_spec.rb.tt",
|
|
231
|
+
engine_path("spec/runtime/notifications_bell_broadcast_spec.rb")
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
def overwrite_readme
|
|
235
|
+
template "README.md.tt", engine_path("README.md"), force: true
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
def update_exposed_concerns
|
|
239
|
+
rubocop_path = engine_path(".rubocop.yml")
|
|
240
|
+
return unless File.exist?(rubocop_path)
|
|
241
|
+
|
|
242
|
+
contents = File.read(rubocop_path)
|
|
243
|
+
replacement = " ExposedConcerns:\n - Notifications::Notifiable"
|
|
244
|
+
contents.sub!(/^ ExposedConcerns: \[\]$/, replacement)
|
|
245
|
+
File.write(rubocop_path, contents)
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
def create_initializer
|
|
249
|
+
# Host-side initializer — documents the configure-adapters
|
|
250
|
+
# entry point AND the optional Notifiable concern include
|
|
251
|
+
# patterns. Wave 9 dropped the auto-include into the host
|
|
252
|
+
# User; hosts now opt in by uncommenting one of the patterns
|
|
253
|
+
# below (or leave the concern uninvoked — the polymorphic
|
|
254
|
+
# owner column doesn't require it).
|
|
255
|
+
template "config/initializers/notifications.rb.tt",
|
|
256
|
+
File.join(destination_root, "config/initializers/notifications.rb")
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
def wire_into_host
|
|
260
|
+
host_inject_gem("ice_cube", ">= 0.16")
|
|
261
|
+
# factory_bot_rails powers the engine's spec/factories/*. Lives
|
|
262
|
+
# in the host's test group only.
|
|
263
|
+
host_inject_gem("factory_bot_rails", "~> 6.4", group: :test)
|
|
264
|
+
host_inject_mount(engine_class: "Notifications::Engine", at: "/notifications")
|
|
265
|
+
# Wave 9: no auto-include into a host User. The canonical demo
|
|
266
|
+
# has no host User after Wave 9 (the "human" is Auth::Identity).
|
|
267
|
+
# Hosts wire `Notifications::Notifiable` themselves via the
|
|
268
|
+
# initializer template — see config/initializers/notifications.rb.
|
|
269
|
+
end
|
|
270
|
+
|
|
271
|
+
def report_summary
|
|
272
|
+
say ""
|
|
273
|
+
say " Notifications engine generated at engines/notifications/", :green
|
|
274
|
+
say ""
|
|
275
|
+
say " Next steps:", :yellow
|
|
276
|
+
say " 1. bundle install (picks up ice_cube)"
|
|
277
|
+
say " 2. bin/rails db:migrate"
|
|
278
|
+
say " 3. Schedule the sweeper. With Solid Queue, add to config/recurring.yml:"
|
|
279
|
+
say " notifications_dispatcher:"
|
|
280
|
+
say " class: Notifications::SendDueNotificationsJob"
|
|
281
|
+
say " schedule: every minute"
|
|
282
|
+
say " 4. Configure adapters in config/initializers/notifications.rb"
|
|
283
|
+
say " 5. (optional) Include Notifications::Notifiable on Auth::Identity"
|
|
284
|
+
say " via the same initializer — see the file's comments."
|
|
285
|
+
say ""
|
|
286
|
+
say " Subscribed to: identity.signed_up.auth (creates an InApp + Email Notification)"
|
|
287
|
+
say ""
|
|
288
|
+
end
|
|
289
|
+
|
|
290
|
+
private
|
|
291
|
+
|
|
292
|
+
# Resolved list of channels the host opted into via --channels.
|
|
293
|
+
# "all" (or empty / unrecognised) → all three. Memoised per
|
|
294
|
+
# generator run so conditional template branches stay consistent.
|
|
295
|
+
def channels
|
|
296
|
+
@channels ||= begin
|
|
297
|
+
raw = options[:channels].to_s.downcase.strip
|
|
298
|
+
if raw.empty? || raw == "all"
|
|
299
|
+
DEFAULT_CHANNELS.dup
|
|
300
|
+
else
|
|
301
|
+
requested = raw.split(",").map(&:strip).reject(&:empty?)
|
|
302
|
+
allowed = requested & DEFAULT_CHANNELS
|
|
303
|
+
allowed.empty? ? DEFAULT_CHANNELS.dup : allowed
|
|
304
|
+
end
|
|
305
|
+
end
|
|
306
|
+
end
|
|
307
|
+
|
|
308
|
+
def engine_path(relative)
|
|
309
|
+
File.join(destination_root, "engines", ENGINE_NAME, relative)
|
|
310
|
+
end
|
|
311
|
+
|
|
312
|
+
# Add 100+offset to the packed timestamp so this engine's
|
|
313
|
+
# migrations don't collide with another engine generated in the
|
|
314
|
+
# same second.
|
|
315
|
+
def timestamp(offset = 0)
|
|
316
|
+
base = Time.now.utc.strftime("%Y%m%d%H%M%S").to_i
|
|
317
|
+
(base + 100 + offset).to_s
|
|
318
|
+
end
|
|
319
|
+
|
|
320
|
+
def dummy_schema
|
|
321
|
+
# Wave 9: the dummy ships an `auth_identities` table (not
|
|
322
|
+
# `users`) so spec fixtures can construct a realistic owner
|
|
323
|
+
# for polymorphic Notifications. The dummy doesn't load the
|
|
324
|
+
# auth gem itself — a slim Auth::Identity stub model lives in
|
|
325
|
+
# spec/dummy/app/models/auth/identity.rb (see dummy_host_user
|
|
326
|
+
# below) and includes Notifiable so existing helpers
|
|
327
|
+
# (`unread_in_app_notifications`, etc.) keep working.
|
|
328
|
+
# The schema mirrors the auth + accounts engine shape (text
|
|
329
|
+
# email, password_digest, staff flag + partial index) so
|
|
330
|
+
# cross-engine fixture sharing doesn't drift.
|
|
331
|
+
<<~SCHEMA
|
|
332
|
+
create_table :auth_identities do |t|
|
|
333
|
+
t.text :email, null: false
|
|
334
|
+
t.string :password_digest, null: false, default: ""
|
|
335
|
+
t.boolean :staff, null: false, default: false
|
|
336
|
+
t.timestamps
|
|
337
|
+
end
|
|
338
|
+
add_index :auth_identities, :email, unique: true
|
|
339
|
+
add_index :auth_identities, :staff, where: "staff = true"
|
|
340
|
+
|
|
341
|
+
create_table :notifications do |t|
|
|
342
|
+
t.string :type, null: false
|
|
343
|
+
# Polymorphic owner stored as strings so the column holds
|
|
344
|
+
# bigint Identity IDs and UUID Account IDs simultaneously.
|
|
345
|
+
t.string :owner_type, null: false
|
|
346
|
+
t.string :owner_id, null: false
|
|
347
|
+
t.string :recipient
|
|
348
|
+
t.string :template, null: false
|
|
349
|
+
t.jsonb :schedule_data
|
|
350
|
+
t.datetime :next_delivery_at
|
|
351
|
+
t.datetime :read_at
|
|
352
|
+
t.timestamps
|
|
353
|
+
end
|
|
354
|
+
add_index :notifications, %i[owner_type owner_id]
|
|
355
|
+
add_index :notifications, :next_delivery_at
|
|
356
|
+
|
|
357
|
+
create_table :notification_preferences do |t|
|
|
358
|
+
t.bigint :identity_id, null: false
|
|
359
|
+
t.string :channel, null: false
|
|
360
|
+
t.string :notification_type
|
|
361
|
+
t.boolean :enabled, null: false, default: true
|
|
362
|
+
t.timestamps
|
|
363
|
+
end
|
|
364
|
+
add_index :notification_preferences, %i[identity_id channel notification_type], unique: true,
|
|
365
|
+
name: "index_notification_prefs_unique"
|
|
366
|
+
|
|
367
|
+
create_table :notification_deliveries do |t|
|
|
368
|
+
t.references :notification, null: false, foreign_key: true, index: true
|
|
369
|
+
t.datetime :sent_at, null: false
|
|
370
|
+
t.timestamps
|
|
371
|
+
end
|
|
372
|
+
SCHEMA
|
|
373
|
+
end
|
|
374
|
+
|
|
375
|
+
# Slim Auth::Identity stub for the dummy app. Stands in for the
|
|
376
|
+
# real Auth::Identity (which lives in the auth engine, not loaded
|
|
377
|
+
# by the dummy) so notifications specs can build a polymorphic
|
|
378
|
+
# owner. Includes Notifiable so the bell + #notify helpers
|
|
379
|
+
# exercise the same code path the canonical seams host uses.
|
|
380
|
+
def dummy_host_user
|
|
381
|
+
<<~RB
|
|
382
|
+
# frozen_string_literal: true
|
|
383
|
+
|
|
384
|
+
module Auth
|
|
385
|
+
class Identity < ApplicationRecord
|
|
386
|
+
self.table_name = "auth_identities"
|
|
387
|
+
include Notifications::Notifiable
|
|
388
|
+
end
|
|
389
|
+
end
|
|
390
|
+
RB
|
|
391
|
+
end
|
|
392
|
+
end
|
|
393
|
+
# rubocop:enable Metrics/ClassLength
|
|
394
|
+
end
|
|
395
|
+
end
|