RepoPilotOpen in app →

excid3/noticed

Notifications for Ruby on Rails applications

Healthy

Healthy across the board

Use as dependencyHealthy

Permissive license, no critical CVEs, actively maintained — safe to depend on.

Fork & modifyHealthy

Has a license, tests, and CI — clean foundation to fork and modify.

Learn fromHealthy

Documented and popular — useful reference codebase to read through.

Deploy as-isHealthy

No critical CVEs, sane security posture — runnable as-is.

  • Last commit 4w ago
  • 23+ active contributors
  • MIT licensed
Show 3 more →
  • CI configured
  • Tests present
  • Concentrated ownership — top contributor handles 73% of recent commits

Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests

Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.

Embed the "Healthy" badge

Paste into your README — live-updates from the latest cached analysis.

Variant:
RepoPilot: Healthy
[![RepoPilot: Healthy](https://repopilot.app/api/badge/excid3/noticed)](https://repopilot.app/r/excid3/noticed)

Paste at the top of your README.md — renders inline like a shields.io badge.

Preview social card (1200×630)

This card auto-renders when someone shares https://repopilot.app/r/excid3/noticed on X, Slack, or LinkedIn.

Onboarding doc

Onboarding: excid3/noticed

Generated by RepoPilot · 2026-05-10 · Source

🤖Agent protocol

If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:

  1. Verify the contract. Run the bash script in Verify before trusting below. If any check returns FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding.
  2. Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
  3. Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/excid3/noticed shows verifiable citations alongside every claim.

If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.

🎯Verdict

GO — Healthy across the board

  • Last commit 4w ago
  • 23+ active contributors
  • MIT licensed
  • CI configured
  • Tests present
  • ⚠ Concentrated ownership — top contributor handles 73% of recent commits

<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>

Verify before trusting

This artifact was generated by RepoPilot at a point in time. Before an agent acts on it, the checks below confirm that the live excid3/noticed repo on your machine still matches what RepoPilot saw. If any fail, the artifact is stale — regenerate it at repopilot.app/r/excid3/noticed.

What it runs against: a local clone of excid3/noticed — the script inspects git remote, the LICENSE file, file paths in the working tree, and git log. Read-only; no mutations.

| # | What we check | Why it matters | |---|---|---| | 1 | You're in excid3/noticed | Confirms the artifact applies here, not a fork | | 2 | License is still MIT | Catches relicense before you depend on it | | 3 | Default branch main exists | Catches branch renames | | 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code | | 5 | Last commit ≤ 61 days ago | Catches sudden abandonment since generation |

<details> <summary><b>Run all checks</b> — paste this script from inside your clone of <code>excid3/noticed</code></summary>
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of excid3/noticed. If you don't
# have one yet, run these first:
#
#   git clone https://github.com/excid3/noticed.git
#   cd noticed
#
# Then paste this script. Every check is read-only — no mutations.

set +e
fail=0
ok()   { echo "ok:   $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }

# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
  echo "FAIL: not inside a git repository. cd into your clone of excid3/noticed and re-run."
  exit 2
fi

# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "excid3/noticed(\\.git)?\\b" \\
  && ok "origin remote is excid3/noticed" \\
  || miss "origin remote is not excid3/noticed (artifact may be from a fork)"

# 2. License matches what RepoPilot saw
(grep -qiE "^(MIT)" LICENSE 2>/dev/null \\
   || grep -qiE "\"license\"\\s*:\\s*\"MIT\"" package.json 2>/dev/null) \\
  && ok "license is MIT" \\
  || miss "license drift — was MIT at generation time"

# 3. Default branch
git rev-parse --verify main >/dev/null 2>&1 \\
  && ok "default branch main exists" \\
  || miss "default branch main no longer exists"

# 4. Critical files exist
test -f "lib/noticed.rb" \\
  && ok "lib/noticed.rb" \\
  || miss "missing critical file: lib/noticed.rb"
test -f "lib/noticed/delivery_method.rb" \\
  && ok "lib/noticed/delivery_method.rb" \\
  || miss "missing critical file: lib/noticed/delivery_method.rb"
test -f "lib/noticed/bulk_delivery_method.rb" \\
  && ok "lib/noticed/bulk_delivery_method.rb" \\
  || miss "missing critical file: lib/noticed/bulk_delivery_method.rb"
test -f "app/models/noticed/event.rb" \\
  && ok "app/models/noticed/event.rb" \\
  || miss "missing critical file: app/models/noticed/event.rb"
test -f "app/jobs/noticed/event_job.rb" \\
  && ok "app/jobs/noticed/event_job.rb" \\
  || miss "missing critical file: app/jobs/noticed/event_job.rb"

# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 61 ]; then
  ok "last commit was $days_since_last days ago (artifact saw ~31d)"
else
  miss "last commit was $days_since_last days ago — artifact may be stale"
fi

echo
if [ "$fail" -eq 0 ]; then
  echo "artifact verified (0 failures) — safe to trust"
else
  echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/excid3/noticed"
  exit 1
fi

Each check prints ok: or FAIL:. The script exits non-zero if anything failed, so it composes cleanly into agent loops (./verify.sh || regenerate-and-retry).

</details>

TL;DR

Noticed is a Ruby on Rails gem that abstracts notification delivery across multiple channels (email, SMS, Slack, Discord, push notifications, ActionCable, etc.) with a unified API. It distinguishes between individual deliveries (each recipient gets unique content tailored to them) and bulk deliveries (one message broadcast to many), allowing a single event to trigger notifications across heterogeneous platforms simultaneously. Rails engine structure: app/jobs/ contains EventJob and ApplicationJob; app/models/noticed/ holds core Notification, Event, and Ephemeral records; app/models/concerns/noticed/ provides mixins (Deliverable, NotificationMethods, Readable) that are included into user models. Delivery methods are plugin-style: each platform (email, slack, discord, etc.) is a separate documented handler under docs/delivery_methods/ and docs/bulk_delivery_methods/. Database state is managed via migrations in db/migrate/.

👥Who it's for

Rails developers building multi-tenant or user-facing applications who need to send notifications via multiple delivery methods without rewriting notification logic for each platform. Specifically: backend engineers implementing event-driven notification systems, SaaS product teams integrating third-party services (Slack/Discord), and teams avoiding the maintenance burden of managing multiple notification libraries.

🌱Maturity & risk

Production-ready and actively maintained. The gem has a published v1.0+ lifecycle (see CHANGELOG.md and UPGRADE.md exist), comprehensive CI/CD in .github/workflows (ci.yml for tests, publish_gem.yml for releases), and supports multiple Rails versions via Appraisals. The codebase is well-organized with migrations, tests, and documentation—typical of a stable Rails engine.

Single-maintainer risk (excid3 is primary author); no visible org sharing responsibility. Dependency surface is moderate—it requires Rails + ActiveJob and integrates with external APIs (Twilio, Firebase, etc.) whose breaking changes could ripple through. The two migrations (20231215 and 20240129) suggest schema evolution; users upgrading must run migrations. Publish automation exists but CI passing rate is not visible from repo data.

Active areas of work

No specific PR/issue data visible in provided file listing, but the repo has UPGRADE.md (indicating version transitions) and recent migration 20240129 (adds notifications_count denormalization to noticed_event). Documentation is actively maintained across delivery methods. The gem is in stable maintenance mode rather than rapid feature development.

🚀Get running

git clone https://github.com/excid3/noticed.git && cd noticed && bundle install && bin/test to run the test suite. Use bin/rails to interact with the dummy Rails app for local development.

Daily commands: bin/test runs the test suite. For interactive development: bin/rails console opens a Rails console against the dummy app. No web server needed unless testing ActionCable delivery; delivery methods are ActiveJob jobs, typically async.

🗺️Map of the codebase

  • lib/noticed.rb — Main entry point and gem initialization; must read to understand what's exported to consumers
  • lib/noticed/delivery_method.rb — Core abstraction for all individual delivery implementations; foundation for extending with custom channels
  • lib/noticed/bulk_delivery_method.rb — Core abstraction for bulk delivery implementations (send to many recipients at once); parallels individual delivery pattern
  • app/models/noticed/event.rb — Event model that represents a notification trigger; connects to delivery pipeline and persistence
  • app/jobs/noticed/event_job.rb — ActiveJob that orchestrates notification delivery; executes the delivery pipeline asynchronously
  • lib/generators/noticed/notifier_generator.rb — Scaffold generator for creating new notifiers; shows the DSL and conventions users must follow
  • app/models/concerns/noticed/deliverable.rb — Mixin that provides notification delivery capabilities to models; enables the core DSL pattern

🛠️How to make changes

Add a new individual delivery method

  1. Create a new class inheriting from Noticed::DeliveryMethod in lib/noticed/delivery_methods/ (lib/noticed/delivery_methods/my_channel.rb)
  2. Implement the deliver instance method receiving the notification record (lib/noticed/delivery_methods/my_channel.rb)
  3. Add option definitions (options :api_key, :template_id) at class level if needed (lib/noticed/delivery_methods/my_channel.rb)
  4. Generate a notifier or edit an existing one to add: deliver_by :my_channel (app/notifiers/application_notifier.rb)
  5. Optionally add tests by following the pattern in lib/noticed/delivery_methods/test.rb (test/delivery_methods/my_channel_test.rb)

Add a new bulk delivery method

  1. Create a new class inheriting from Noticed::BulkDeliveryMethod in lib/noticed/bulk_delivery_methods/ (lib/noticed/bulk_delivery_methods/my_service.rb)
  2. Implement the deliver instance method receiving an array of notification records (lib/noticed/bulk_delivery_methods/my_service.rb)
  3. Use the notifications parameter to batch access recipient data and send in one request (lib/noticed/bulk_delivery_methods/my_service.rb)
  4. Register in a Notifier via: deliver_by :my_service, bulk: true (app/notifiers/application_notifier.rb)

Create a new notifier class

  1. Run: rails generate noticed:notifier CommentNotifier (lib/generators/noticed/notifier_generator.rb)
  2. Edit the generated notifier to define methods and delivery_by declarations (app/notifiers/comment_notifier.rb)
  3. Define recipients via recipient_ids method that returns array of user IDs (app/notifiers/comment_notifier.rb)
  4. Trigger from model via: notify(:message_posted).deliver_later (app/models/comment.rb)

Add read status tracking to a notification

  1. Ensure Noticed::Notification model is in use (created by install generator) (db/migrate/20231215190233_create_noticed_tables.rb)
  2. In your app, include Noticed::Readable on the user or notification model (app/models/user.rb)
  3. Call notification.mark_as_read! in your UI controller when user views notification (app/controllers/notifications_controller.rb)
  4. Query unread: Noticed::Notification.unread or via user.notifications.unread (app/controllers/notifications_controller.rb)

🔧Why these technologies

  • Rails Engine — Seamless integration into host Rails app; auto-loads models, jobs, migrations, generators
  • ActiveJob — Decouples notification delivery from request cycle; supports multiple backends (Sidekiq, Delayed Job, etc.)
  • ActionMailer — Leverage existing Rails email infrastructure for the email delivery method
  • ActionCable — Real-time WebSocket push to browsers without external service dependency
  • Polymorphic associations — Event can attach to any model (Post, Comment, Order); flexible trigger source
  • YAML serialization (Coder) — Store notification params and data as JSON in DB; avoids extra columns

⚖️Trade-offs already made

  • Separate Event and Notification models

    • Why: Event is the trigger (one per action); Notification is per-recipient (one per user receiving it). Allows tracking which users got notified and read status.
    • Consequence: Requires DB lookups to find recipients; adds schema complexity vs. single table
  • Async-first delivery via EventJob

    • Why: Non-blocking; scales to many recipients and external APIs without slowing request response
    • Consequence: Notifications not sent synchronously; timing unpredictable if job queue fails
  • Ephemeral mode (no DB record)

    • Why: Lightweight for high-volume, transient notifications (ActionCable only); skip persistence overhead
    • Consequence: No audit trail or read status for ephemeral notifications
  • Individual vs. bulk delivery split

    • Why: Some channels (Slack, Discord)
    • Consequence: undefined

🪤Traps & gotchas

No explicit .env or config file visible—credentials for external services (Twilio, Firebase, Slack tokens) must be set as Rails credentials or environment variables (convention-over-configuration). The gem expects ActiveJob to be configured in the Rails app; missing job adapter will cause silent notification failures. Bulk deliveries are fire-and-forget; individual deliveries create persisted records. Migration 20240129 adds a counter cache (notifications_count) to noticed_event—existing deployments must run migrations in order.

🏗️Architecture

💡Concepts to learn

  • Rails Concerns (Mixins) — Noticed uses Concerns (Deliverable, NotificationMethods, Readable) to inject behavior into user models without inheritance; understanding this pattern is essential to extending Noticed for custom use cases
  • ActiveJob — Noticed relies on ActiveJob for asynchronous delivery of notifications via EventJob and individual delivery jobs; you must understand job queueing, retries, and adapters to debug production issues
  • Strategy Pattern (Pluggable Delivery Methods) — Each delivery method (email, Slack, Discord, etc.) is a self-contained strategy class; adding a new delivery method requires implementing this pattern
  • Observer Pattern (Event-Driven Notifications) — Noticed triggers notifications on model changes without tightly coupling the model to notification logic; understands how Event observers fire EventJob
  • Counter Cache (Denormalization) — Migration 20240129 adds notifications_count to noticed_event; understanding when to denormalize and how to maintain cache integrity is important for performance tuning
  • Rails Engine Architecture — Noticed is a Rails engine, not a standalone gem; understanding how engines mount into host apps, provide migrations, and serve models/jobs is crucial for contributing
  • Individual vs. Bulk Delivery Trade-offs — Noticed's core differentiator; individual deliveries create per-recipient notification records (good for user UX, tracking), while bulk deliveries are stateless (good for team alerts). Design patterns depend on this choice
  • thoughtbot/high_voltage — Rails engine for static pages; shares Rails engine architecture patterns and gem publishing patterns with Noticed
  • rails/rails — Noticed depends heavily on ActiveJob, ActionMailer, and Rails concerns; core reference for understanding Rails patterns used
  • sidekiq/sidekiq — Common background job processor used to run Noticed's EventJob and delivery jobs in production Rails apps
  • excid3/streamlined — Another gem by the same author (excid3); likely uses similar Rails engine and mixin patterns
  • rails/actioncable — Noticed supports ActionCable delivery method; reference for real-time WebSocket notification delivery in Rails

🪄PR ideas

To work on one of these in Claude Code or Cursor, paste: Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.

Add comprehensive integration tests for bulk delivery methods (Slack, Discord, Bluesky, Webhook)

The repo has documentation for bulk delivery methods in docs/bulk_delivery_methods/ but there's no evidence of dedicated test files for these implementations. Given that the codebase supports multiple bulk delivery channels, adding integration tests would ensure reliability and prevent regressions. This is high-value because bulk deliveries are complex (requiring API batching logic) and are critical for team notifications.

  • [ ] Create test/noticed/delivery_methods/bulk/ directory structure mirroring docs/bulk_delivery_methods/
  • [ ] Add test file for Slack bulk delivery testing (API batching, error handling, rate limiting)
  • [ ] Add test file for Discord bulk delivery testing (webhook payload validation)
  • [ ] Add test file for Bluesky bulk delivery testing
  • [ ] Add test file for Webhook bulk delivery testing with retry logic
  • [ ] Verify tests run in CI workflow (.github/workflows/ci.yml) with appropriate gems/mocks

Create comprehensive test suite for Noticed::Ephemeral notification model

The file app/models/noticed/ephemeral.rb exists but there are likely no dedicated tests for ephemeral (non-persisted) notifications. Ephemeral notifications are a core feature that differ significantly from persistent Noticed::Notification records. This PR would ensure the ephemeral delivery path is tested, especially around the event job execution and delivery method handling without database persistence.

  • [ ] Create test/noticed/ephemeral_test.rb with tests for ephemeral notification creation
  • [ ] Add tests verifying ephemeral notifications don't persist to database
  • [ ] Add tests for Noticed::EventJob behavior with ephemeral notifications
  • [ ] Test delivery method execution for ephemeral notifications
  • [ ] Test that notification_methods work correctly without persisted records
  • [ ] Verify tests integrate with the CI pipeline

Add migration and test helpers for multi-version Rails compatibility (Rails 7.0-8.1)

The repo maintains Appraisals and gemfiles for Rails 7.0 through 8.1, indicating complex multi-version testing needs. However, there's likely missing test helpers/migrations to validate schema compatibility across versions. Adding a test utility file and comprehensive migration validation tests would help catch breaking changes early.

  • [ ] Create test/support/migration_helpers.rb with utilities for testing db/migrate/*.rb across Rails versions
  • [ ] Add test/migrations/migrations_test.rb to verify all migrations (20231215190233_create_noticed_tables.rb and 20240129184740_add_notifications_count_to_noticed_event.rb) work on Rails 7.0, 7.1, 7.2, 8.0, and 8.1
  • [ ] Create test/support/appraisal_helper.rb to manage Appraisal environment testing
  • [ ] Add CI matrix step in .github/workflows/ci.yml to explicitly test migrations across all Gemfiles if not present
  • [ ] Document the multi-version testing approach in docs/extending-noticed.md

🌿Good first issues

  • Add missing test coverage for app/models/noticed/ephemeral.rb (in-memory notifications) with unit tests covering edge cases like concurrent access and memory cleanup.
  • Expand docs/delivery_methods/ with a 'testing delivery methods' guide showing how to stub external API calls (e.g., mocking Twilio requests) in test suites.
  • Create a changelog entry generator or audit UPGRADE.md to ensure all breaking changes from v0.x to v1.0 are documented with migration examples.

Top contributors

Click to expand

📝Recent commits

Click to expand
  • aca286e — Require MFA for gem pushes (#578) (MatheusRich)
  • ddab2d1 — Version bump (excid3)
  • 06b1e4f — Update gemfiles (excid3)
  • eda6f53 — Simplify setup-ruby action (excid3)
  • 18b143b — Rewrite lockfiles (excid3)
  • a4ee163 — Update lock files (excid3)
  • 815b41f — Update gems (excid3)
  • abf0097 — test against Ruby 4 (excid3)
  • 82db1f4 — Fix another typo in github actions (excid3)
  • 4c7cccd — Fix github actions (excid3)

🔒Security observations

The Noticed gem is a notification delivery framework for Rails with moderate security posture. Primary concerns include: (1) Potential API communication vulnerabilities in the API client, (2) Template injection risks in code generators, (3) Sensitive data exposure in serialized job queues, and (4) SSRF risks in webhook delivery methods. The codebase lacks visible hardcoded secrets or obvious SQL injection vectors. Recommendations: conduct code review of API client and delivery methods, implement strict input validation in generators, secure the job queue backend, and validate webhook URLs. Regular dependency auditing is essential given the notification framework's integration with external services (Slack, Discord, email, SMS, FCM, etc.).

  • Medium · API Client Without Rate Limiting or Authentication Validation — lib/noticed/api_client.rb. The file 'lib/noticed/api_client.rb' suggests HTTP API communication, but without reviewing its implementation, there's a risk of unvalidated API calls, missing authentication headers, or lack of rate limiting protections. This could lead to abuse or unauthorized access. Fix: Ensure the API client implements: (1) Proper authentication mechanisms (API keys, tokens), (2) Rate limiting and retry logic with exponential backoff, (3) Request validation and sanitization, (4) Secure credential storage via environment variables, not hardcoded values
  • Medium · Potential Template Injection in Generator Templates — lib/generators/noticed/templates/*.tt. The gem includes multiple ERB template files (.tt) for code generation (notifier, delivery methods). Improper handling of user input during generation could lead to code injection or template injection vulnerabilities. Fix: Validate and sanitize all user inputs used in template generation. Use Rails generators' built-in escaping mechanisms. Avoid evaluating user input as code within templates.
  • Medium · Job Queue Security - Sensitive Data in Serialized Jobs — app/jobs/noticed/event_job.rb, app/models/noticed/event.rb. The notification system uses ActiveJob (app/jobs/noticed/event_job.rb). If notification events contain sensitive user data (PII, auth tokens), they may be logged or exposed if the job queue is not properly secured. Fix: Implement secure serialization practices: (1) Avoid serializing sensitive data directly in jobs, (2) Use IDs/references instead of full objects, (3) Decrypt sensitive data at delivery time, (4) Ensure job queue backend is secured with authentication and encryption
  • Medium · Missing CSRF Protection in Webhook Delivery Methods — docs/bulk_delivery_methods/webhook.md, lib/noticed/api_client.rb. Documentation references webhook delivery methods (docs/bulk_delivery_methods/webhook.md). Outbound webhooks may not validate target endpoints, allowing potential SSRF attacks or callback to internal services. Fix: Implement strict URL validation for webhooks: (1) Whitelist allowed domains/IP ranges, (2) Block private IP ranges (127.0.0.1, 10.x.x.x, etc.), (3) Validate SSL certificates, (4) Implement timeout and size limits on responses
  • Low · Dependency Version Pinning Not Visible — Gemfile, Gemfile.lock, gemfiles/*.gemfile. The Gemfile and Gemfile.lock are referenced but content not provided. Unable to verify if dependencies are pinned to specific secure versions or if known vulnerable versions are in use. Fix: Regularly audit dependencies using 'bundle audit' or similar tools. Pin specific versions and keep dependencies updated. Monitor security advisories for Rails, ActiveJob, and other key dependencies.
  • Low · Potential Information Disclosure via Error Messages — app/models/noticed/deliverable/deliver_by.rb. Delivery methods (email, SMS, push notifications) may expose sensitive information in error logs if exceptions contain user data or API responses. Fix: Implement careful error handling: (1) Log exceptions without sensitive payloads, (2) Sanitize API responses before logging, (3) Use structured logging, (4) Implement proper access controls on log files

LLM-derived; treat as a starting point, not a security audit.


Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.

Healthy signals · excid3/noticed — RepoPilot