Skip to content

feat: add alarms system with notifications#331

Closed
maoshuorz wants to merge 1 commit intodatabuddy-analytics:mainfrom
maoshuorz:feat/alarms-system
Closed

feat: add alarms system with notifications#331
maoshuorz wants to merge 1 commit intodatabuddy-analytics:mainfrom
maoshuorz:feat/alarms-system

Conversation

@maoshuorz
Copy link

Summary

Resolves #267

Adds a full alarms system for monitoring website events and sending notifications via Slack, Discord, Email, or custom Webhooks.

Changes

Database

  • New alarms table with fields for name, description, enabled state, notification channels, webhook URLs, trigger type/conditions
  • 5 btree indexes (userId, organizationId, websiteId, enabled, createdBy)
  • 4 foreign keys with cascade/restrict policies
  • Relations defined for website, organization, user, and creator

API (ORPC Router)

  • list — List alarms for a website or organization (protected)
  • get — Get single alarm by ID (protected)
  • create — Create new alarm with auth resolution for API key users (protected)
  • update — Update alarm with URL cleanup for empty strings (protected)
  • delete — Soft-delete alarm, disables notifications (protected)
  • test — Send test notification through all configured channels (protected)

Shared Validation (@databuddy/shared/alarms)

  • Zod schemas: alarmFormSchema, createAlarmSchema, updateAlarmSchema, listAlarmsSchema, getAlarmSchema, deleteAlarmSchema, testAlarmSchema
  • Enums: notificationChannelSchema (slack, discord, email, webhook), triggerTypeSchema (uptime, traffic_spike, error_rate, goal, custom)
  • 20 tests passing for all schema validations

Dashboard UI

  • Notifications Settings Page — Full page with alarm list, create button, right sidebar with documentation
  • Alarm Sheet — Create/edit form with trigger type selector, notification channel toggles, channel-specific configuration (Slack/Discord webhook URLs, email recipients, custom webhook with headers)
  • Alarms List — Alarm rows with enable/disable toggle, trigger type badge, channel badges, test notification action, edit/delete actions
  • Skeleton loading states for all list components

Design

  • Uses Phosphor icons throughout (BellIcon, SirenIcon, EnvelopeIcon, WebhookLogoIcon, etc.)
  • Uses rounded class (matches existing patterns)
  • No any types — uses unknown for JSONB fields
  • No console.log statements
  • Follows existing ORPC router patterns with proper auth checks

/claim #267

@vercel
Copy link

vercel bot commented Mar 6, 2026

@maoshuorz is attempting to deploy a commit to the Databuddy OSS Team on Vercel.

A member of the Team first needs to authorize it.

@CLAassistant
Copy link

CLAassistant commented Mar 6, 2026

CLA assistant check
All committers have signed the CLA.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 6, 2026

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: db78ac13-36a0-44d5-b3f7-ef30561e4533

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Tip

Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs).
Share your feedback on Discord.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Mar 6, 2026

Greptile Summary

This PR implements a full alarms system allowing users to create notification alarms triggered by uptime, traffic spikes, error rates, goals, or custom conditions — with delivery via Slack, Discord, Email, or custom webhooks. It adds a new alarms database table, a complete ORPC router, shared Zod schemas with 20 tests, and a new Notifications Settings page replacing the previous "Coming Soon" placeholder.

The overall structure is solid and follows existing project patterns well. There is one UX issue that should be addressed:

  • UX/Logic — email test always fails: The test endpoint's email case unconditionally returns success: false, causing misleading failure toasts for email-only alarm configurations even when correctly set up.

Confidence Score: 4/5

  • Safe to merge. Authorization logic is sound with proper schema validation enforcing scope requirements. Only remaining issue is a non-critical UX problem where email test notifications incorrectly report failure.
  • The PR implements a complete, well-structured alarms system that follows existing patterns and includes comprehensive Zod schema validation. Prior critical security concerns (authorization bypass, permission mapping) are not applicable — the schema prevents creating alarms without a scope, making the authorization bypass impossible in practice. The only remaining issue is that the email test channel unconditionally returns failure, causing misleading test results for email-only configurations. This is a UX issue, not a security or data integrity problem. The code is safe to merge once the email test behavior is addressed.
  • packages/rpc/src/routers/alarms.ts (email test UX issue)

Important Files Changed

