Skip to main content

Milestone 8: Notifications and snippets

Purpose: Agents receive in-app and email notifications for assignments, replies, mentions, SLA, and system events; notification preferences; snippets in reply composer.

Exit state: In-app notification panel and unread count; email notifications via Postmark (react-email); preferences; snippets CRUD and picker in composer.

Spec reference: §2.10 Notification System, §2.10b Email Templates, §5.9 Notification, §5.15 Snippet, §5.20 NotificationPreference, §6.10 Notifications panel, §6.6 SnippetPicker.

Prerequisites: M07 (Tickets — assignment and reply exist).


8.1 Notifications data and API

Tasks

  1. Schema

    • Already in M01: notifications (tenant_id, user_id, type, payload jsonb, read_at, created_at); notification_preferences (user_id, tenant_id, event_type, email_enabled, in_app_enabled). Section 5.9, 5.20.
  2. tRPC

    • Create notification (internal: worker or tRPC): insert row.
    • List notifications: by user_id + tenant_id; filter unread (read_at null); sort created_at desc; limit for panel (e.g. 20).
    • Mark read: single id or "mark all read" (update read_at for user+tenant).
    • Unread count: count where user_id + tenant_id and read_at null.
  3. Fan-out from events

    • When ticket assigned: create notification for assignee (type ticket_assigned); trigger email if preference allows. Section 2.10.
    • When new inbound message on ticket: if ticket has assignee, create notification for assignee (type ticket_reply); trigger email.
    • When @mention in internal note: parse mention nodes; create notification for mentioned user(s); trigger email. Section 2.10 (mention).
    • When SLA breach/near-breach: create notification for assignee and admins (M11 will trigger); trigger email.
    • When inbox error (OAuth failure): create notification for tenant admins; trigger email (inbox-error template). Section 2.10.
    • Trial/billing: day-25, day-30, day-37 emails to admins (M10); can create in-app notification too.
    • Implement helper: createNotification({ tenantId, userId, type, payload }) and optionally sendEmail(type, recipient, data). Call from worker and tRPC where events occur.

Acceptance criteria

CriterionStatus
Notifications created on assignment, reply, mention, inbox error; list and unread count correct.Pending
Mark read (single and all) works; list shows in panel (M08.3).Pending
Creating a notification publishes to Redis so SSE clients receive notification.new; panel and badge update in real time (Section 4.11).Pending

8.2 Transactional email (Postmark + react-email)

Tasks

  1. react-email templates

    • Create components for: invite, password-reset, ticket-assigned, ticket-reply, mention, sla-breach, inbox-error, trial-ending, trial-expired, trial-locked, payment-failed, subscription-cancelled. Section 2.10b. Each accepts props (e.g. org_name, ticket_url); render to HTML + plain text.
  2. Rendering and send

    • In worker or shared package: import template, render with data, POST to Postmark API (From, To, Subject, HtmlBody, TextBody). Use POSTMARK_API_KEY and POSTMARK_FROM_ADDRESS from config.
    • Invite email: send on invite create (M09); password-reset on request (M02). Ticket-assigned, ticket-reply, mention: send when creating notification if user preference email_enabled. Sla-breach: from SLA cron (M11). Inbox-error: on OAuth failure in worker. Trial/billing: from trial cron (M10).
  3. Base layout

    • Shared BaseLayout for all templates: logo, footer with legal/unsubscribe link, consistent styling. Section 2.10b.

Acceptance criteria

CriterionStatus
All templates render without error; send via Postmark succeeds in dev/staging.Pending
Invite and password-reset emails sent from M02/M09; ticket-assigned and ticket-reply sent when notification created and preference allows.Pending

8.3 In-app notification panel

Tasks

  1. Bell icon and badge

    • In app shell (M03): notification bell in top bar; badge with unread count (from tRPC unread count). Poll every 30s or use same refetchInterval as list. Section 4.11.
  2. Panel (Sheet or Popover)

    • On click: open panel with list of notifications (scrollable). Each item: icon by type, text (e.g. "Ticket #42 assigned to you"), link to ticket or page, relative time, unread dot. "Mark all as read" button. Optional "View all" link to /app/[slug]/notifications (full page) if implemented.
    • Clicking notification: navigate to ticket (or relevant page); mark that notification read.

Acceptance criteria

CriterionStatus
Unread count visible on bell; panel opens and shows list; mark read and mark all read work; click navigates and marks read.Pending
Unread count and panel list update in real time via SSE (notification.new); optional polling fallback when SSE unavailable.Pending

8.4 Notification preferences

Tasks

  1. Schema and defaults

    • notification_preferences: (user_id, tenant_id, event_type, email_enabled, in_app_enabled). Unique (user_id, tenant_id, event_type). If no row, default both true. Section 5.20.
  2. tRPC

    • Get preferences for user+tenant (list of event_type with email_enabled, in_app_enabled). Update preference (upsert row).
  3. UI

    • Profile or Settings: "Notifications" section; matrix or list of event types (ticket assigned, reply received, mention, SLA breach, inbox error, etc.) with toggles for Email and In-app. Save on change or Save button.

Acceptance criteria

CriterionStatus
User can view and update notification preferences per event type; defaults apply when no row.Pending
Sending respects preferences (email only if email_enabled; in-app only if in_app_enabled).Pending

8.5 Snippets (canned responses)

Tasks

  1. CRUD

    • tRPC: list snippets (tenant); create (name, body); update; delete. Section 5.15. Snippets table tenant-scoped; body is text or HTML.
  2. Settings → Snippets

    • List snippets: name, body preview, edit/delete. "New snippet" modal: name input, Tiptap or textarea for body; save. Section 6.10. Role: Agent + Admin can manage per spec.
  3. Picker in composer

    • In reply composer (M07): "Snippets" button or dropdown; open popover with list of snippet names; on select insert body into editor (replace or append); user can edit before send. Section 2.4, 6.6.

Acceptance criteria

CriterionStatus
Admin/Agent can create and edit snippets in Settings; snippets appear in composer picker; insert and edit before send works.Pending
Snippets are tenant-scoped.Pending

Milestone 8 sign-off

CriterionStatus
All tasks in 8.1–8.5 complete.Pending
All acceptance criteria met.Pending
Notifications (in-app + email) and snippets fully functional.Pending
E2E: Notifications and snippets flows (see INDEX — Testing strategy).Pending
Ready for M09 (Invites and team).Pending