Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions .changeset/24753-approval-decision-notifies-submitter.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
"@objectstack/plugin-approvals": minor
---

feat(plugin-approvals): the decision that ends an approval tells its submitter the outcome (`approval.approved` / `approval.rejected`)

Clause-②: yes (widening)

- **What was wrong.** Approving or rejecting a request notified nobody. A send-back (`approval.returned`) and a question (`approval.request_info`) reached the submitter, but the decision itself did not, so a submitter learned that their request was approved or rejected only by opening the Approvals Inbox.
- **What is new.** When a decision ends the approval, the submitter of the request it decides gets one notification on one of two new topics: `approval.approved` (title "Request approved") or `approval.rejected` (title "Request rejected"). The body names the record by its object's label and its id, as every approval notification does (`Your Deal D_123 was rejected.`), followed by the decider's comment as its own paragraph when they wrote one. It links to that request in the Approvals Inbox and, like the other approval notices, carries as its actor the person the decision's context vouches for. It goes through the installed `messaging` service like every other approval topic, so the same channels and delivery preferences apply; a preference row can mute one outcome and keep the other.
- **When "ends the approval" holds.** A co-sign vote that leaves a `unanimous`, `quorum` or `per_group` request pending tells no one. A decision whose flow moves on to another approval step tells no one either; the decision that ends the run is the one that notifies. That is read from the run after the decision resumes it, not from the flow's graph, so when a decision node routes around a later step, the first decision is the outcome.
- **Who is not told.** A submitter who decided their own request. And an SLA escalation's `auto_approve` or `auto_reject`: the escalation's own submitter notice (`approval.sla_breached`, naming the action taken) is the one message about it, so `escalation.notifySubmitter: false` still means the submitter hears nothing. A decision whose flow run cannot be resumed reports its failure to the decider and tells the submitter nothing, as a send-back in the same state already did.
- **What to change in your flows.** If a flow ends with a `notify` node whose only job is to tell the submitter the decision, remove it, or the submitter is told twice. `notify` nodes that address anyone else are unaffected. No flow in this repository's examples has that workaround: the three showcase flows whose `notify` node reports a decision address someone other than the submitter — `showcase_invoice_signoff` and `showcase_project_closure` the record's owner, `showcase_release_signoff` a fixed address — so they are unchanged, and only a record owner who is also the person who submitted now hears both.
31 changes: 29 additions & 2 deletions content/docs/automation/approvals.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -536,8 +536,35 @@ second one for the opening.

If a flow has a `notify` node beside its approval node only to tell the
approvers that a request is waiting, remove that node: those approvers are now
told twice. Keep `notify` nodes that address someone else, such as the
submitter or a watcher, or that report the decision.
told twice. Keep `notify` nodes that address someone else, such as a watcher,
or that report the decision to anyone but the submitter.
</Callout>

<Callout type="info">
**The decision tells the submitter.** When a decision ends the approval, the
submitter of the request it decides gets one notification: `approval.approved`
("Request approved") or `approval.rejected` ("Request rejected"). Its body
names the record (`Deal D_123`) and the outcome, followed by the decider's
comment when they wrote one, and it links to that request in the Approvals
Inbox. There is one topic per outcome, so a delivery preference can mute
approvals and keep rejections.

"Ends the approval" means the process, not the step. A co-sign vote that
leaves a `unanimous`, `quorum` or `per_group` request pending tells no one,
and neither does a decision whose flow moves on to another approval step: on
a two-step flow the first step's decision is silent and the decision that ends
the run is the one that notifies. Whether a later step opened is read from the
run, not from the flow's graph, so when a decision node routes around the
later step, the first decision is the outcome and notifies.

Two cases tell nobody by design. A submitter who decided their own request
already knows. An SLA `auto_approve` or `auto_reject` is told by the
escalation's own submitter notice (`approval.sla_breached`, which names the
action taken), so `notifySubmitter: false` still means the submitter hears
nothing about it.

If a flow ends with a `notify` node whose only job is to tell the submitter
the decision, remove that node: the submitter is now told twice.
</Callout>

### Mount the approvals inbox in your app
Expand Down
Loading
Loading