Filename Overview
packages/rpc/src/routers/alarms.ts Core ORPC router with all alarm operations. One UX issue: the email test channel always returns failure, causing misleading success/failure messages for email-only configurations.
apps/dashboard/app/(main)/settings/notifications/_components/alarm-sheet.tsx Create/edit form with channel toggles and configuration panels. Client-side email validation could provide faster feedback before form submission, though server-side Zod validation covers the requirement.
packages/shared/src/alarms/index.ts Well-structured Zod schemas for all alarm operations with comprehensive validation. All 20 schema tests pass.
packages/db/src/drizzle/schema.ts New alarms table with appropriate JSONB columns, 5 btree indexes, and 4 foreign keys with correct cascade/restrict policies.
apps/dashboard/app/(main)/settings/notifications/_components/alarms-list.tsx Alarm list with per-row enable toggle, trigger/channel badges, and action dropdown; event propagation from interactive children properly stopped.
apps/dashboard/app/(main)/settings/notifications/page.tsx Replaced "Coming Soon" placeholder with full alarms management page including query, create/edit sheet, delete dialog, and empty states.
packages/rpc/src/routers/alarms.test.ts 20 schema-level tests covering all enums, form schema, create, update, and list validation; good coverage of edge cases.

Sequence Diagram

sequenceDiagram
    participant UI as Dashboard UI
    participant Router as alarms Router
    participant AuthFn as authorizeScope
    participant DB as Database
    participant Notif as notifications pkg

    UI->>Router: list alarms for org
    Router->>AuthFn: check read permission
    AuthFn-->>Router: allowed or forbidden
    Router->>DB: select non-deleted alarms
    DB-->>Router: alarm rows
    Router-->>UI: alarm list

    UI->>Router: create alarm
    Router->>AuthFn: check write permission
    AuthFn-->>Router: allowed or forbidden
    Router->>DB: insert new alarm
    DB-->>Router: created alarm
    Router-->>UI: alarm record

    UI->>Router: update alarm
    Router->>DB: fetch alarm by id
    DB-->>Router: alarm record
    Router->>AuthFn: check write permission
    AuthFn-->>Router: allowed or forbidden
    Router->>DB: update alarm fields
    DB-->>Router: updated alarm
    Router-->>UI: updated record

    UI->>Router: test alarm
    Router->>DB: fetch alarm by id
    DB-->>Router: alarm record
    Router->>AuthFn: check write permission
    AuthFn-->>Router: allowed or forbidden
    Router->>Notif: send to Slack, Discord, Webhook
    Notif-->>Router: per-channel results
    Router-->>UI: overall success plus results (email always fails)

    UI->>Router: delete alarm
    Router->>DB: fetch alarm scope
    DB-->>Router: websiteId or orgId
    Router->>AuthFn: check delete permission
    AuthFn-->>Router: allowed or forbidden
    Router->>DB: soft delete and disable
    DB-->>Router: done
    Router-->>UI: success true
Loading

Last reviewed commit: 49f4aba

Comment on lines +462 to +471
case "email": {
// Email sending requires an email provider configured at app level
results.push({
channel: "email",
success: false,
error:
"Email notifications require server-side email configuration",
});
break;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The email case unconditionally returns success: false, which causes misleading UX when email is the only configured channel. Since the overall success is computed as results.some((r) => r.success) (line 497), a user with a valid email-only alarm configuration will always see "Test notification failed" in the UI.

Consider either:

  1. Excluding email from the notification channel options (mark as "coming soon")
  2. Returning a distinct non-failure status or surfacing a different message like "Email test not yet supported"
  3. Implementing server-side email functionality so the test can actually complete

Comment on lines +179 to +189
const addEmail = () => {
const trimmed = emailInput.trim();
if (!trimmed) {
return;
}
const current = form.getValues("emailAddresses") || [];
if (!current.includes(trimmed)) {
form.setValue("emailAddresses", [...current, trimmed]);
}
setEmailInput("");
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The addEmail() function accepts any non-empty string without validating email format before adding to the form field. Invalid entries like "not-an-email" appear as badges in the UI and are only rejected at submit time by Zod validation.

Consider adding a quick client-side format check before calling form.setValue for faster feedback:

Suggested change
const addEmail = () => {
const trimmed = emailInput.trim();
if (!trimmed) {
return;
}
const current = form.getValues("emailAddresses") || [];
if (!current.includes(trimmed)) {
form.setValue("emailAddresses", [...current, trimmed]);
}
setEmailInput("");
};
const addEmail = () => {
const trimmed = emailInput.trim();
if (!trimmed || !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(trimmed)) {
return;
}
const current = form.getValues("emailAddresses") || [];
if (!current.includes(trimmed)) {
form.setValue("emailAddresses", [...current, trimmed]);
}
setEmailInput("");
};

@maoshuorz
Copy link
Author

recheck

@izadoesdev izadoesdev closed this Mar 19, 2026
@izadoesdev
Copy link
Member

Closing as part of maintainer triage: we’re not merging unsolicited / AI-style bulk bounty PRs for this area. If you plan a good-faith contribution later, open a new PR with a short description that matches the actual diff.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

🎯 Bounty: Alarms System - Database, API & Dashboard UI

3 participants