source_monitor 0.1.1
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/.gitignore +16 -0
- data/.rubocop.yml +12 -0
- data/.ruby-version +1 -0
- data/AGENTS.md +132 -0
- data/CHANGELOG.md +66 -0
- data/CONTRIBUTING.md +31 -0
- data/Gemfile +30 -0
- data/Gemfile.lock +411 -0
- data/MIT-LICENSE +20 -0
- data/README.md +108 -0
- data/Rakefile +8 -0
- data/app/assets/builds/.keep +0 -0
- data/app/assets/config/source_monitor_manifest.js +4 -0
- data/app/assets/images/source_monitor/.keep +0 -0
- data/app/assets/javascripts/source_monitor/application.js +20 -0
- data/app/assets/javascripts/source_monitor/controllers/async_submit_controller.js +36 -0
- data/app/assets/javascripts/source_monitor/controllers/dropdown_controller.js +109 -0
- data/app/assets/javascripts/source_monitor/controllers/modal_controller.js +56 -0
- data/app/assets/javascripts/source_monitor/controllers/notification_controller.js +53 -0
- data/app/assets/javascripts/source_monitor/turbo_actions.js +13 -0
- data/app/assets/stylesheets/source_monitor/application.tailwind.css +13 -0
- data/app/assets/svgs/source_monitor/.keep +0 -0
- data/app/controllers/concerns/.keep +0 -0
- data/app/controllers/concerns/source_monitor/sanitizes_search_params.rb +81 -0
- data/app/controllers/source_monitor/application_controller.rb +62 -0
- data/app/controllers/source_monitor/dashboard_controller.rb +27 -0
- data/app/controllers/source_monitor/fetch_logs_controller.rb +9 -0
- data/app/controllers/source_monitor/health_controller.rb +10 -0
- data/app/controllers/source_monitor/items_controller.rb +116 -0
- data/app/controllers/source_monitor/logs_controller.rb +15 -0
- data/app/controllers/source_monitor/scrape_logs_controller.rb +9 -0
- data/app/controllers/source_monitor/source_bulk_scrapes_controller.rb +35 -0
- data/app/controllers/source_monitor/source_fetches_controller.rb +22 -0
- data/app/controllers/source_monitor/source_health_checks_controller.rb +34 -0
- data/app/controllers/source_monitor/source_health_resets_controller.rb +27 -0
- data/app/controllers/source_monitor/source_retries_controller.rb +22 -0
- data/app/controllers/source_monitor/source_turbo_responses.rb +115 -0
- data/app/controllers/source_monitor/sources_controller.rb +179 -0
- data/app/helpers/source_monitor/application_helper.rb +327 -0
- data/app/jobs/source_monitor/application_job.rb +13 -0
- data/app/jobs/source_monitor/fetch_feed_job.rb +117 -0
- data/app/jobs/source_monitor/item_cleanup_job.rb +48 -0
- data/app/jobs/source_monitor/log_cleanup_job.rb +47 -0
- data/app/jobs/source_monitor/schedule_fetches_job.rb +29 -0
- data/app/jobs/source_monitor/scrape_item_job.rb +47 -0
- data/app/jobs/source_monitor/source_health_check_job.rb +77 -0
- data/app/mailers/source_monitor/application_mailer.rb +17 -0
- data/app/models/concerns/.keep +0 -0
- data/app/models/concerns/source_monitor/loggable.rb +18 -0
- data/app/models/source_monitor/application_record.rb +5 -0
- data/app/models/source_monitor/fetch_log.rb +31 -0
- data/app/models/source_monitor/health_check_log.rb +28 -0
- data/app/models/source_monitor/item.rb +102 -0
- data/app/models/source_monitor/item_content.rb +11 -0
- data/app/models/source_monitor/log_entry.rb +56 -0
- data/app/models/source_monitor/scrape_log.rb +31 -0
- data/app/models/source_monitor/source.rb +115 -0
- data/app/views/layouts/source_monitor/application.html.erb +54 -0
- data/app/views/source_monitor/dashboard/_fetch_schedule.html.erb +90 -0
- data/app/views/source_monitor/dashboard/_job_metrics.html.erb +82 -0
- data/app/views/source_monitor/dashboard/_recent_activity.html.erb +39 -0
- data/app/views/source_monitor/dashboard/_stat_card.html.erb +6 -0
- data/app/views/source_monitor/dashboard/_stats.html.erb +9 -0
- data/app/views/source_monitor/dashboard/index.html.erb +48 -0
- data/app/views/source_monitor/fetch_logs/show.html.erb +90 -0
- data/app/views/source_monitor/items/_details.html.erb +234 -0
- data/app/views/source_monitor/items/_details_wrapper.html.erb +3 -0
- data/app/views/source_monitor/items/index.html.erb +147 -0
- data/app/views/source_monitor/items/show.html.erb +3 -0
- data/app/views/source_monitor/logs/index.html.erb +208 -0
- data/app/views/source_monitor/scrape_logs/show.html.erb +73 -0
- data/app/views/source_monitor/shared/_toast.html.erb +34 -0
- data/app/views/source_monitor/sources/_bulk_scrape_form.html.erb +64 -0
- data/app/views/source_monitor/sources/_bulk_scrape_modal.html.erb +53 -0
- data/app/views/source_monitor/sources/_details.html.erb +302 -0
- data/app/views/source_monitor/sources/_details_wrapper.html.erb +3 -0
- data/app/views/source_monitor/sources/_empty_state_row.html.erb +5 -0
- data/app/views/source_monitor/sources/_fetch_interval_heatmap.html.erb +46 -0
- data/app/views/source_monitor/sources/_form.html.erb +143 -0
- data/app/views/source_monitor/sources/_health_status_badge.html.erb +46 -0
- data/app/views/source_monitor/sources/_row.html.erb +102 -0
- data/app/views/source_monitor/sources/edit.html.erb +28 -0
- data/app/views/source_monitor/sources/index.html.erb +153 -0
- data/app/views/source_monitor/sources/new.html.erb +22 -0
- data/app/views/source_monitor/sources/show.html.erb +3 -0
- data/config/coverage_baseline.json +2010 -0
- data/config/initializers/feedjira.rb +19 -0
- data/config/routes.rb +18 -0
- data/config/tailwind.config.js +17 -0
- data/db/migrate/20241008120000_create_source_monitor_sources.rb +40 -0
- data/db/migrate/20241008121000_create_source_monitor_items.rb +44 -0
- data/db/migrate/20241008122000_create_source_monitor_fetch_logs.rb +32 -0
- data/db/migrate/20241008123000_create_source_monitor_scrape_logs.rb +25 -0
- data/db/migrate/20251008183000_change_fetch_interval_to_minutes.rb +23 -0
- data/db/migrate/20251009090000_create_source_monitor_item_contents.rb +38 -0
- data/db/migrate/20251009103000_add_feed_content_readability_to_sources.rb +5 -0
- data/db/migrate/20251010090000_add_adaptive_fetching_toggle_to_sources.rb +7 -0
- data/db/migrate/20251010123000_add_deleted_at_to_source_monitor_items.rb +8 -0
- data/db/migrate/20251010153000_add_type_to_source_monitor_sources.rb +8 -0
- data/db/migrate/20251010154500_add_fetch_status_to_source_monitor_sources.rb +9 -0
- data/db/migrate/20251010160000_create_solid_cable_messages.rb +16 -0
- data/db/migrate/20251011090000_add_fetch_retry_state_to_sources.rb +14 -0
- data/db/migrate/20251012090000_add_health_fields_to_sources.rb +17 -0
- data/db/migrate/20251012100000_optimize_source_monitor_database_performance.rb +13 -0
- data/db/migrate/20251014064947_add_not_null_constraints_to_items.rb +30 -0
- data/db/migrate/20251014171659_add_performance_indexes.rb +29 -0
- data/db/migrate/20251014172525_add_fetch_status_check_constraint.rb +18 -0
- data/db/migrate/20251015100000_create_source_monitor_log_entries.rb +89 -0
- data/db/migrate/20251022100000_create_source_monitor_health_check_logs.rb +22 -0
- data/db/migrate/20251108120116_refresh_fetch_status_constraint.rb +29 -0
- data/docs/configuration.md +170 -0
- data/docs/deployment.md +63 -0
- data/docs/gh-cli-workflow.md +44 -0
- data/docs/installation.md +144 -0
- data/docs/troubleshooting.md +76 -0
- data/eslint.config.mjs +27 -0
- data/lib/generators/source_monitor/install/install_generator.rb +59 -0
- data/lib/generators/source_monitor/install/templates/source_monitor.rb.tt +155 -0
- data/lib/source_monitor/analytics/source_activity_rates.rb +53 -0
- data/lib/source_monitor/analytics/source_fetch_interval_distribution.rb +57 -0
- data/lib/source_monitor/analytics/sources_index_metrics.rb +92 -0
- data/lib/source_monitor/assets/bundler.rb +49 -0
- data/lib/source_monitor/assets.rb +6 -0
- data/lib/source_monitor/configuration.rb +654 -0
- data/lib/source_monitor/dashboard/queries.rb +356 -0
- data/lib/source_monitor/dashboard/quick_action.rb +7 -0
- data/lib/source_monitor/dashboard/quick_actions_presenter.rb +26 -0
- data/lib/source_monitor/dashboard/recent_activity.rb +30 -0
- data/lib/source_monitor/dashboard/recent_activity_presenter.rb +77 -0
- data/lib/source_monitor/dashboard/turbo_broadcaster.rb +87 -0
- data/lib/source_monitor/dashboard/upcoming_fetch_schedule.rb +126 -0
- data/lib/source_monitor/engine.rb +107 -0
- data/lib/source_monitor/events.rb +110 -0
- data/lib/source_monitor/feedjira_extensions.rb +103 -0
- data/lib/source_monitor/fetching/advisory_lock.rb +54 -0
- data/lib/source_monitor/fetching/completion/event_publisher.rb +22 -0
- data/lib/source_monitor/fetching/completion/follow_up_handler.rb +37 -0
- data/lib/source_monitor/fetching/completion/retention_handler.rb +30 -0
- data/lib/source_monitor/fetching/feed_fetcher.rb +627 -0
- data/lib/source_monitor/fetching/fetch_error.rb +88 -0
- data/lib/source_monitor/fetching/fetch_runner.rb +142 -0
- data/lib/source_monitor/fetching/retry_policy.rb +85 -0
- data/lib/source_monitor/fetching/stalled_fetch_reconciler.rb +146 -0
- data/lib/source_monitor/health/source_health_check.rb +100 -0
- data/lib/source_monitor/health/source_health_monitor.rb +210 -0
- data/lib/source_monitor/health/source_health_reset.rb +68 -0
- data/lib/source_monitor/health.rb +46 -0
- data/lib/source_monitor/http.rb +85 -0
- data/lib/source_monitor/instrumentation.rb +52 -0
- data/lib/source_monitor/items/item_creator.rb +601 -0
- data/lib/source_monitor/items/retention_pruner.rb +146 -0
- data/lib/source_monitor/items/retention_strategies/destroy.rb +26 -0
- data/lib/source_monitor/items/retention_strategies/soft_delete.rb +50 -0
- data/lib/source_monitor/items/retention_strategies.rb +9 -0
- data/lib/source_monitor/jobs/cleanup_options.rb +85 -0
- data/lib/source_monitor/jobs/fetch_failure_subscriber.rb +129 -0
- data/lib/source_monitor/jobs/solid_queue_metrics.rb +199 -0
- data/lib/source_monitor/jobs/visibility.rb +133 -0
- data/lib/source_monitor/logs/entry_sync.rb +69 -0
- data/lib/source_monitor/logs/filter_set.rb +163 -0
- data/lib/source_monitor/logs/query.rb +81 -0
- data/lib/source_monitor/logs/table_presenter.rb +161 -0
- data/lib/source_monitor/metrics.rb +77 -0
- data/lib/source_monitor/model_extensions.rb +109 -0
- data/lib/source_monitor/models/sanitizable.rb +76 -0
- data/lib/source_monitor/models/url_normalizable.rb +84 -0
- data/lib/source_monitor/pagination/paginator.rb +90 -0
- data/lib/source_monitor/realtime/adapter.rb +97 -0
- data/lib/source_monitor/realtime/broadcaster.rb +237 -0
- data/lib/source_monitor/realtime.rb +17 -0
- data/lib/source_monitor/release/changelog.rb +59 -0
- data/lib/source_monitor/release/runner.rb +73 -0
- data/lib/source_monitor/scheduler.rb +82 -0
- data/lib/source_monitor/scrapers/base.rb +105 -0
- data/lib/source_monitor/scrapers/fetchers/http_fetcher.rb +97 -0
- data/lib/source_monitor/scrapers/parsers/readability_parser.rb +101 -0
- data/lib/source_monitor/scrapers/readability.rb +156 -0
- data/lib/source_monitor/scraping/bulk_result_presenter.rb +85 -0
- data/lib/source_monitor/scraping/bulk_source_scraper.rb +233 -0
- data/lib/source_monitor/scraping/enqueuer.rb +125 -0
- data/lib/source_monitor/scraping/item_scraper/adapter_resolver.rb +44 -0
- data/lib/source_monitor/scraping/item_scraper/persistence.rb +189 -0
- data/lib/source_monitor/scraping/item_scraper.rb +84 -0
- data/lib/source_monitor/scraping/scheduler.rb +43 -0
- data/lib/source_monitor/scraping/state.rb +79 -0
- data/lib/source_monitor/security/authentication.rb +85 -0
- data/lib/source_monitor/security/parameter_sanitizer.rb +42 -0
- data/lib/source_monitor/sources/turbo_stream_presenter.rb +54 -0
- data/lib/source_monitor/turbo_streams/stream_responder.rb +95 -0
- data/lib/source_monitor/version.rb +3 -0
- data/lib/source_monitor.rb +149 -0
- data/lib/tasks/recover_stalled_fetches.rake +16 -0
- data/lib/tasks/source_monitor_assets.rake +28 -0
- data/lib/tasks/source_monitor_tasks.rake +29 -0
- data/lib/tasks/test_smoke.rake +12 -0
- data/package-lock.json +3997 -0
- data/package.json +29 -0
- data/postcss.config.js +6 -0
- data/source_monitor.gemspec +46 -0
- data/stylelint.config.js +12 -0
- metadata +469 -0
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
# Configuration & API Reference
|
|
2
|
+
|
|
3
|
+
All configuration lives in `SourceMonitor.configure`—the install generator creates `config/initializers/source_monitor.rb` with sensible defaults and inline documentation. This guide expands on every namespace so you know which knobs to turn in production.
|
|
4
|
+
|
|
5
|
+
```ruby
|
|
6
|
+
SourceMonitor.configure do |config|
|
|
7
|
+
# customize settings here
|
|
8
|
+
end
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Restart your application whenever you change these settings. The engine reloads model extensions automatically when the block runs, but background processes need a restart to pick up queue name or adapter changes.
|
|
12
|
+
|
|
13
|
+
## Asset Bundling
|
|
14
|
+
|
|
15
|
+
- SourceMonitor ships with npm-based bundling via `cssbundling-rails` and `jsbundling-rails`; follow `.ai/engine-asset-configuration.md:11-113` when adjusting dependency versions or adding new entrypoints.
|
|
16
|
+
- Keep bundled outputs under the namespaced directories (`app/assets/builds/source_monitor`, `images/source_monitor`, `svgs/source_monitor`) so host apps avoid collisions. See `.ai/engine-asset-configuration.md:32-44` for the layout recommendations.
|
|
17
|
+
- Use `rbenv exec bundle exec rake app:source_monitor:assets:build` (or `npm run build`) after tweaking Tailwind/Stimulus code to refresh the builds, and rely on `test/dummy/bin/dev` to watch `build:css:watch` + `build:js:watch` during development.
|
|
18
|
+
- Sprockets hosts receive automatic precompile coverage; if a host prefers manifest-based precompilation, adapt the approach documented in `.ai/engine-asset-configuration.md:114-143`.
|
|
19
|
+
|
|
20
|
+
## Queue & Worker Settings
|
|
21
|
+
|
|
22
|
+
- `config.queue_namespace` – prefix applied to queue names (`"source_monitor"` by default)
|
|
23
|
+
- `config.fetch_queue_name` / `config.scrape_queue_name` – base queue names before the host's `ActiveJob.queue_name_prefix` is applied
|
|
24
|
+
- `config.fetch_queue_concurrency` / `config.scrape_queue_concurrency` – advisory values Solid Queue uses for per-queue limits
|
|
25
|
+
- `config.queue_name_for(:fetch | :scrape)` – helper that respects the host's queue prefix
|
|
26
|
+
|
|
27
|
+
Use the helpers exposed on `SourceMonitor`:
|
|
28
|
+
|
|
29
|
+
```ruby
|
|
30
|
+
SourceMonitor.queue_name(:fetch) # => "source_monitor_fetch"
|
|
31
|
+
SourceMonitor.queue_concurrency(:scrape) # => 2
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Job Metrics & Mission Control
|
|
35
|
+
|
|
36
|
+
- `config.job_metrics_enabled` – toggles Solid Queue metrics collection for the dashboard cards (default `true`)
|
|
37
|
+
- `config.mission_control_enabled` – surfaces the Mission Control link on the dashboard when `true`
|
|
38
|
+
- `config.mission_control_dashboard_path` – host route helper or callable returning the Mission Control path/URL; left blank by default
|
|
39
|
+
|
|
40
|
+
The helper `SourceMonitor.mission_control_dashboard_path` performs a routing check so the dashboard only renders links that resolve.
|
|
41
|
+
|
|
42
|
+
## HTTP Client Settings
|
|
43
|
+
|
|
44
|
+
`config.http` maps directly onto Faraday's middleware options.
|
|
45
|
+
|
|
46
|
+
- `timeout` – total request timeout in seconds (default `15`)
|
|
47
|
+
- `open_timeout` – connection open timeout in seconds (`5`)
|
|
48
|
+
- `max_redirects` – maximum redirects to follow (`5`)
|
|
49
|
+
- `user_agent` – defaults to `SourceMonitor/<version>`
|
|
50
|
+
- `proxy` – hash or URL to configure proxy usage
|
|
51
|
+
- `headers` – hash (or callables) merged into every request
|
|
52
|
+
- `retry_max`, `retry_interval`, `retry_interval_randomness`, `retry_backoff_factor`, `retry_statuses` – mapped to `faraday-retry`
|
|
53
|
+
|
|
54
|
+
## Fetching Behaviour
|
|
55
|
+
|
|
56
|
+
`config.fetching` controls adaptive scheduling.
|
|
57
|
+
|
|
58
|
+
- `min_interval_minutes` / `max_interval_minutes` – enforce floor/ceiling for automatic schedule adjustments (defaults: `5` and `1440`)
|
|
59
|
+
- `increase_factor` / `decrease_factor` – multipliers when a source trends slow/fast
|
|
60
|
+
- `failure_increase_factor` – multiplier applied on consecutive failures
|
|
61
|
+
- `jitter_percent` – random jitter applied to next fetch time (0.1 = ±10%)
|
|
62
|
+
|
|
63
|
+
## Retention Defaults
|
|
64
|
+
|
|
65
|
+
`config.retention` sets global defaults that sources inherit when their fields are blank.
|
|
66
|
+
|
|
67
|
+
- `items_retention_days` – prune items older than this many days (`nil` = retain forever)
|
|
68
|
+
- `max_items` – keep only the most recent N items (`nil` = unlimited)
|
|
69
|
+
- `strategy` – `:destroy` or `:soft_delete` (defaults to `:destroy` in the configuration class; the installer comments demonstrate `:soft_delete`)
|
|
70
|
+
|
|
71
|
+
The retention pruner runs after every successful fetch and inside nightly cleanup jobs.
|
|
72
|
+
|
|
73
|
+
## Scraper Registry
|
|
74
|
+
|
|
75
|
+
Register adapters that inherit from `SourceMonitor::Scrapers::Base`:
|
|
76
|
+
|
|
77
|
+
```ruby
|
|
78
|
+
config.scrapers.register(:readability, SourceMonitor::Scrapers::Readability)
|
|
79
|
+
config.scrapers.register(:custom, "MyApp::Scrapers::Premium" )
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Adapters receive merged settings (`default -> source -> invocation`), and must return a `SourceMonitor::Scrapers::Result` object. Use `config.scrapers.unregister(:custom)` to remove overrides.
|
|
83
|
+
|
|
84
|
+
## Events & Item Processors
|
|
85
|
+
|
|
86
|
+
Respond to lifecycle events without monkey patching:
|
|
87
|
+
|
|
88
|
+
```ruby
|
|
89
|
+
config.events.after_item_created do |event|
|
|
90
|
+
Analytics.track_new_item(event.item, source: event.source)
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
config.events.after_fetch_completed do |event|
|
|
94
|
+
Rails.logger.info("Feed #{event.source.name} finished with #{event.status}")
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
config.events.register_item_processor ->(context) {
|
|
98
|
+
SearchIndexer.index(context.item)
|
|
99
|
+
}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Event structs expose `item`, `source`, `entry`, `result`, `status`, and `occurred_at`. Item processors run after events and receive an `ItemProcessorContext` with the same shape.
|
|
103
|
+
|
|
104
|
+
## Model Extensions
|
|
105
|
+
|
|
106
|
+
`config.models` lets host apps customise engine models at load time.
|
|
107
|
+
|
|
108
|
+
- `config.models.table_name_prefix` – override the default `sourcemon_` prefix
|
|
109
|
+
- `config.models.source.include_concern "MyApp::SourceMonitor::SourceExtensions"` – mix in concerns before models load
|
|
110
|
+
- `config.models.source.validate :ensure_metadata_rules` – register validations (blocks or symbols)
|
|
111
|
+
- Equivalent hooks exist for items, fetch logs, scrape logs, and item content via `config.models.item`, etc.
|
|
112
|
+
|
|
113
|
+
The engine reloads model extensions whenever configuration runs so code reloading in development continues to work.
|
|
114
|
+
|
|
115
|
+
## Realtime Settings
|
|
116
|
+
|
|
117
|
+
`config.realtime` governs Action Cable transport.
|
|
118
|
+
|
|
119
|
+
- `config.realtime.adapter` – one of `:solid_cable`, `:redis`, or `:async`
|
|
120
|
+
- `config.realtime.redis_url` – optional Redis URL when using the Redis adapter
|
|
121
|
+
- `config.realtime.solid_cable` – yields options: `polling_interval`, `message_retention`, `autotrim`, `use_skip_locked`, `trim_batch_size`, `connects_to` (hash for multi-database setups), `silence_polling`
|
|
122
|
+
|
|
123
|
+
Call `config.realtime.action_cable_config` if you need a full hash for environment-specific `cable.yml` generation.
|
|
124
|
+
|
|
125
|
+
## Authentication Helpers
|
|
126
|
+
|
|
127
|
+
Protect the dashboard with host-specific auth in one place:
|
|
128
|
+
|
|
129
|
+
```ruby
|
|
130
|
+
config.authentication.authenticate_with :authenticate_admin!
|
|
131
|
+
config.authentication.authorize_with ->(controller) {
|
|
132
|
+
controller.current_user&.feature_enabled?(:source_monitor)
|
|
133
|
+
}
|
|
134
|
+
config.authentication.current_user_method = :current_user
|
|
135
|
+
config.authentication.user_signed_in_method = :user_signed_in?
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Handlers can be symbols (invoked on the controller) or callables. Return `false` or raise to deny access.
|
|
139
|
+
|
|
140
|
+
## Health Model
|
|
141
|
+
|
|
142
|
+
`config.health` tunes automatic pause/resume heuristics.
|
|
143
|
+
|
|
144
|
+
- `window_size` – number of fetch attempts to evaluate (default `20`)
|
|
145
|
+
- `healthy_threshold` / `warning_threshold` – ratios that drive UI badges
|
|
146
|
+
- `auto_pause_threshold` / `auto_resume_threshold` – percentages that trigger automatic toggling
|
|
147
|
+
- `auto_pause_cooldown_minutes` – grace period before re-enabling a source
|
|
148
|
+
|
|
149
|
+
## Helper APIs
|
|
150
|
+
|
|
151
|
+
- `SourceMonitor.configure` – run-time configuration entry point
|
|
152
|
+
- `SourceMonitor.reset_configuration!` – revert to defaults (useful in tests)
|
|
153
|
+
- `SourceMonitor.events` – direct access to the events registry
|
|
154
|
+
- `SourceMonitor.queue_name(role)` / `SourceMonitor.queue_concurrency(role)` – convenience helpers
|
|
155
|
+
- `SourceMonitor::Metrics.snapshot` – inspect counters/gauges (great for health checks)
|
|
156
|
+
|
|
157
|
+
## Environment Variables
|
|
158
|
+
|
|
159
|
+
The engine honours several environment variables out of the box:
|
|
160
|
+
|
|
161
|
+
- `SOLID_QUEUE_SKIP_RECURRING` – skip loading `config/recurring.yml`
|
|
162
|
+
- `SOLID_QUEUE_RECURRING_SCHEDULE_FILE` – alternative schedule file path
|
|
163
|
+
- `SOFT_DELETE` / `SOURCE_IDS` / `SOURCE_ID` – overrides for item cleanup rake tasks
|
|
164
|
+
- `FETCH_LOG_DAYS` / `SCRAPE_LOG_DAYS` – retention windows for log cleanup
|
|
165
|
+
|
|
166
|
+
## After Changing Configuration
|
|
167
|
+
|
|
168
|
+
1. Restart web and worker processes so Solid Queue picks up new queue names/adapters.
|
|
169
|
+
2. Re-run `npm run build` (engine root) and `bin/rails assets:precompile` if you adjust engine assets per `.ai/engine-asset-configuration.md:11-188`.
|
|
170
|
+
3. Keep a regression test per configuration extension—for example, ensure custom validations are exercised in MiniTest.
|
data/docs/deployment.md
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# Deployment Guide
|
|
2
|
+
|
|
3
|
+
This guide captures the production considerations for running SourceMonitor inside a host Rails application. Pair it with your platform playbook (Heroku, Render, Kubernetes, etc.) for environment-specific instructions.
|
|
4
|
+
|
|
5
|
+
## Build & Release Pipeline
|
|
6
|
+
|
|
7
|
+
> **Ruby version management in production:** Use rbenv, asdf, or the Ruby version baked into your container image, depending on your deployment platform. The commands below are shown without version manager prefixes—adjust for your environment (e.g., `rbenv exec bundle install`, `asdf exec bundle install`, or bare `bundle install` in Docker).
|
|
8
|
+
|
|
9
|
+
1. **Install dependencies** – use `bundle install` and `npm install` during build steps.
|
|
10
|
+
2. **Copy and run migrations** – always run `bin/rails railties:install:migrations FROM=source_monitor` before `bin/rails db:migrate` so new engine tables ship with each release.
|
|
11
|
+
3. **Precompile assets** – `bin/rails assets:precompile` pulls in SourceMonitor's bundled CSS/JS outputs and Stimulus controllers. Fail the build if `source_monitor:assets:verify` raises.
|
|
12
|
+
4. **Run quality gates** – `bin/rubocop`, `bin/brakeman --no-pager`, `bin/lint-assets`, and `bin/test-coverage` mirror the repository CI setup.
|
|
13
|
+
|
|
14
|
+
## Process Model
|
|
15
|
+
|
|
16
|
+
SourceMonitor assumes the standard Rails 8 process split:
|
|
17
|
+
|
|
18
|
+
- **Web** – your application server (Puma) serving the mounted engine and Action Cable. When using Solid Cable, no separate Redis process is required.
|
|
19
|
+
- **Worker** – at least one Solid Queue worker (`bin/rails solid_queue:start`). Scale horizontally to match feed volume and retention pruning needs. Use queue selectors if you dedicate workers to `source_monitor_fetch` or `source_monitor_scrape`.
|
|
20
|
+
- **Scheduler/Recurring** – optional process invoking `bin/jobs --recurring_schedule_file=config/recurring.yml` so the bundled recurring tasks enqueue fetch/scrape/cleanup jobs. Disable with `SOLID_QUEUE_SKIP_RECURRING=true` when another scheduler handles cron-style jobs.
|
|
21
|
+
|
|
22
|
+
## Database & Storage
|
|
23
|
+
|
|
24
|
+
- **Primary Database** – hosts sources, items, logs, and Solid Cable messages. Ensure autovacuum keeps up; retention pruning helps bound growth.
|
|
25
|
+
- **Solid Queue Database (optional)** – create a dedicated connection via `rails solid_queue:install` if queue load warrants isolation. Update the generated config before running migrations.
|
|
26
|
+
- **Backups** – include Solid Queue tables in backups if they share the primary database; they store job state.
|
|
27
|
+
|
|
28
|
+
## Observability & Alerting
|
|
29
|
+
|
|
30
|
+
- Subscribe to ActiveSupport notifications (`source_monitor.fetch.finish`, `source_monitor.scheduler.run`, `source_monitor.dashboard.*`) to emit logs or metrics into your monitoring stack.
|
|
31
|
+
- Scrape `SourceMonitor::Metrics.snapshot` periodically (e.g., via a health check controller) to track counters and gauges in Prometheus or StatsD.
|
|
32
|
+
- Mission Control integration becomes useful once queues exceed a few hundred jobs; enable it when your platform already hosts the Mission Control UI.
|
|
33
|
+
|
|
34
|
+
## Security & Authentication
|
|
35
|
+
|
|
36
|
+
- Lock down the engine routes with authentication hooks (`config.authentication.authenticate_with` / `authorize_with`).
|
|
37
|
+
- Configure HTTPS for Action Cable if you expose Solid Cable over the public internet.
|
|
38
|
+
- Store API keys for authenticated feeds in encrypted credentials and inject them via per-source custom headers.
|
|
39
|
+
|
|
40
|
+
## Scaling Guidelines
|
|
41
|
+
|
|
42
|
+
- Increase `config.fetch_queue_concurrency` and the number of Solid Queue workers as source volume grows.
|
|
43
|
+
- Adjust `config.fetching` multipliers to smooth out noisy feeds; raising `failure_increase_factor` slows retries for consistently failing sources.
|
|
44
|
+
- Use `config.retention` to cap database growth; nightly cleanup jobs can run on separate workers if pruning becomes heavy.
|
|
45
|
+
|
|
46
|
+
## Rolling Upgrades
|
|
47
|
+
|
|
48
|
+
1. Merge and deploy code.
|
|
49
|
+
2. Run migrations before restarting workers so new tables/columns exist before jobs enqueue.
|
|
50
|
+
3. Restart Solid Queue workers after deploy so they load updated configuration and code.
|
|
51
|
+
4. Verify the dashboard loads, queue counts appear, and Mission Control links resolve when enabled.
|
|
52
|
+
|
|
53
|
+
## Disaster Recovery Checklist
|
|
54
|
+
|
|
55
|
+
- Restore the database, then replay any external feed data if necessary (SourceMonitor deduplicates using GUID/fingerprint).
|
|
56
|
+
- Resume Solid Queue workers and monitor `fetch_failed_total` gauge for anomalies.
|
|
57
|
+
- Rebuild assets if you deploy to ephemeral filesystems.
|
|
58
|
+
|
|
59
|
+
Keep this guide alongside your platform runbooks so teams can confidently deploy and operate SourceMonitor in any environment.
|
|
60
|
+
|
|
61
|
+
## Container Reference Stack
|
|
62
|
+
|
|
63
|
+
The repository ships a reusable Docker stack under `examples/docker` that mirrors the recommended process model. It builds a Ruby 3.3 image with Node, mounts your generated example via `APP_PATH`, and launches three services (`web`, `worker`, `scheduler`) alongside Postgres and Redis. Use it to trial production settings locally or as a baseline for ECS/Kubernetes manifests.
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# GitHub CLI Workflow for Branches & Pull Requests
|
|
2
|
+
|
|
3
|
+
Use this checklist whenever you create or land a slice. It keeps `gh` commands predictable and avoids redo steps.
|
|
4
|
+
|
|
5
|
+
## 1. Prep local branch
|
|
6
|
+
1. `git checkout main && git fetch origin && git reset --hard origin/main`
|
|
7
|
+
2. `git checkout -b <feature|bugfix>/<description>`
|
|
8
|
+
3. Do the work, run tests/lint, then `git commit -am "scope: summary"`
|
|
9
|
+
4. Push: `git push -u origin <branch>`
|
|
10
|
+
|
|
11
|
+
## 2. Open a PR (as draft)
|
|
12
|
+
1. `gh pr create --base main --head <branch> --title "scope: summary" --body "## Summary\n..." --draft`
|
|
13
|
+
2. `gh pr view --json url,isDraft` (confirm association & draft status)
|
|
14
|
+
|
|
15
|
+
## 3. Iterate on the PR
|
|
16
|
+
1. Additional commits → `git push`
|
|
17
|
+
2. `gh pr status` shows open PRs for the current branch.
|
|
18
|
+
|
|
19
|
+
## 4. Move PR out of draft
|
|
20
|
+
1. Check draft flag: `gh pr view <number> --json isDraft`
|
|
21
|
+
2. If true, run `gh pr ready <number>`.
|
|
22
|
+
3. Request reviews: `gh pr ready <number> --reviewer user1,user2`
|
|
23
|
+
|
|
24
|
+
## 5. Merge steps
|
|
25
|
+
1. Ensure PR is not draft & CI green: `gh pr checks <number>`
|
|
26
|
+
2. Merge via GitHub (avoids local fast-forward issues):
|
|
27
|
+
```bash
|
|
28
|
+
gh pr merge <number> --squash --delete-branch --auto
|
|
29
|
+
```
|
|
30
|
+
`--auto` queues the merge once requirements are satisfied. Drop `--auto` only if you intend to merge immediately and have maintainer privileges.
|
|
31
|
+
|
|
32
|
+
## 6. Local cleanup
|
|
33
|
+
1. `git checkout main`
|
|
34
|
+
2. `git pull --ff-only origin main`
|
|
35
|
+
3. Delete local branch: `git branch -d <branch>`
|
|
36
|
+
4. Optional: `git remote prune origin`
|
|
37
|
+
|
|
38
|
+
## 7. Handy status commands
|
|
39
|
+
- `gh pr status` – current branch PR state
|
|
40
|
+
- `gh pr view <number> --json url,state,isDraft` – PR summary
|
|
41
|
+
- `gh pr checks <number>` – CI state
|
|
42
|
+
- `gh pr list --author @me` – open PRs authored by you
|
|
43
|
+
|
|
44
|
+
Keep this document in `docs/gh-cli-workflow.md` and update it as our process evolves.
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
# Installation Guide
|
|
2
|
+
|
|
3
|
+
SourceMonitor installs like any other Rails engine, but it ships enough infrastructure (background jobs, realtime broadcasting, configuration DSL) that it is worth walking through the full setup. This guide assumes you are adding the engine to an existing Rails 8 host application.
|
|
4
|
+
|
|
5
|
+
## Prerequisites
|
|
6
|
+
|
|
7
|
+
- Ruby 3.4.4 (we recommend [rbenv](https://github.com/rbenv/rbenv) for local development: `rbenv install 3.4.4 && rbenv local 3.4.4`, but asdf, chruby, rvm, or container-managed Ruby all work equally well—choose whatever fits your environment)
|
|
8
|
+
- Rails 8.0.2.1 or newer
|
|
9
|
+
- PostgreSQL 13 or newer (the engine migrations rely on JSONB, SKIP LOCKED, and advisory locks)
|
|
10
|
+
- Node.js 18+ and npm or Yarn for asset linting/builds
|
|
11
|
+
- Solid Queue and Solid Cable gems available (they ship with Rails 8, but make sure they are not removed)
|
|
12
|
+
- Optional: Mission Control Jobs if you plan to surface the dashboard shortcut, Redis if you intend to switch realtime adapters
|
|
13
|
+
|
|
14
|
+
> **Command prefixes:** All commands below are shown without `rbenv exec`. If you use rbenv, prefix `bundle` and `bin/rails` commands with `rbenv exec`. For asdf, no prefix is needed. In Docker/container environments, run commands directly inside the container.
|
|
15
|
+
|
|
16
|
+
## Quick Reference
|
|
17
|
+
|
|
18
|
+
| Step | Command | Purpose |
|
|
19
|
+
| --- | --- | --- |
|
|
20
|
+
| 1 | `gem "source_monitor", github: "dchuk/source_monitor"` | Add the engine to your Gemfile |
|
|
21
|
+
| 2 | `bundle install` | Install Ruby dependencies |
|
|
22
|
+
| 3 | `bin/rails generate source_monitor:install --mount-path=/source_monitor` | Mount the engine and create the initializer |
|
|
23
|
+
| 4 | `bin/rails railties:install:migrations FROM=source_monitor` | Copy engine migrations (idempotent) |
|
|
24
|
+
| 5 | `bin/rails db:migrate` | Apply schema updates, including Solid Queue tables |
|
|
25
|
+
| 6 | `bin/rails solid_queue:start` | Ensure jobs process via Solid Queue |
|
|
26
|
+
| 7 | `bin/jobs --recurring_schedule_file=config/recurring.yml` | Start recurring scheduler (optional but recommended) |
|
|
27
|
+
|
|
28
|
+
## 1. Add the Gem
|
|
29
|
+
|
|
30
|
+
In your host application's `Gemfile`:
|
|
31
|
+
|
|
32
|
+
```ruby
|
|
33
|
+
gem "source_monitor", github: "dchuk/source_monitor"
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Then install dependencies:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
bundle install
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
If you vendor node tooling for linting/assets in the host app, run `npm install` as well.
|
|
43
|
+
|
|
44
|
+
## 2. Run the Install Generator
|
|
45
|
+
|
|
46
|
+
The generator mounts the engine and drops an initializer stub for you to configure.
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
bin/rails generate source_monitor:install --mount-path=/source_monitor
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Key outputs:
|
|
53
|
+
|
|
54
|
+
- Adds `mount SourceMonitor::Engine, at: "/source_monitor"` to your routes (change the path with `--mount-path`)
|
|
55
|
+
- Creates `config/initializers/source_monitor.rb` with documented configuration defaults
|
|
56
|
+
- The generator is idempotent: re-running it will detect existing mounts/initializers and skip overwriting your customizations
|
|
57
|
+
- Update your navigation or admin layout to link to the mount path so teammates can discover the dashboard.
|
|
58
|
+
|
|
59
|
+
## 3. Copy Engine Migrations
|
|
60
|
+
|
|
61
|
+
SourceMonitor relies on several tables (sources, items, fetch logs, scrape logs, Solid Cable messages, retention helpers) plus an optional Solid Queue schema. Copy them into your host application with:
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
bin/rails railties:install:migrations FROM=source_monitor
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
This command is idempotent—re-run it when upgrading to pick up new migrations.
|
|
68
|
+
|
|
69
|
+
## 4. Run Database Migrations
|
|
70
|
+
|
|
71
|
+
Apply the new schema:
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
bin/rails db:migrate
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
If you prefer a dedicated database for Solid Queue, run `bin/rails solid_queue:install` beforehand and point the generated config at your queue database. Otherwise the engine-provided migration keeps Solid Queue tables in the primary database.
|
|
78
|
+
|
|
79
|
+
> Tip: Solid Queue tables must be present before you start the dashboard. If your host app already ran `solid_queue:install`, delete the engine-provided migration before running `db:migrate` to avoid duplication.
|
|
80
|
+
|
|
81
|
+
## 5. Wire Action Cable (if needed)
|
|
82
|
+
|
|
83
|
+
SourceMonitor defaults to Solid Cable for realtime. Rails expects `ApplicationCable::Connection` and `ApplicationCable::Channel` to exist in your host app:
|
|
84
|
+
|
|
85
|
+
```ruby
|
|
86
|
+
# app/channels/application_cable/connection.rb
|
|
87
|
+
module ApplicationCable
|
|
88
|
+
class Connection < ActionCable::Connection::Base; end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# app/channels/application_cable/channel.rb
|
|
92
|
+
module ApplicationCable
|
|
93
|
+
class Channel < ActionCable::Channel::Base; end
|
|
94
|
+
end
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Verify `config/cable.yml` allows the adapter you choose. To switch to Redis, update `config/initializers/source_monitor.rb` with `config.realtime.adapter = :redis` and provide `config.realtime.redis_url`.
|
|
98
|
+
|
|
99
|
+
## 6. Configure Background Workers
|
|
100
|
+
|
|
101
|
+
Solid Queue becomes the default Active Job adapter when the host app still uses `:async`. Keep at least one worker process running:
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
# long-running process
|
|
105
|
+
bin/rails solid_queue:start
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
SourceMonitor respects explicit queue adapter overrides. If your host sets `config.active_job.queue_adapter` (for example, to `:inline` or `:sidekiq`), the engine leaves that configuration in place.
|
|
109
|
+
|
|
110
|
+
For recurring schedules, add a process that runs the Solid Queue CLI with the engine's schedule file:
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
bin/jobs --recurring_schedule_file=config/recurring.yml
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Set `SOLID_QUEUE_SKIP_RECURRING=true` in environments that manage recurring tasks elsewhere.
|
|
117
|
+
|
|
118
|
+
## 7. Review Configuration Defaults
|
|
119
|
+
|
|
120
|
+
Open `config/initializers/source_monitor.rb` and adjust queue namespaces, HTTP timeouts, scraping adapters, retention limits, authentication hooks, and Mission Control integration to match your environment. The [configuration reference](configuration.md) covers every option with examples.
|
|
121
|
+
|
|
122
|
+
## 8. Verify the Installation
|
|
123
|
+
|
|
124
|
+
1. Start your Rails server: `bin/rails server`
|
|
125
|
+
2. Ensure a Solid Queue worker is running (see step 6)
|
|
126
|
+
3. Visit the mount path (`/source_monitor` by default)
|
|
127
|
+
4. Create a source and trigger `Fetch Now`—watch fetch logs appear and dashboard metrics update
|
|
128
|
+
|
|
129
|
+
If you encounter issues, consult the [troubleshooting guide](troubleshooting.md).
|
|
130
|
+
|
|
131
|
+
## Next Steps
|
|
132
|
+
|
|
133
|
+
- Explore the admin UI and dashboards
|
|
134
|
+
- Integrate custom scraper adapters or item processors via `SourceMonitor.configure`
|
|
135
|
+
- Set up monitoring for the Solid Queue queues using Mission Control or your preferred observability stack
|
|
136
|
+
|
|
137
|
+
## Host Compatibility Matrix
|
|
138
|
+
|
|
139
|
+
| Host Scenario | Status | Notes |
|
|
140
|
+
| --- | --- | --- |
|
|
141
|
+
| Rails 8 full-stack app | ✅ Supported | Default generator flow (mount + initializer) |
|
|
142
|
+
| Rails 8 API-only app (`--api`) | ✅ Supported | Generator mounts engine; ensure you provide a UI entry point if needed |
|
|
143
|
+
| Dedicated Solid Queue database | ✅ Supported | Run `bin/rails solid_queue:install` in the host app before copying SourceMonitor migrations |
|
|
144
|
+
| Redis-backed Action Cable | ✅ Supported | Set `config.realtime.adapter = :redis` and provide `config.realtime.redis_url`; existing `config/cable.yml` entries are preserved |
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# Troubleshooting Guide
|
|
2
|
+
|
|
3
|
+
This guide lists common issues you might encounter while installing, upgrading, or operating SourceMonitor, along with concrete steps to resolve them.
|
|
4
|
+
|
|
5
|
+
## 1. Mount Path Returns 404
|
|
6
|
+
|
|
7
|
+
- Ensure the install generator added `mount SourceMonitor::Engine, at: "/source_monitor"` (or your custom path) inside the host `config/routes.rb`.
|
|
8
|
+
- Restart the Rails server after modifying routes.
|
|
9
|
+
- Confirm your host application routes are reloaded (run `rbenv exec bin/rails routes | grep source_monitor`).
|
|
10
|
+
|
|
11
|
+
## 2. Migrations or Solid Queue Tables Are Missing
|
|
12
|
+
|
|
13
|
+
- Run `rbenv exec bin/rails railties:install:migrations FROM=source_monitor` followed by `rbenv exec bin/rails db:migrate`.
|
|
14
|
+
- If you see duplicate migration timestamps, remove the older copy before rerunning the installer.
|
|
15
|
+
- For Solid Queue tables, verify the host database contains the `solid_queue_*` tables shipped with the engine migration or run `rbenv exec bin/rails solid_queue:install` for a dedicated queue database.
|
|
16
|
+
|
|
17
|
+
## 3. Dashboard Metrics Show "Unavailable"
|
|
18
|
+
|
|
19
|
+
- Solid Queue metrics require the `solid_queue` tables—see issue 2 above.
|
|
20
|
+
- Ensure at least one Solid Queue worker is running; the dashboard reads visibility data via `SourceMonitor::Jobs::Visibility`.
|
|
21
|
+
- When using mission control integration, keep `config.mission_control_dashboard_path` pointing at a valid route helper; otherwise the dashboard hides the link.
|
|
22
|
+
|
|
23
|
+
## 4. Realtime Updates Do Not Stream
|
|
24
|
+
|
|
25
|
+
- Confirm Action Cable is mounted and `ApplicationCable` classes exist (see installation guide).
|
|
26
|
+
- In production, verify WebSocket proxy settings allow the `/cable` endpoint.
|
|
27
|
+
- When switching to Redis, add `config.realtime.adapter = :redis` and `config.realtime.redis_url` in the initializer, then restart web and worker processes.
|
|
28
|
+
- For Solid Cable, check that the `solid_cable_messages` table exists and that no other process clears it unexpectedly.
|
|
29
|
+
|
|
30
|
+
## 5. Fetch Jobs Keep Failing
|
|
31
|
+
|
|
32
|
+
- Review the most recent fetch log entry for the source; it stores the HTTP status, error class, and error message.
|
|
33
|
+
- Increase `config.http.timeout` or `config.http.retry_max` if the feed is slow or prone to transient errors.
|
|
34
|
+
- Supply custom headers or basic auth credentials via the source form when feeds require authentication.
|
|
35
|
+
- Check for TLS issues on self-signed feeds; you may need to configure Faraday with custom SSL options.
|
|
36
|
+
|
|
37
|
+
## 6. Scraping Returns "Failed"
|
|
38
|
+
|
|
39
|
+
- Confirm the source has scraping enabled and the configured adapter exists.
|
|
40
|
+
- Override selectors in the source's scrape settings if the default Readability extraction misses key elements.
|
|
41
|
+
- Inspect the scrape log to see the adapter status and content length. Logs store the HTTP status and any exception raised by the adapter.
|
|
42
|
+
- Retry manually from the item detail page after fixing selectors.
|
|
43
|
+
|
|
44
|
+
## 7. Cleanup Rake Tasks Fail
|
|
45
|
+
|
|
46
|
+
- Pass numeric values for `FETCH_LOG_DAYS` or `SCRAPE_LOG_DAYS` environment variables (e.g., `FETCH_LOG_DAYS=30`).
|
|
47
|
+
- Ensure workers or the console environment have permission to soft delete (`SOFT_DELETE=true`) if you expect tombstones.
|
|
48
|
+
- If job classes cannot load, verify `SourceMonitor.configure` ran before calling `rake source_monitor:cleanup:*`.
|
|
49
|
+
|
|
50
|
+
## 8. Test Suite Cannot Launch a Browser
|
|
51
|
+
|
|
52
|
+
- System tests rely on Selenium + Chrome. Install Chrome/Chromium and set `SELENIUM_CHROME_BINARY` if the binary lives in a non-standard path.
|
|
53
|
+
- You can run `rbenv exec bin/test-coverage --verbose` to inspect failures with additional logging.
|
|
54
|
+
|
|
55
|
+
## 9. Mission Control Jobs Link Returns 404
|
|
56
|
+
|
|
57
|
+
- Mount `MissionControl::Jobs::Engine` in your host routes (for example, `mount MissionControl::Jobs::Engine, at: "/mission_control"`).
|
|
58
|
+
- Keep `config.mission_control_enabled = true` **and** `config.mission_control_dashboard_path` pointing at that mounted route helper. Call `SourceMonitor.mission_control_dashboard_path` in the Rails console to confirm it resolves.
|
|
59
|
+
- When hosting Mission Control in a separate app, provide a full URL instead of a route helper and ensure CORS/WebSocket settings allow the dashboard iframe.
|
|
60
|
+
|
|
61
|
+
## 10. Tailwind Build Fails or Admin UI Loads Without Styles
|
|
62
|
+
|
|
63
|
+
- Running `test/dummy/bin/dev` before configuring the bundling pipeline will serve the admin UI without Tailwind styles or Stimulus behaviours. This happens because the engine no longer ships precompiled assets; see `.ai/engine-asset-configuration.md:11-44` for the required npm setup.
|
|
64
|
+
- Fix by running `npm install` followed by `npm run build` inside the engine root so that `app/assets/builds/source_monitor/application.css` and `application.js` exist. The Rake task `app:source_monitor:assets:build` wraps the same scripts for CI usage.
|
|
65
|
+
- When the UI is still unstyled, confirm the dummy app can read the namespaced asset directories noted in `.ai/engine-asset-configuration.md:32-44` and restart `bin/dev` so the CSS/JS watchers reconnect.
|
|
66
|
+
|
|
67
|
+
## Still Stuck?
|
|
68
|
+
|
|
69
|
+
Collect the following and open an issue or start a discussion:
|
|
70
|
+
|
|
71
|
+
- Engine version (`SourceMonitor::VERSION`)
|
|
72
|
+
- Host Rails version and Ruby version
|
|
73
|
+
- Relevant configuration snippet from `config/initializers/source_monitor.rb`
|
|
74
|
+
- Recent fetch/scrape log entries or stack traces
|
|
75
|
+
|
|
76
|
+
We track known issues and roadmap items in `.ai/tasks.md`; check the next slice to see if your problem is already scheduled.
|
data/eslint.config.mjs
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import js from "@eslint/js";
|
|
2
|
+
|
|
3
|
+
export default [
|
|
4
|
+
{
|
|
5
|
+
ignores: [
|
|
6
|
+
"node_modules/**",
|
|
7
|
+
"vendor/assets/**",
|
|
8
|
+
"app/assets/builds/**"
|
|
9
|
+
]
|
|
10
|
+
},
|
|
11
|
+
js.configs.recommended,
|
|
12
|
+
{
|
|
13
|
+
files: [ "app/assets/javascripts/**/*.js" ],
|
|
14
|
+
languageOptions: {
|
|
15
|
+
sourceType: "module",
|
|
16
|
+
globals: {
|
|
17
|
+
window: "readonly",
|
|
18
|
+
document: "readonly",
|
|
19
|
+
CustomEvent: "readonly"
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
rules: {
|
|
23
|
+
"no-unused-vars": [ "error", { args: "none", ignoreRestSiblings: true } ],
|
|
24
|
+
"no-console": [ "warn", { allow: [ "warn", "error" ] } ]
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
];
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rails/generators"
|
|
4
|
+
require "rails/generators/base"
|
|
5
|
+
|
|
6
|
+
module SourceMonitor
|
|
7
|
+
module Generators
|
|
8
|
+
class InstallGenerator < Rails::Generators::Base
|
|
9
|
+
source_root File.expand_path("templates", __dir__)
|
|
10
|
+
|
|
11
|
+
class_option :mount_path,
|
|
12
|
+
type: :string,
|
|
13
|
+
default: "/source_monitor",
|
|
14
|
+
desc: "Path the engine will mount at inside the host application's routes"
|
|
15
|
+
|
|
16
|
+
def add_routes_mount
|
|
17
|
+
mount_path = normalized_mount_path
|
|
18
|
+
return if engine_already_mounted?(mount_path)
|
|
19
|
+
|
|
20
|
+
route %(mount SourceMonitor::Engine, at: "#{mount_path}")
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def create_initializer
|
|
24
|
+
initializer_path = "config/initializers/source_monitor.rb"
|
|
25
|
+
destination = File.join(destination_root, initializer_path)
|
|
26
|
+
|
|
27
|
+
if File.exist?(destination)
|
|
28
|
+
say_status :skip, initializer_path, :yellow
|
|
29
|
+
return
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
template "source_monitor.rb.tt", initializer_path
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def print_next_steps
|
|
36
|
+
say_status :info,
|
|
37
|
+
"Next steps: review docs/installation.md for install walkthroughs and docs/troubleshooting.md for common fixes.",
|
|
38
|
+
:green
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
private
|
|
42
|
+
|
|
43
|
+
def engine_already_mounted?(mount_path)
|
|
44
|
+
routes_path = File.join(destination_root, "config/routes.rb")
|
|
45
|
+
return false unless File.exist?(routes_path)
|
|
46
|
+
|
|
47
|
+
routes_content = File.read(routes_path)
|
|
48
|
+
routes_content.include?("mount SourceMonitor::Engine, at: \"#{mount_path}\"") ||
|
|
49
|
+
routes_content.include?("mount SourceMonitor::Engine")
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def normalized_mount_path
|
|
53
|
+
raw_path = options.key?(:mount_path) ? options[:mount_path] : "/source_monitor"
|
|
54
|
+
path = (raw_path && !raw_path.strip.empty?) ? raw_path.strip : "/source_monitor"
|
|
55
|
+
path.start_with?("/") ? path : "/#{path}"
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|