> ## Documentation Index
> Fetch the complete documentation index at: https://docs.encoreos.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Clinical Notification Service Admin Guide

> Version: 1.0.0 Last Updated: 2026-05-11 Module: CL (Clinical) Spec: CL-56 Status: Active

**Version:** 1.0.0
**Last Updated:** 2026-05-11
**Module:** CL (Clinical)
**Spec:** CL-56
**Status:** Active

> **Purpose:** Configure notification policies, escalation chains, and audit exports that govern how clinical signals reach staff.

***

## Overview

The Centralized Clinical Notification Service routes signals (critical labs, medication exceptions, task assignments, etc.) into in-app alerts with severity, SLA, deduplication, and escalation behavior. As an administrator you control:

* **Policies** — per signal type: severity rules, SLA seconds, deduplication window, active toggle.
* **Escalation chains** — ordered recipient roles per severity tier.
* **Audit log** — searchable history of every dispatched event with CSV export.
* **Feature flag** — `cl.notification_service_enabled` global on/off switch.

***

## Prerequisites

| Permission                      | Description                                         |
| ------------------------------- | --------------------------------------------------- |
| `cl.notification_policy.manage` | Create, edit, delete policies and escalation chains |
| `cl.notification_audit.view`    | View the audit log                                  |
| `cl.notification_audit.export`  | Download the audit CSV                              |

These keys are seeded to `org_admin` by default. Grant to additional roles via the Permissions page.

***

## Enabling the Service

The service is governed by the global feature flag `cl.notification_service_enabled` (default: **on**).

1. Open **Platform → Feature Flags**.
2. Locate `cl.notification_service_enabled`.
3. Toggle **off** to immediately disable both the dispatch edge function (returns 503) and the three notification UI pages ("Feature unavailable" empty state).

No code change or redeploy is required to flip the flag.

***

## Managing Policies

Path: **Clinical → Notifications → Policies**.

### Create a Policy

1. Click **New Policy** (top right).
2. Fill the form:
   * **Signal type** — must match a publisher signal (e.g. `lab_critical`, `medication_exception`, `task_assigned`). Unique per organization.
   * **SLA (seconds)** — time before the alert escalates. Examples: `1500` (25 min) for critical labs, `28800` (8 h) for task assignments.
   * **Dedup window (seconds)** — identical signals on the same chart inside this window are suppressed. Use a longer window for noisy sources.
   * **Severity rules (JSON)** — optional rules that promote/demote severity based on payload fields. Default severity comes from the publisher.
3. Click **Save**.

### Edit, Toggle, or Delete

* **Edit** — click a row, modify, save.
* **Active toggle** — switches dispatch on/off without losing configuration.
* **Delete** — the trash icon opens a confirmation dialog. Deletion is permanent; existing events remain in the audit log.

### Severity Rule Tips

* Keep rules narrow and explicit; broad rules cause incorrect routing.
* Avoid PHI in rules — only payload metadata is allowed (a database CHECK constraint blocks PHI fields).

***

## Managing Escalation Chains

Located on the same page, below Policies.

Each chain is keyed by **severity tier** (`critical`, `warning`, `info`) and consists of ordered steps. Each step contains:

* **Step order** — `0` is the first recipient.
* **Recipient role key** — a system role (e.g. `clinical_supervisor`, `medical_director`, `org_admin`).
* **Wait seconds** — optional delay before the SLA evaluator can promote to this step.

### Resolution Rules

1. The dispatch edge function reads step `0` for the alert's severity, resolves the role to a user via `pf_user_role_assignments`, and creates the in-app notification.
2. When the SLA evaluator (cron, every 60 s) finds an unacknowledged event past its deadline, it advances to the next step and inserts a fresh event for the new recipient.
3. If no user is found for a role, the chain falls back to `org_admin` so alerts are never dropped.
4. When the chain is exhausted, the original event is marked `sla_breached` but no further escalation occurs.

### Best Practices

* Always end the chain with `org_admin` (or your equivalent terminal role).
* Keep chains short (≤ 4 steps) — long chains delay clinically important escalations.
* Validate by triggering a synthetic event in a non-production org before publishing.

***

## Audit Log and CSV Export

Path: **Clinical → Notifications → Audit**.

### Filters

* **Date range** (required)
* **Severity** (multi-select)
* **Signal type** (multi-select)
* **SLA status** — On time / Breached

### Columns

`Dispatched At`, `Signal Type`, `Severity`, `Recipient`, `SLA Deadline`, `Acknowledged At`, `SLA Status`, `Escalation Step`.

### Export to CSV

1. Apply filters that scope the result set.
2. Click **Export CSV**.
3. The current filtered view is streamed as CSV (UTF-8, comma delimited).

**Hard cap:** 10,000 rows per export. Narrow the date range or filter further if you hit this limit. The CSV intentionally excludes free-text payload fields to minimize PHI exposure.

### Retention

`cl_notification_events` rows are retained indefinitely. Coordinate with Compliance before bulk deletion; events are part of the clinical audit trail.

***

## Operational Reference

### Edge Functions

| Function                        | Purpose                                                      | Trigger                                      |
| ------------------------------- | ------------------------------------------------------------ | -------------------------------------------- |
| `cl-clinical-notify`            | Resolve policy, dedup, dispatch, persist event               | Called by publishers via `useClinicalNotify` |
| `cl-notification-sla-evaluator` | Promote unacknowledged overdue events to the next chain step | Cron every 60 s                              |

Both functions short-circuit when `cl.notification_service_enabled` is off.

### Tables

* `cl_notification_policies`
* `cl_notification_escalation_chains`
* `cl_notification_events` — append-only event log with `chk_cl_notification_no_phi` CHECK constraint

RLS scopes every read/write to the active organization. The acknowledgement RPC `cl_acknowledge_notification` is `SECURITY DEFINER` and verifies access before stamping `acknowledged_at` / `acknowledged_by`.

***

## Troubleshooting

#### Alerts are not being dispatched

1. Confirm `cl.notification_service_enabled` is on.
2. Verify a policy exists for the signal type and is active.
3. Check `cl-clinical-notify` logs for dedup hits or PF-10 insert errors.

#### Escalations are not advancing

1. Confirm a chain row exists for the next `(severity, step_order)`.
2. Confirm a user holds the chain's role in `pf_user_role_assignments`.
3. Inspect `cl-notification-sla-evaluator` logs for resolution failures (fallback to `org_admin` is logged as a warning).

#### CSV export is empty

* Check the date range; the default may not include recent events.
* Verify the requesting user has `cl.notification_audit.export`.

***

## Related Documentation

* **User Guide:** [cl-56-notification-service-user-guide.md](notification-service-user-guide.md)
* **Specification:** `specs/cl/specs/CL-56-centralized-clinical-notification-service.md`
* **Context:** `specs/cl/specs/CL-56-CONTEXT.md`
* **Implementation Log:** `specs/cl/IMPLEMENTATION_LOG.md`
* **Cross-core Integrations:** `docs/architecture/integrations/CROSS_CORE_INTEGRATIONS.md`

***

**Last Updated:** 2026-05-11
