Repository navigation
feat(notification): include task/doc title in email event payload - #553
Conversation
There was a problem hiding this comment.
ℹ️ Minor suggestions only.
Reviewed changes
entity_titleon notification plugin events — adds a title field to thenotification.{assigned,mentioned,doc_mentioned,task_description_mentioned}payloads, resolved via a new optionalSvc.WithTitleLookup(taskRepo, docRepo); empty when no lookup is configured or the entity can't be loaded, so a subscribing plugin must tolerate an empty value.- Best-effort title helpers —
taskTitle/docTitlereturn""on a nil repo or lookup error; the mention paths resolve the title once per call and only after the project-membership check for the client-supplied doc/task-description mentions. - Bootstrap wiring + tests —
WithTitleLookup(taskRepo, docRepo)wired inbootstrap; new unit tests assert the lookup runs (once for multi-mention comments, zero for a non-member).go test ./internal/service/notification/...passes.
The anti-leak ordering is preserved: for NotifyDocMentioned/NotifyTaskDescriptionMentioned the title is resolved only after FindMemberByUserProject, and no event is published for a non-member. Adding a JSON key is backward compatible for subscribers.
ℹ️ Nitpicks
- The new tests assert lookup counts but never that
entity_titleactually appears in the published payload, so they would still pass if the field were dropped frompublishNotificationEventor wired to the wrong helper. Capturing the payload is awkward here becausemessaging.Publisheris a concrete Redis-backed struct and the file runs with a nil publisher, so this is understandable — but it means the feature's output is only covered indirectly.
deepseek-v4.1-flash (free via Pullfrog for OSS) | 𝕏
|
Thanks for the review — addressed both points in
|
There was a problem hiding this comment.
✅ No new issues found.
Reviewed changes
- Title-only lookups —
taskLookup/docLookupnow resolveentity_titlethrough the newFindTaskTitleByID/FindDocumentTitleByIDrepository methods instead of loading the full task/document row, replacing the eager full-entity reads the prior review flagged. - Fakeable publisher — a minimal
eventPublisherinterface (Append+Publish) replaces the concrete*messaging.PublisherinNew, so a test can capture what is published;*messaging.Publisherstill satisfies it. - Payload assertion test —
TestNotifyAssigned_PublishesEntityTitlecaptures theAppendpayload and assertsentity_title, directly covering the previously count-only gap.
go build ./..., go vet, and go test ./internal/service/notification/... ./internal/repository/postgres/... all pass.
deepseek-v4.1-flash (free via Pullfrog for OSS) | 𝕏
pikann
left a comment
There was a problem hiding this comment.
LGTM! Please fix the failing lint check before merging.
Thank you for your contribution! 🚀
The notification.{assigned,mentioned,doc_mentioned,
task_description_mentioned} events published to plugins carried only
actor_name and link_url, so a subscribing email plugin had no way to
name the task/document — the email could only say "a task was assigned
to you" with a bare link.
Add an entity_title field to the payload, resolved best-effort via a new
WithTitleLookup(taskRepo, docRepo) option: when no lookup is configured
or the entity can't be loaded, the title is simply empty and behaviour is
identical to before, so a subscribing plugin must tolerate an empty
entity_title. For the mention topics (whose IDs come from client-supplied
content) the title is only resolved after the existing project-membership
check, preserving the current anti-leak guarantee.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Addresses the PR review: - entity_title now resolves via dedicated FindTaskTitleByID / FindDocumentTitleByID (SELECT title) instead of FindTaskByID / FindDocumentByID, which pulled the full row (task description JSONB + a second assignee query; full document content) just to read a title on the synchronous comment/doc-update path. - The publisher is now an eventPublisher interface so a unit test can capture the published payload and assert entity_title carries the resolved title — not only that the lookup ran. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The repo-wide `golangci-lint run ./...` (api-pr-ci's Lint job) fails on `net.Listen` in email_test.go, added by 27b1029 (the GHSA-f2mf-mg99-22w5 netguard fix) — a pre-existing violation unrelated to this PR's change, but it turns the Lint check red on every PR built against current master. Switch to (*net.ListenConfig).Listen with context, exactly as the noctx linter prescribes, so the Lint job passes. `golangci-lint run ./...` is now clean (0 issues). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
eaad653 to
88bca4f
Compare
|
Thanks @pikann for the review and for merging the plugin side! 🙏 Fixed the failing Lint check: I rebased this branch onto current Verified locally: The branch now needs a maintainer to re-approve the workflow run so CI re-runs. |

Why
The
notification.{assigned,mentioned,doc_mentioned,task_description_mentioned}events published to plugins carry onlyrecipient_*,actor_nameandlink_url. A subscribing email plugin (the first-partycom.paca.smtp) therefore can't name the task/document the notification is about — the email can only say "A task was assigned to you" with a bare link, while the in-app notification already shows the task title. This closes that gap so the email can match.What
entity_titlefield to the notification event payload (the task title forassigned/mentioned/task_description_mentioned, the document title fordoc_mentioned).Svc.WithTitleLookup(taskRepo, docRepo). Both lookups are optional: when a repo is nil or the entity can't be loaded,entity_titleis simply empty and behaviour is identical to before — so a subscribing plugin must tolerate an empty value.taskLookup/docLookup), matching the existinguserLookup/memberLookuppattern; the real repositories satisfy them. Wired inbootstrap.Testing
go build ./...,go vet ./...clean.notification/service_test.gocover: the title is resolved for assignments; resolved once for a multi-mention comment; and resolved only after the membership check for the client-supplied mention topics (zero lookups for a non-member).🤖 Generated with Claude Code