rails-metro 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 (150) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +17 -0
  3. data/LICENSE +21 -0
  4. data/README.md +267 -0
  5. data/exe/metro +3 -0
  6. data/lib/rails/metro/cli.rb +162 -0
  7. data/lib/rails/metro/config.rb +40 -0
  8. data/lib/rails/metro/feature_pack.rb +59 -0
  9. data/lib/rails/metro/feature_registry.rb +147 -0
  10. data/lib/rails/metro/packs/aasm_pack.rb +29 -0
  11. data/lib/rails/metro/packs/ab_testing_pack.rb +39 -0
  12. data/lib/rails/metro/packs/action_text_pack.rb +29 -0
  13. data/lib/rails/metro/packs/activeadmin_pack.rb +32 -0
  14. data/lib/rails/metro/packs/activity_feed_pack.rb +31 -0
  15. data/lib/rails/metro/packs/acts_as_list_pack.rb +28 -0
  16. data/lib/rails/metro/packs/acts_as_votable_pack.rb +32 -0
  17. data/lib/rails/metro/packs/administrate_pack.rb +31 -0
  18. data/lib/rails/metro/packs/after_party_pack.rb +31 -0
  19. data/lib/rails/metro/packs/ahoy_pack.rb +31 -0
  20. data/lib/rails/metro/packs/amplitude_pack.rb +45 -0
  21. data/lib/rails/metro/packs/annotate_pack.rb +30 -0
  22. data/lib/rails/metro/packs/api_cors_pack.rb +41 -0
  23. data/lib/rails/metro/packs/api_docs_pack.rb +34 -0
  24. data/lib/rails/metro/packs/api_guard_pack.rb +31 -0
  25. data/lib/rails/metro/packs/api_serialization_pack.rb +38 -0
  26. data/lib/rails/metro/packs/app_linting_pack.rb +35 -0
  27. data/lib/rails/metro/packs/audit_trail_pack.rb +31 -0
  28. data/lib/rails/metro/packs/authentication_pack.rb +31 -0
  29. data/lib/rails/metro/packs/authorization_pack.rb +31 -0
  30. data/lib/rails/metro/packs/avo_pack.rb +32 -0
  31. data/lib/rails/metro/packs/aws_ses_pack.rb +45 -0
  32. data/lib/rails/metro/packs/background_jobs_pack.rb +34 -0
  33. data/lib/rails/metro/packs/blazer_pack.rb +62 -0
  34. data/lib/rails/metro/packs/breadcrumbs_pack.rb +31 -0
  35. data/lib/rails/metro/packs/caching_pack.rb +30 -0
  36. data/lib/rails/metro/packs/charting_pack.rb +67 -0
  37. data/lib/rails/metro/packs/circuit_breaker_pack.rb +34 -0
  38. data/lib/rails/metro/packs/clicky_pack.rb +37 -0
  39. data/lib/rails/metro/packs/cloudinary_pack.rb +42 -0
  40. data/lib/rails/metro/packs/components_pack.rb +30 -0
  41. data/lib/rails/metro/packs/counter_culture_pack.rb +29 -0
  42. data/lib/rails/metro/packs/data_migrate_pack.rb +29 -0
  43. data/lib/rails/metro/packs/datadog_pack.rb +41 -0
  44. data/lib/rails/metro/packs/deployment_pack.rb +30 -0
  45. data/lib/rails/metro/packs/devise_pack.rb +33 -0
  46. data/lib/rails/metro/packs/doorkeeper_pack.rb +32 -0
  47. data/lib/rails/metro/packs/dotenv_pack.rb +36 -0
  48. data/lib/rails/metro/packs/elasticsearch_pack.rb +31 -0
  49. data/lib/rails/metro/packs/encryption_pack.rb +37 -0
  50. data/lib/rails/metro/packs/error_tracking_pack.rb +40 -0
  51. data/lib/rails/metro/packs/event_sourcing_pack.rb +31 -0
  52. data/lib/rails/metro/packs/faraday_pack.rb +42 -0
  53. data/lib/rails/metro/packs/fathom_pack.rb +36 -0
  54. data/lib/rails/metro/packs/feature_flags_pack.rb +34 -0
  55. data/lib/rails/metro/packs/friendly_id_pack.rb +31 -0
  56. data/lib/rails/metro/packs/geocoder_pack.rb +38 -0
  57. data/lib/rails/metro/packs/good_job_pack.rb +34 -0
  58. data/lib/rails/metro/packs/google_analytics_pack.rb +42 -0
  59. data/lib/rails/metro/packs/google_tag_manager_pack.rb +51 -0
  60. data/lib/rails/metro/packs/graphql_pack.rb +31 -0
  61. data/lib/rails/metro/packs/health_check_pack.rb +34 -0
  62. data/lib/rails/metro/packs/heap_pack.rb +39 -0
  63. data/lib/rails/metro/packs/honeybadger_pack.rb +37 -0
  64. data/lib/rails/metro/packs/hotwire_livereload_pack.rb +28 -0
  65. data/lib/rails/metro/packs/icons_pack.rb +28 -0
  66. data/lib/rails/metro/packs/invisible_captcha_pack.rb +35 -0
  67. data/lib/rails/metro/packs/kredis_pack.rb +31 -0
  68. data/lib/rails/metro/packs/lemon_squeezy_pack.rb +36 -0
  69. data/lib/rails/metro/packs/letter_opener_pack.rb +31 -0
  70. data/lib/rails/metro/packs/letter_opener_web_pack.rb +32 -0
  71. data/lib/rails/metro/packs/logging_pack.rb +36 -0
  72. data/lib/rails/metro/packs/madmin_pack.rb +32 -0
  73. data/lib/rails/metro/packs/mailgun_pack.rb +44 -0
  74. data/lib/rails/metro/packs/maintenance_mode_pack.rb +30 -0
  75. data/lib/rails/metro/packs/maintenance_tasks_pack.rb +32 -0
  76. data/lib/rails/metro/packs/markdown_pack.rb +48 -0
  77. data/lib/rails/metro/packs/matomo_pack.rb +48 -0
  78. data/lib/rails/metro/packs/meilisearch_pack.rb +37 -0
  79. data/lib/rails/metro/packs/mixpanel_pack.rb +47 -0
  80. data/lib/rails/metro/packs/mobility_pack.rb +32 -0
  81. data/lib/rails/metro/packs/mollie_pack.rb +36 -0
  82. data/lib/rails/metro/packs/multitenancy_pack.rb +35 -0
  83. data/lib/rails/metro/packs/newrelic_pack.rb +52 -0
  84. data/lib/rails/metro/packs/notifications_pack.rb +31 -0
  85. data/lib/rails/metro/packs/omniauth_pack.rb +49 -0
  86. data/lib/rails/metro/packs/paddle_pack.rb +37 -0
  87. data/lib/rails/metro/packs/pagination_pack.rb +44 -0
  88. data/lib/rails/metro/packs/passwordless_pack.rb +32 -0
  89. data/lib/rails/metro/packs/payments_pack.rb +35 -0
  90. data/lib/rails/metro/packs/paypal_pack.rb +35 -0
  91. data/lib/rails/metro/packs/pdf_pack.rb +45 -0
  92. data/lib/rails/metro/packs/performance_pack.rb +37 -0
  93. data/lib/rails/metro/packs/pghero_pack.rb +31 -0
  94. data/lib/rails/metro/packs/plausible_pack.rb +36 -0
  95. data/lib/rails/metro/packs/posthog_pack.rb +40 -0
  96. data/lib/rails/metro/packs/postmark_pack.rb +39 -0
  97. data/lib/rails/metro/packs/pretender_pack.rb +33 -0
  98. data/lib/rails/metro/packs/profiling_pack.rb +30 -0
  99. data/lib/rails/metro/packs/pundit_pack.rb +50 -0
  100. data/lib/rails/metro/packs/qr_code_pack.rb +37 -0
  101. data/lib/rails/metro/packs/r2_storage_pack.rb +48 -0
  102. data/lib/rails/metro/packs/rack_timeout_pack.rb +34 -0
  103. data/lib/rails/metro/packs/rails_i18n_pack.rb +31 -0
  104. data/lib/rails/metro/packs/ransack_pack.rb +29 -0
  105. data/lib/rails/metro/packs/rate_limiting_pack.rb +39 -0
  106. data/lib/rails/metro/packs/recaptcha_pack.rb +38 -0
  107. data/lib/rails/metro/packs/resend_pack.rb +37 -0
  108. data/lib/rails/metro/packs/revenuecat_pack.rb +36 -0
  109. data/lib/rails/metro/packs/rolify_pack.rb +32 -0
  110. data/lib/rails/metro/packs/rollbar_pack.rb +38 -0
  111. data/lib/rails/metro/packs/s3_storage_pack.rb +45 -0
  112. data/lib/rails/metro/packs/scenic_pack.rb +28 -0
  113. data/lib/rails/metro/packs/scheduling_pack.rb +46 -0
  114. data/lib/rails/metro/packs/search_pack.rb +32 -0
  115. data/lib/rails/metro/packs/security_pack.rb +30 -0
  116. data/lib/rails/metro/packs/sendgrid_pack.rb +44 -0
  117. data/lib/rails/metro/packs/sent_dm_pack.rb +36 -0
  118. data/lib/rails/metro/packs/seo_pack.rb +40 -0
  119. data/lib/rails/metro/packs/shoulda_matchers_pack.rb +37 -0
  120. data/lib/rails/metro/packs/sidekiq_pack.rb +42 -0
  121. data/lib/rails/metro/packs/simple_calendar_pack.rb +29 -0
  122. data/lib/rails/metro/packs/simple_form_pack.rb +30 -0
  123. data/lib/rails/metro/packs/simplecov_pack.rb +38 -0
  124. data/lib/rails/metro/packs/slack_notifier_pack.rb +36 -0
  125. data/lib/rails/metro/packs/soft_deletes_pack.rb +30 -0
  126. data/lib/rails/metro/packs/solidus_pack.rb +31 -0
  127. data/lib/rails/metro/packs/spreadsheets_pack.rb +29 -0
  128. data/lib/rails/metro/packs/statcounter_pack.rb +41 -0
  129. data/lib/rails/metro/packs/stimulus_components_pack.rb +33 -0
  130. data/lib/rails/metro/packs/storage_validations_pack.rb +28 -0
  131. data/lib/rails/metro/packs/strong_migrations_pack.rb +30 -0
  132. data/lib/rails/metro/packs/tagging_pack.rb +31 -0
  133. data/lib/rails/metro/packs/test_mocking_pack.rb +41 -0
  134. data/lib/rails/metro/packs/testing_pack.rb +39 -0
  135. data/lib/rails/metro/packs/twilio_pack.rb +38 -0
  136. data/lib/rails/metro/packs/vite_rails_pack.rb +31 -0
  137. data/lib/rails/metro/packs/web_push_pack.rb +39 -0
  138. data/lib/rails/metro/packs/webhooks_pack.rb +45 -0
  139. data/lib/rails/metro/packs/websockets_pack.rb +29 -0
  140. data/lib/rails/metro/template_compiler.rb +85 -0
  141. data/lib/rails/metro/tui/app.rb +119 -0
  142. data/lib/rails/metro/tui/steps/app_name_step.rb +57 -0
  143. data/lib/rails/metro/tui/steps/database_step.rb +53 -0
  144. data/lib/rails/metro/tui/steps/pack_step.rb +248 -0
  145. data/lib/rails/metro/tui/steps/review_step.rb +94 -0
  146. data/lib/rails/metro/tui/styles.rb +47 -0
  147. data/lib/rails/metro/tui.rb +37 -0
  148. data/lib/rails/metro/version.rb +5 -0
  149. data/lib/rails/metro.rb +9 -0
  150. metadata +206 -0
