Decide validations in Slack
A human validation node (human.approve, human.choose) can publish its request to a
Slack channel or to a person, with buttons: Accepter / Refuser, or one button per
option of a choice. A click decides the validation like a decision taken in the console
or the record system: the run resumes and the decision keeps the Slack person who
clicked, the time and the outcome. The message is then rewritten with the outcome; a
validation decided elsewhere, expired or withdrawn updates the message too.
Clicks come back through Socket Mode: Meridian opens a WebSocket to Slack, so the instance needs no public URL.
For the mechanism (the validation port, the validation-decision format), see
Plugin manifest — Validation channels and incoming decisions.
Before you start
- The plugins
@posos/commonand@posos/slackare loaded (core plugins). - Runs use journal format 2:
RUN_JOURNAL_FORMAT=2on the proxy (see Upgrade the platform). With format 1, validations are not published to Slack. - A Slack app installed in the workspace, with:
- Socket Mode enabled and an app-level token (
xapp-…) with theconnections:writescope; - Interactivity enabled (no request URL is needed with Socket Mode);
- a bot token (
xoxb-…) with thechat:writescope, andusers:read.emailto address a person by e-mail; - the bot invited to each target channel.
- Socket Mode enabled and an app-level token (
1. Declare the connections
Three connections, in the instance manifest (connections:) or in the console
(Connexions → Nouvelle connexion):
connections:
slack-garde: # posts the requests (bot token)
type: slack
label: Slack garde
baseUrl: https://slack.com/api
defaultChannel: "#garde-pharma"
auth: { scheme: bearer, token: env:SLACK_BOT_TOKEN }
slack-app: # opens the Socket Mode WebSocket (app-level token)
type: slack-app
label: Application Slack
baseUrl: https://slack.com/api
auth: { scheme: bearer, token: env:SLACK_APP_TOKEN }
slack-decisions: # receives the clicks
type: slack-socket
format: validation-decision
connection: slack-app
| Type | Direction | Role |
|---|---|---|
slack |
outbound | Posts and updates the messages. Parameters defaultChannel, patientContext. |
slack-app |
outbound | Holds the app-level token; used only by the listening connection. |
slack-socket |
inbound | Listens to the clicks (Socket Mode) and hands each decision to the inbox. Parameter connection: the slack-app connection (empty: the default one). |
The listening connection runs on the API process that holds the inbound connections. Its status is shown in Connexions: an app-level token refused by Slack leaves it in error (« Connexion non démarrée. Vérifiez ses paramètres et les droits du process. »).
2. Designate the connection on the validation node
In the editor, select the human.approve or human.choose node and pick the slack
connection in Connexion. In YAML:
nodes:
relire:
type: human.approve
connection: slack-garde
config:
type: String
title: Relire la prescription
message: Vérifier la posologie avant envoi.
recipients: "#garde-pharma, dr.martin@chu.fr"
deadlineSeconds: 3600
orienter:
type: human.choose
connection: slack-garde
config:
type: String
title: Orienter le patient
options:
- { id: cardio, label: Cardiologie }
- { id: nephro, label: Néphrologie }
recipients lists channels (#garde-pharma, C0123456789) and people (U0123456789,
or an e-mail address resolved with users.lookupByEmail), separated by commas; absent,
the connection's defaultChannel applies. A person receives the request as a direct
message from the app. A node without a connection uses ports.validation of the
instance when one is bound, else publishes nowhere.
human.choose has one output per option, named by its id; the chosen option's output
carries the value. Choice validations are decided in Slack or the console; they are not
published to the record system (FHIR Task), which handles accept / reject only.
3. Decide what goes to Slack
The message shows the title, the message, the workflow name and the deadline. The
submitted value is not shown. The identifier of the patient in context is added only
when the slack connection sets patientContext: true (false by default). Slack is not
a health data host: keep patient data out of the title and the message unless your
organisation allows it.
Who decides
Anyone who sees the message can click. The decision is recorded with the Slack name and
identifier of that person, for example pierre (Slack U0123456789). The first decision
applies; a later click, in Slack or elsewhere, is refused and logged by the API
(« décision refusée »).
Verify
- Start a run that reaches the validation node: the request appears in the channel with its buttons, and in the console under the run.
- Click a button: the run resumes, the console shows the decision with its author, and the Slack message shows the outcome in place of the buttons.
If nothing is posted, the engine logs « publication de la demande de validation
échouée » (« … incomplète » when the record system received the request) with Slack's
answer, for example
[slack] chat.postMessage (connexion « slack-garde », canal #garde) : refusé par Slack (not_in_channel).:
invite the bot to the channel. If the request is posted to several recipients and one
fails, the messages already posted are withdrawn and the validation stays to decide in
the console.
Related
- Send notifications — the same
slackconnection for notifications. - Manage connections — declare, create, designate connections.
- Run and resolve — decisions through the API, choice validations.
- Bundled plugins —
@posos/common,@posos/slack.