Skip to content

moooon

Motir

Vibe your whole project. Bring an idea — Motir's three AI layers plan it, track it, and ship it, end to end. You're looking at Motir, built in Motir.

  • Vibe Project
  • Open Source
  • AI Agent
  • AI Loop
1
requests
0
upvotes
145
planned
1,361
shipped

Motir · Work items

MOTIR-270Done

5.1.6 Mention → email notification job (`work-item/comment.created` + description-mention parity) via the 1.6 pipeline + `mentionNotification` template

Estimate: 30m · Depends on: 5.1.2, 1.6.3

The notification hook — the stub's "Mention → notification hook (via Story 1.6 jobs)". Email only here; the event payload is channel-agnostic so Story 5.7 (in-app bell) and Story 5.4 (watchers) fan in off the SAME events later.

Job (lib/jobs/definitions/mentionNotify.ts, the 1.6 defineJob harness — mirroring emailSend.ts, the production reference): consumes work-item/comment.created (and work-item/mentioned, below). Per mentioned user: skip the author (never self-notify), re-validate view access at send time (the Jira rule — access may have changed since the write; the 5.1.2 scoping reused), render the mentionNotification template and send through the shipped email pipeline. Idempotent per (commentId × userId) via the harness idempotency key — a replay or retry never double-mails. Failures land in the DLQ per the 1.6 contract.

Template (lib/emailTemplates/mentionNotification.tsx, the pure-template contract): "<Author> mentioned you on <PROD-N: title>" subject; body with the author, the issue identifier + title as a deep link, a short PLAIN-TEXT excerpt of the comment (Markdown stripped, mention tokens rendered as @Name — a small lib/mentions helper; no raw token leakage), and the CTA button to the issue. Hand-written plain text with the link unredacted (the dev-console grep contract).

Description-mention parity (Jira-faithful). Mentions in the issue DESCRIPTION notify too: on createWorkItem / description-changing updateWorkItem, parse with the SAME lib/mentions/parse.ts helper, diff against the prior body (only newly-added, view-validated ids), and emit work-item/mentioned (workspaceId, workItemId, authorId, mentionedUserIds) after commit. The job treats both events uniformly (idempotency key swaps commentId for the revision id). No WorkItem schema change — description mentions are notification-only (no stored mention rows; recorded as the deliberate scope line: the queryable substrate is comment-scoped until a use case earns more).

Acceptance criteria

  • JobEventDataMap gains work-item/comment.created + work-item/mentioned (typed payloads); both emit AFTER their transactions commit; the job fans out one email per mentioned user, skipping the author and any user who can no longer view the issue at send time.
  • Idempotency: replaying the event or retrying the job never double-sends (per comment×user / revision×user key); failures land in the DLQ (@inngest/test coverage, the 1.6 test harness).
  • mentionNotification is a pure template (no I/O; props in, {subject, text, html} out) with hand-written plain text + unredacted deep link; the excerpt renders mention tokens as @Name, never raw mention: markup.
  • Editing a comment notifies ONLY newly-added mentions; description create/edit notifies newly-added description mentions through the same job; the dev email console shows the [EMAIL] line in the E2E flow.
  • pnpm test:coverage holds the gate on the new job/template/service-diff code.

Context refs

  • lib/jobs/defineJob.ts + definitions/emailSend.ts (1.6.3) — the harness, idempotency, DLQ + the production job exemplar; lib/jobs/types.ts — the typed event map to extend
  • lib/emailTemplates/ contract (CLAUDE.md — pure templates, hand-written plain text); workspaceInvite.tsx as the exemplar
  • lib/mentions/parse.ts + the view-scoping (5.1.2); workItemsService create/update paths (the description diff point)
  • Story 5.7 stub (the in-app consumer of these same events) + Story 5.4 (watchers) — the channel-agnostic payload contract