@@ -0,0 +1,41 @@
1
+ module Rails
2
+ module Metro
3
+ module Packs
4
+ class DatadogPack < FeaturePack
5
+ pack_name "datadog"
6
+ description "Datadog APM for tracing, metrics, and log management"
7
+ category "ops"
8
+
9
+ def gems
10
+ [
11
+ {name: "datadog"}
12
+ ]
13
+ end
14
+
15
+ def template_lines
16
+ [
17
+ 'create_file "config/initializers/datadog.rb", <<~RUBY',
18
+ " Datadog.configure do |c|",
19
+ " c.service = Rails.application.class.module_parent_name.underscore",
20
+ " c.env = Rails.env",
21
+ "",
22
+ " c.tracing.instrument :rails",
23
+ " c.tracing.instrument :http",
24
+ " c.tracing.instrument :active_record",
25
+ " c.tracing.instrument :redis if defined?(Redis)",
26
+ " c.tracing.instrument :sidekiq if defined?(Sidekiq)",
27
+ " end",
28
+ "RUBY"
29
+ ]
30
+ end
31
+
32
+ def post_install_notes
33
+ [
34
+ "Datadog: Install the Datadog Agent on your server (not a Ruby gem)",
35
+ "Datadog: Set DD_API_KEY and DD_ENV environment variables in production"
36
+ ]
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,30 @@
1
+ module Rails
2
+ module Metro
3
+ module Packs
4
+ class DeploymentPack < FeaturePack
5
+ pack_name "deployment"
6
+ description "Kamal for zero-downtime deploys to any Linux box"
7
+ category "ops"
8
+
9
+ def gems
10
+ [
11
+ {name: "kamal", version: "~> 2.0"}
12
+ ]
13
+ end
14
+
15
+ def template_lines
16
+ [
17
+ 'rails_command "generate kamal"'
18
+ ]
19
+ end
20
+
21
+ def post_install_notes
22
+ [
23
+ "Deployment: Edit config/deploy.yml with your server details",
24
+ "Deployment: Run `kamal setup` to provision, then `kamal deploy`"
25
+ ]
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,33 @@
1
+ module Rails
2
+ module Metro
3
+ module Packs
4
+ class DevisePack < FeaturePack
5
+ pack_name "devise"
6
+ description "Devise for full-featured authentication (OmniAuth, LDAP, etc.)"
7
+ category "core"
8
+ conflicts_with "authentication", "passwordless"
9
+
10
+ def gems
11
+ [
12
+ {name: "devise"}
13
+ ]
14
+ end
15
+
16
+ def template_lines
17
+ [
18
+ 'rails_command "generate devise:install"',
19
+ 'rails_command "generate devise User"'
20
+ ]
21
+ end
22
+
23
+ def post_install_notes
24
+ [
25
+ "Devise: Run `bin/rails db:migrate` to create users table",
26
+ "Devise: Generate views with `bin/rails g devise:views`",
27
+ "Devise: Configure mailer sender in config/initializers/devise.rb"
28
+ ]
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,32 @@
1
+ module Rails
2
+ module Metro
3
+ module Packs
4
+ class DoorkeeperPack < FeaturePack
5
+ pack_name "doorkeeper"
6
+ description "Doorkeeper for OAuth2 provider (issue tokens, authorize apps)"
7
+ category "api"
8
+
9
+ def gems
10
+ [
11
+ {name: "doorkeeper"}
12
+ ]
13
+ end
14
+
15
+ def template_lines
16
+ [
17
+ 'rails_command "generate doorkeeper:install"',
18
+ 'rails_command "generate doorkeeper:migration"'
19
+ ]
20
+ end
21
+
22
+ def post_install_notes
23
+ [
24
+ "Doorkeeper: Run `bin/rails db:migrate` to create OAuth tables",
25
+ "Doorkeeper: Configure resource owner in config/initializers/doorkeeper.rb",
26
+ "Doorkeeper: Manage OAuth apps at /oauth/applications"
27
+ ]
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,36 @@
1
+ module Rails
2
+ module Metro
3
+ module Packs
4
+ class DotenvPack < FeaturePack
5
+ pack_name "dotenv"
6
+ description "Dotenv for loading .env files in development"
7
+ category "ops"
8
+
9
+ def gems
10
+ [
11
+ {name: "dotenv-rails", group: :development}
12
+ ]
13
+ end
14
+
15
+ def template_lines
16
+ [
17
+ 'create_file ".env.example", <<~ENV',
18
+ " # Copy to .env and fill in values",
19
+ " # DATABASE_URL=postgres://localhost/myapp_development",
20
+ " # RAILS_MASTER_KEY=your_master_key",
21
+ "ENV",
22
+ "",
23
+ 'append_to_file ".gitignore", "\\n.env\\n.env.local\\n"'
24
+ ]
25
+ end
26
+
27
+ def post_install_notes
28
+ [
29
+ "Dotenv: Copy .env.example to .env and fill in your values",
30
+ "Dotenv: .env files are gitignored -- never commit secrets"
31
+ ]
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,31 @@
1
+ module Rails
2
+ module Metro
3
+ module Packs
4
+ class ElasticsearchPack < FeaturePack
5
+ pack_name "elasticsearch"
6
+ description "Searchkick for Elasticsearch-powered search"
7
+ category "data"
8
+ conflicts_with "search", "meilisearch"
9
+
10
+ def gems
11
+ [
12
+ {name: "searchkick"}
13
+ ]
14
+ end
15
+
16
+ def template_lines
17
+ []
18
+ end
19
+
20
+ def post_install_notes
21
+ [
22
+ "Searchkick: Install and run Elasticsearch (or OpenSearch)",
23
+ "Searchkick: Add `searchkick` to models you want to search",
24
+ "Searchkick: Reindex with `Model.reindex`",
25
+ "Searchkick: Search with `Model.search(\"query\")`"
26
+ ]
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,37 @@
1
+ module Rails
2
+ module Metro
3
+ module Packs
4
+ class EncryptionPack < FeaturePack
5
+ pack_name "encryption"
6
+ description "Lockbox for application-level field encryption"
7
+ category "data"
8
+
9
+ def gems
10
+ [
11
+ {name: "lockbox"},
12
+ {name: "blind_index"}
13
+ ]
14
+ end
15
+
16
+ def template_lines
17
+ [
18
+ 'create_file "config/initializers/lockbox.rb", <<~RUBY',
19
+ " Lockbox.master_key = Rails.application.credentials.dig(:lockbox, :master_key) || ENV[\"LOCKBOX_MASTER_KEY\"]",
20
+ "RUBY"
21
+ ]
22
+ end
23
+
24
+ def post_install_notes
25
+ [
26
+ "Lockbox: Generate a master key with `Lockbox.generate_key`",
27
+ "Lockbox: Add to credentials with `bin/rails credentials:edit`:",
28
+ " lockbox:",
29
+ " master_key: your_generated_key",
30
+ "Lockbox: Use `encrypts :email` in models to encrypt fields",
31
+ "Lockbox: Use `blind_index :email` for searchable encrypted fields"
32
+ ]
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,40 @@
1
+ module Rails
2
+ module Metro
3
+ module Packs
4
+ class ErrorTrackingPack < FeaturePack
5
+ pack_name "error_tracking"
6
+ description "Sentry for error tracking and performance monitoring"
7
+ category "ops"
8
+ conflicts_with "honeybadger", "rollbar"
9
+
10
+ def gems
11
+ [
12
+ {name: "sentry-ruby"},
13
+ {name: "sentry-rails"}
14
+ ]
15
+ end
16
+
17
+ def template_lines
18
+ [
19
+ 'create_file "config/initializers/sentry.rb", <<~RUBY',
20
+ " Sentry.init do |config|",
21
+ ' config.dsn = Rails.application.credentials.dig(:sentry, :dsn) || ENV["SENTRY_DSN"]',
22
+ " config.breadcrumbs_logger = [:active_support_logger, :http_logger]",
23
+ " config.traces_sample_rate = 0.1",
24
+ " config.profiles_sample_rate = 0.1",
25
+ " end",
26
+ "RUBY"
27
+ ]
28
+ end
29
+
30
+ def post_install_notes
31
+ [
32
+ "Sentry: Add your DSN with `bin/rails credentials:edit`:",
33
+ " sentry:",
34
+ " dsn: https://your-dsn@sentry.io/project-id"
35
+ ]
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,31 @@
1
+ module Rails
2
+ module Metro
3
+ module Packs
4
+ class EventSourcingPack < FeaturePack
5
+ pack_name "event_sourcing"
6
+ description "Rails Event Store for event sourcing and CQRS"
7
+ category "data"
8
+
9
+ def gems
10
+ [
11
+ {name: "rails_event_store"}
12
+ ]
13
+ end
14
+
15
+ def template_lines
16
+ [
17
+ 'rails_command "generate rails_event_store_active_record:install"'
18
+ ]
19
+ end
20
+
21
+ def post_install_notes
22
+ [
23
+ "Event Store: Run `bin/rails db:migrate` to create events table",
24
+ "Event Store: Publish events with `Rails.configuration.event_store.publish(event)`",
25
+ "Event Store: Browse events at /res if you mount the browser engine"
26
+ ]
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,42 @@
1
+ module Rails
2
+ module Metro
3
+ module Packs
4
+ class FaradayPack < FeaturePack
5
+ pack_name "faraday"
6
+ description "Faraday for composable HTTP client requests"
7
+ category "core"
8
+
9
+ def gems
10
+ [
11
+ {name: "faraday", version: "~> 2.0"},
12
+ {name: "faraday-retry"}
13
+ ]
14
+ end
15
+
16
+ def template_lines
17
+ [
18
+ 'create_file "app/clients/application_client.rb", <<~RUBY',
19
+ " class ApplicationClient",
20
+ " def connection",
21
+ " @connection ||= Faraday.new do |f|",
22
+ " f.request :json",
23
+ " f.response :json",
24
+ " f.request :retry, max: 2, interval: 0.5",
25
+ " f.adapter Faraday.default_adapter",
26
+ " end",
27
+ " end",
28
+ " end",
29
+ "RUBY"
30
+ ]
31
+ end
32
+
33
+ def post_install_notes
34
+ [
35
+ "Faraday: Base client class at app/clients/application_client.rb",
36
+ "Faraday: Create service-specific clients inheriting from ApplicationClient"
37
+ ]
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,36 @@
1
+ module Rails
2
+ module Metro
3
+ module Packs
4
+ class FathomPack < FeaturePack
5
+ pack_name "fathom"
6
+ description "Fathom -- simple, privacy-focused website analytics"
7
+ category "analytics"
8
+
9
+ def gems
10
+ []
11
+ end
12
+
13
+ def template_lines
14
+ [
15
+ 'create_file "app/views/layouts/_fathom.html.erb", <<~ERB',
16
+ ' <script src="https://cdn.usefathom.com/script.js" data-site="<%%= Rails.application.credentials.dig(:fathom, :site_id) || ENV["FATHOM_SITE_ID"] %>" defer></script>',
17
+ "ERB",
18
+ "",
19
+ 'inject_into_file "app/views/layouts/application.html.erb", after: "<head>\\n" do',
20
+ ' " <%= render \\"layouts/fathom\\" %>\\n"',
21
+ "end"
22
+ ]
23
+ end
24
+
25
+ def post_install_notes
26
+ [
27
+ "Fathom: Add your site ID with `bin/rails credentials:edit`:",
28
+ " fathom:",
29
+ " site_id: ABCDEFGH",
30
+ "Fathom: No cookie banner needed -- privacy-first, GDPR compliant"
31
+ ]
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,34 @@
1
+ module Rails
2
+ module Metro
3
+ module Packs
4
+ class FeatureFlagsPack < FeaturePack
5
+ pack_name "feature_flags"
6
+ description "Flipper for feature flags with web UI"
7
+ category "ops"
8
+
9
+ def gems
10
+ [
11
+ {name: "flipper"},
12
+ {name: "flipper-active_record"},
13
+ {name: "flipper-ui"}
14
+ ]
15
+ end
16
+
17
+ def template_lines
18
+ [
19
+ 'rails_command "generate flipper:setup"',
20
+ 'route "mount Flipper::UI.app(Flipper) => \\"/flipper\\""'
21
+ ]
22
+ end
23
+
24
+ def post_install_notes
25
+ [
26
+ "Feature Flags: Run `bin/rails db:migrate` to create Flipper tables",
27
+ "Feature Flags: Manage flags at /flipper",
28
+ "Feature Flags: Use `Flipper.enabled?(:my_feature)` in code"
29
+ ]
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,31 @@
1
+ module Rails
2
+ module Metro
3
+ module Packs
4
+ class FriendlyIdPack < FeaturePack
5
+ pack_name "friendly_id"
6
+ description "FriendlyId for human-readable URL slugs"
7
+ category "ui"
8
+
9
+ def gems
10
+ [
11
+ {name: "friendly_id", version: "~> 5.5"}
12
+ ]
13
+ end
14
+
15
+ def template_lines
16
+ [
17
+ 'rails_command "generate friendly_id"'
18
+ ]
19
+ end
20
+
21
+ def post_install_notes
22
+ [
23
+ "FriendlyId: Run `bin/rails db:migrate` to create slugs table",
24
+ "FriendlyId: Add `extend FriendlyId` and `friendly_id :name, use: :slugged` to models",
25
+ "FriendlyId: Use `User.friendly.find(\"john-doe\")` instead of `User.find(id)`"
26
+ ]
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,38 @@
1
+ module Rails
2
+ module Metro
3
+ module Packs
4
+ class GeocoderPack < FeaturePack
5
+ pack_name "geocoder"
6
+ description "Geocoder for address lookup, geocoding, and distance queries"
7
+ category "data"
8
+
9
+ def gems
10
+ [
11
+ {name: "geocoder"}
12
+ ]
13
+ end
14
+
15
+ def template_lines
16
+ [
17
+ 'create_file "config/initializers/geocoder.rb", <<~RUBY',
18
+ " Geocoder.configure(",
19
+ " timeout: 5,",
20
+ " lookup: :nominatim,",
21
+ " units: :mi,",
22
+ " cache: Rails.cache",
23
+ " )",
24
+ "RUBY"
25
+ ]
26
+ end
27
+
28
+ def post_install_notes
29
+ [
30
+ "Geocoder: Add `geocoded_by :address` to models with latitude/longitude columns",
31
+ "Geocoder: Use `Model.near(\"New York\", 50)` for proximity search",
32
+ "Geocoder: Default uses free Nominatim API -- switch to Google/Mapbox for production"
33
+ ]
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,34 @@
1
+ module Rails
2
+ module Metro
3
+ module Packs
4
+ class GoodJobPack < FeaturePack
5
+ pack_name "good_job"
6
+ description "GoodJob for Postgres-backed background jobs (no Redis needed)"
7
+ category "core"
8
+ conflicts_with "background_jobs", "sidekiq"
9
+
10
+ def gems
11
+ [
12
+ {name: "good_job", version: "~> 4.0"}
13
+ ]
14
+ end
15
+
16
+ def template_lines
17
+ [
18
+ 'environment "config.active_job.queue_adapter = :good_job"',
19
+ 'rails_command "generate good_job:install"',
20
+ 'route "mount GoodJob::Engine => \\"/good_job\\""'
21
+ ]
22
+ end
23
+
24
+ def post_install_notes
25
+ [
26
+ "GoodJob: Run `bin/rails db:migrate` to create job tables",
27
+ "GoodJob: Monitor jobs at /good_job",
28
+ "GoodJob: Supports cron-like recurring jobs via config/good_job.yml"
29
+ ]
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,42 @@
1
+ module Rails
2
+ module Metro
3
+ module Packs
4
+ class GoogleAnalyticsPack < FeaturePack
5
+ pack_name "google_analytics"
6
+ description "Google Analytics 4 (GA4) for web analytics"
7
+ category "analytics"
8
+
9
+ def gems
10
+ []
11
+ end
12
+
13
+ def template_lines
14
+ [
15
+ 'create_file "app/views/layouts/_google_analytics.html.erb", <<~ERB',
16
+ " <!-- Google Analytics 4 -->",
17
+ ' <script async src="https://www.googletagmanager.com/gtag/js?id=<%%= Rails.application.credentials.dig(:google_analytics, :measurement_id) || ENV["GA_MEASUREMENT_ID"] %>"></script>',
18
+ " <script>",
19
+ " window.dataLayer = window.dataLayer || [];",
20
+ " function gtag(){dataLayer.push(arguments);}",
21
+ ' gtag("js", new Date());',
22
+ ' gtag("config", "<%%= Rails.application.credentials.dig(:google_analytics, :measurement_id) || ENV["GA_MEASUREMENT_ID"] %>");',
23
+ " </script>",
24
+ "ERB",
25
+ "",
26
+ 'inject_into_file "app/views/layouts/application.html.erb", after: "<head>\\n" do',
27
+ ' " <%= render \\"layouts/google_analytics\\" %>\\n"',
28
+ "end"
29
+ ]
30
+ end
31
+
32
+ def post_install_notes
33
+ [
34
+ "Google Analytics: Add your measurement ID with `bin/rails credentials:edit`:",
35
+ " google_analytics:",
36
+ " measurement_id: G-XXXXXXXXXX"
37
+ ]
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,51 @@
1
+ module Rails
2
+ module Metro
3
+ module Packs
4
+ class GoogleTagManagerPack < FeaturePack
5
+ pack_name "google_tag_manager"
6
+ description "Google Tag Manager for managing analytics and marketing tags"
7
+ category "analytics"
8
+
9
+ def gems
10
+ []
11
+ end
12
+
13
+ def template_lines
14
+ [
15
+ 'create_file "app/views/layouts/_gtm_head.html.erb", <<~ERB',
16
+ " <!-- Google Tag Manager -->",
17
+ " <script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({\"gtm.start\":",
18
+ ' new Date().getTime(),event:"gtm.js"});var f=d.getElementsByTagName(s)[0],',
19
+ ' j=d.createElement(s),dl=l!="dataLayer"?"&l="+l:"";j.async=true;j.src=',
20
+ ' "https://www.googletagmanager.com/gtm.js?id="+i+dl;f.parentNode.insertBefore(j,f);',
21
+ ' })(window,document,"script","dataLayer","<%%= Rails.application.credentials.dig(:gtm, :container_id) || ENV["GTM_CONTAINER_ID"] %>");</script>',
22
+ "ERB",
23
+ "",
24
+ 'create_file "app/views/layouts/_gtm_body.html.erb", <<~ERB',
25
+ " <!-- Google Tag Manager (noscript) -->",
26
+ ' <noscript><iframe src="https://www.googletagmanager.com/ns.html?id=<%%= Rails.application.credentials.dig(:gtm, :container_id) || ENV["GTM_CONTAINER_ID"] %>"',
27
+ ' height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>',
28
+ "ERB",
29
+ "",
30
+ 'inject_into_file "app/views/layouts/application.html.erb", after: "<head>\\n" do',
31
+ ' " <%= render \\"layouts/gtm_head\\" %>\\n"',
32
+ "end",
33
+ "",
34
+ 'inject_into_file "app/views/layouts/application.html.erb", after: "<body>\\n" do',
35
+ ' " <%= render \\"layouts/gtm_body\\" %>\\n"',
36
+ "end"
37
+ ]
38
+ end
39
+
40
+ def post_install_notes
41
+ [
42
+ "GTM: Add your container ID with `bin/rails credentials:edit`:",
43
+ " gtm:",
44
+ " container_id: GTM-XXXXXXX",
45
+ "GTM: Manage all your analytics/marketing tags from the GTM dashboard"
46
+ ]
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,31 @@
1
+ module Rails
2
+ module Metro
3
+ module Packs
4
+ class GraphqlPack < FeaturePack
5
+ pack_name "graphql"
6
+ description "GraphQL API with graphql-ruby"
7
+ category "api"
8
+
9
+ def gems
10
+ [
11
+ {name: "graphql", version: "~> 2.0"}
12
+ ]
13
+ end
14
+
15
+ def template_lines
16
+ [
17
+ 'rails_command "generate graphql:install"'
18
+ ]
19
+ end
20
+
21
+ def post_install_notes
22
+ [
23
+ "GraphQL: Endpoint available at /graphql",
24
+ "GraphQL: Generate types with `bin/rails g graphql:object User`",
25
+ "GraphQL: GraphiQL IDE available in development at /graphiql"
26
+ ]
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end