From 8e20f09b65873e31e8b04c76ec3680ba301e8397 Mon Sep 17 00:00:00 2001
From: Konstantinos Kopanidis
Date: Mon, 22 Jun 2026 15:31:14 +0300
Subject: [PATCH] docs(web): expand communications module page
---
.../content/docs/modules/communications.mdx | 188 +++++++++++++-----
.../deep-dives/communications-deep-dive.mdx | 131 ++++++++++++
2 files changed, 270 insertions(+), 49 deletions(-)
create mode 100644 apps/web/src/mdx/deep-dives/communications-deep-dive.mdx
diff --git a/apps/web/content/docs/modules/communications.mdx b/apps/web/content/docs/modules/communications.mdx
index 6877b0fb..afe46f6c 100644
--- a/apps/web/content/docs/modules/communications.mdx
+++ b/apps/web/content/docs/modules/communications.mdx
@@ -1,10 +1,14 @@
---
title: Communications
-description: Unified email, SMS, and push notifications (replaces legacy modules).
-agent_summary: "v0.17 unified communications; email/SMS/push via Admin API and grpcSdk; MCP ?modules=communications; Handlebars templates."
+description: Unified email, SMS, and push — one module, three channels, orchestrated delivery.
+agent_summary: "v0.17 unified communications; Admin /email /push /sms; EmailTemplate + CommunicationTemplate; orchestrator multi-channel/fallback; grpcSdk legacy aliases; MCP ?modules=communications."
---
-In **v0.17**, separate **email**, **sms**, and **push-notifications** modules are consolidated into **communications** — one module, one config namespace, three channels.
+import CommunicationsDeepDive from "@/mdx/deep-dives/communications-deep-dive.mdx";
+
+Your app needs to reach users on email, push, and SMS — without operating three separate modules, credential sets, and send paths. The **communications** module is the unified messaging layer: one config namespace, channel-specific Admin API routes under `/email`, `/push`, and `/sms` (not `/pushNotifications`), plus orchestration for multi-channel and fallback delivery.
+
+In **v0.17**, legacy **email**, **sms**, and **push-notifications** modules consolidate here. Existing `grpcSdk.email`, `grpcSdk.pushNotifications`, and `grpcSdk.sms` calls continue to work; new integrations can use `grpcSdk.communications` for orchestrated sends. Sending from application runtime stays server-side — never admin credentials in the browser.
## Use cases
@@ -12,19 +16,23 @@ In **v0.17**, separate **email**, **sms**, and **push-notifications** modules ar
items={[
{
title: "Transactional email",
- outcome: "Welcome emails, receipts, password resets via Handlebars templates",
+ outcome: "Welcome emails, receipts, password resets via Handlebars EmailTemplate",
},
{
title: "Push notifications",
- outcome: "FCM device tokens registered from apps; send via Admin API or workers",
+ outcome: "FCM/OneSignal device tokens registered from apps; send via Admin API or workers",
},
{
title: "SMS & 2FA",
- outcome: "Twilio or AWS SNS for verification codes and alerts",
+ outcome: "Twilio Verify, AWS SNS, or MessageBird for verification codes and alerts",
},
{
title: "Multi-channel orchestration",
- outcome: "Fallback chains (email then push) configured admin-side",
+ outcome: "Broadcast to email + push + SMS, or fallback chains when a channel fails",
+ },
+ {
+ title: "Unified templates",
+ outcome: "CommunicationTemplate documents coordinate copy across channels for GitOps export",
},
]}
/>
@@ -33,26 +41,36 @@ In **v0.17**, separate **email**, **sms**, and **push-notifications** modules ar
-## Example: Transactional email + push token
+## Example: Template, email send, and fallback
+ Hi {{name}}, welcome aboard.
"}'`}
+ />
+
## How it works
-### API surfaces
+
+
-| Layer | Role |
-|-------|------|
-| **Client API** | Device token registration, in-app notification inbox |
-| **Admin API** | Send email/push/SMS, template CRUD, delivery history |
-| **gRPC / grpc-sdk** | Server-side sending from custom modules (`grpcSdk.email`, etc.) |
+## Configure
-Legacy grpc-sdk client names (`grpcSdk.email`, `grpcSdk.pushNotifications`, `grpcSdk.sms`) route to communications automatically.
+Patch via MCP `patch_config_communications` (`?modules=communications` or aliases `email`, `push`, `sms`):
+
+| Key | Default | Meaning |
+|-----|---------|---------|
+| `email.active` | `false` | Enable email channel |
+| `email.transport` | `smtp` | Provider: `smtp`, `sendgrid`, `mailgun`, `amazonSes`, `mandrill`, `mailersend` |
+| `email.sendingDomain` | `conduit.com` | Appended to bare sender names |
+| `email.storeEmails.enabled` | — | Persist sent email records for resend/history |
+| `pushNotifications.active` | `false` | Enable push channel |
+| `pushNotifications.providerName` | — | `firebase`, `onesignal`, `amazonSns` |
+| `sms.active` | `false` | Enable SMS channel |
+| `sms.providerName` | `twilio` | `twilio`, `awsSns`, `messageBird` |
+| `sms.twilio.verify.active` | `false` | Twilio Verify for OTP flows |
+| `orchestration.retryAttempts` | `3` | Retries per channel send |
+| `orchestration.fallbackTimeout` | `5000` | Default fallback step timeout (ms) |
-### Templates
+## Client API
-Email templates use Handlebars (`{{variableName}}`) in subject and body. Variables are extracted on create. Reference `templateName` when sending — provision templates at deploy time, not from app runtime.
+Push and in-app notification routes (authenticated). Served at the router root (no module prefix):
-### Migration from v0.16
+| Method | Path | Purpose |
+|--------|------|---------|
+| POST | `/token` | Register device token `{ token, platform }` |
+| DELETE | `/token` | Clear tokens; optional `?platform=` |
+| GET | `/notifications` | In-app inbox (`read`, `skip`, `limit`, `platform`) |
+| PATCH | `/notifications` | Mark read `{ id }` or `{ before }` |
-Standalone email, sms, and push-notifications modules are replaced. MCP aliases `?modules=email,push,sms` still work. See [Migration guide](/docs/resources/migration-v0.16-to-v0.17).
-
+**Sending** email, SMS, or push is Admin API or grpc-sdk only — not from browser-exposed app code.
-## Configure
+## Admin API
-MCP: `?modules=communications` (aliases: `email`, `push`, `sms`).
+All routes require Admin API authentication. Default Admin port: `3030`. Paths use `/email`, `/push`, `/sms` — never `/pushNotifications`.
-| Tool | Purpose |
-|------|---------|
-| `get_config_communications` | Read email, push, SMS, orchestration |
-| `patch_config_communications` | Provider credentials and channel settings |
-| `post_email_templates` | Create Handlebars template |
+### `/email`
-Config nests `email`, `pushNotifications`, `sms`, and `orchestration` under the communications key.
+| Method | Path | Purpose |
+|--------|------|---------|
+| POST | `/email/send` | Send — `templateName` or inline `subject` + `body` |
+| GET | `/email/templates` | List EmailTemplates (`skip`, `limit`, `sort`, `search`) |
+| POST | `/email/templates` | Create EmailTemplate |
+| PATCH | `/email/templates/:id` | Update EmailTemplate |
+| DELETE | `/email/templates/:id` | Delete EmailTemplate |
+| GET | `/email/templates/external` | List provider-managed templates |
+| POST | `/email/templates/external/sync` | Sync external templates into Conduit |
+| POST | `/email/resend` | Resend by email record `{ id }` |
+| GET | `/email/emails` | Sent email history |
+| GET | `/email/emails/:id` | Single email record |
+
+### `/push`
-## Client API
+| Method | Path | Purpose |
+|--------|------|---------|
+| POST | `/push/send` | Send — `userId`, `title`, `body`, optional `data`, `platform`, `isSilent`, `doNotStore` |
+| GET | `/push/tokens` | List device tokens |
+| GET | `/push/tokens/:id` | Single token |
+| DELETE | `/push/tokens/:id` | Remove token |
-Push and in-app notification routes (authenticated). v0.17 unified communications serves these at the router root (no module prefix):
+### `/sms`
| Method | Path | Purpose |
|--------|------|---------|
-| POST | `/token` | Register FCM/device token `{ token, platform }` |
-| DELETE | `/token` | Clear tokens; optional `?platform=` |
-| GET | `/notifications` | In-app inbox (`read`, `skip`, `limit`, `platform`) |
-| PATCH | `/notifications` | Mark read `{ id }` or `{ before }` |
+| POST | `/sms/send` | Send SMS — `to`, `message` |
+| GET | `/sms/messages` | Sent SMS history |
+| GET | `/sms/messages/:id` | Single SMS record |
-**Sending** email/SMS/push is Admin API or grpc-sdk — not from browser-exposed app code with admin credentials.
+### Orchestrator (`/send`)
+
+| Method | Path | Purpose |
+|--------|------|---------|
+| POST | `/send/multiple` | Multi-channel broadcast — `channels`, `strategy`, `recipient`, `subject?`, `body?`, `variables?` |
+| POST | `/send/fallback` | Fallback chain — `fallbackChain[{ channel, timeout }]`, `recipient`, `subject?`, `body?`, `variables?` |
+
+### CommunicationTemplate (GitOps)
+
+Multi-channel **CommunicationTemplate** documents have no dedicated Admin REST CRUD yet. Manage via [state export/import](/docs/guides/gitops-state-export) (`communicationTemplates`), direct database provisioning, or gRPC `RegisterCommunicationTemplate` from server-side workers (placeholder until unified template CRUD is complete).
+
+## grpc-sdk
+
+| Client | Use when |
+|--------|----------|
+| `grpcSdk.email` | Legacy email send, template register, status — routes to communications |
+| `grpcSdk.pushNotifications` | Legacy push send, token management |
+| `grpcSdk.sms` | Legacy SMS send, Twilio Verify |
+| `grpcSdk.communications` | Unified API: `sendMessage`, `sendToMultipleChannels`, `sendWithFallback`, `getMessageStatus` |
+
+Never import grpc-sdk in client components or browser bundles.
## MCP
-- `?modules=communications`
-- Aliases: `?modules=email,push,sms`
-- Note: `push-notifications` is not a valid MCP alias — use `push` or `communications`
+- `?modules=communications` — full module tools and config
+- Aliases: `?modules=email`, `?modules=push`, `?modules=sms`, or `?modules=email,push,sms`
+- **Invalid:** `push-notifications` — use `push` or `communications`
+
+| Tool | Purpose |
+|------|---------|
+| `get_config_communications` | Read email, push, SMS, orchestration settings |
+| `patch_config_communications` | Provider credentials and channel toggles |
+| `post_email_templates` | Create Handlebars EmailTemplate |
diff --git a/apps/web/src/mdx/deep-dives/communications-deep-dive.mdx b/apps/web/src/mdx/deep-dives/communications-deep-dive.mdx
new file mode 100644
index 00000000..2572e733
--- /dev/null
+++ b/apps/web/src/mdx/deep-dives/communications-deep-dive.mdx
@@ -0,0 +1,131 @@
+### Unified module, channel-scoped Admin paths
+
+One **communications** module owns all three channels. Admin routes register at the **router root** — there is no `/communications` prefix:
+
+| Prefix | Purpose |
+|--------|---------|
+| `/email/*` | Send, templates, delivery history, resend |
+| `/push/*` | Send notifications, manage device tokens — **not** `/pushNotifications` |
+| `/sms/*` | Send SMS, delivery history |
+| `/send/*` | Orchestrator — multi-channel broadcast and fallback |
+
+Config nests push settings under `pushNotifications` (legacy key name); Admin API paths use `/push`.
+
+### API surfaces
+
+| Layer | Role |
+|-------|------|
+| **Client API** | Device token registration, in-app notification inbox (router root, no prefix) |
+| **Admin API** | Send email/push/SMS, template CRUD, delivery history, orchestration |
+| **gRPC / grpc-sdk** | Server-side sending from custom modules (`grpcSdk.email`, `grpcSdk.communications`, …) |
+
+Legacy grpc-sdk clients (`grpcSdk.email`, `grpcSdk.pushNotifications`, `grpcSdk.sms`) route to communications automatically.
+
+### Templates: EmailTemplate vs CommunicationTemplate
+
+**EmailTemplate** — email-only Handlebars templates. Full Admin CRUD at `/email/templates`. Variables are auto-extracted from `{{placeholders}}` in subject and body on create. Reference by **`templateName`** when calling `POST /email/send` or `grpcSdk.email.sendEmail`.
+
+| Field | Purpose |
+|-------|---------|
+| `name` | Unique identifier — used as `templateName` when sending |
+| `subject`, `body` | Handlebars strings |
+| `variables` | Auto-derived from `{{…}}` placeholders |
+| `sender` | Optional override sender |
+| `externalManaged` | Sync with SendGrid/Mailgun provider templates |
+
+**CommunicationTemplate** — unified multi-channel template stored in the database. One document covers every channel the message uses:
+
+| Field | Purpose |
+|-------|---------|
+| `name` | Unique template identifier |
+| `channels` | `['email', 'push', 'sms']` — which channels this template serves |
+| `email` | `{ subject, body, sender? }` — Handlebars in subject/body |
+| `push` | `{ title, body }` — `{{variable}}` interpolation |
+| `sms` | `{ message }` — `{{variable}}` interpolation |
+| `variables` | Declared variable names shared across channels |
+
+CommunicationTemplate documents are **exportable/importable** via [state export](/docs/guides/gitops-state-export) (`communicationTemplates` resource type). Provision at deploy time alongside EmailTemplates.
+
+For **EmailTemplate**, use Admin REST (`POST /email/templates`) or MCP `post_email_templates`. For **CommunicationTemplate**, prefer GitOps state import or direct database provisioning today. gRPC `RegisterCommunicationTemplate` is the orchestrator registration hook (server-side grpc-sdk only); it currently returns a minimal placeholder response — full unified Admin REST CRUD for CommunicationTemplate is not exposed yet.
+
+### Sending with `templateName`
+
+| Path | `templateName` behavior |
+|------|-------------------------|
+| `POST /email/send` | Resolves **EmailTemplate** by name; compiles Handlebars with `variables`. Omit only when providing inline `subject` + `body`. |
+| `grpcSdk.email.sendEmail(templateName, …)` | Same resolution as Admin API |
+| `POST /send/multiple`, `POST /send/fallback` | Inline `subject`, `body`, `variables` per channel — **no** `templateName` lookup on REST |
+| gRPC `SendToMultipleChannels`, `SendWithFallback` | Accept `templateName` in the proto for CommunicationTemplate resolution |
+| `POST /push/send`, `POST /sms/send` | Inline `title`/`body` or `message` — no template lookup |
+
+```typescript
+// Email — template by name (server-side only)
+await grpcSdk.email!.sendEmail("WelcomeEmail", {
+ email: "user@example.com",
+ variables: { name: "Alex" },
+});
+
+// Orchestrator — multi-channel broadcast
+await grpcSdk.communications!.sendToMultipleChannels(
+ ["email", "push"],
+ "BEST_EFFORT",
+ {
+ recipient: "user@example.com",
+ subject: "Order shipped",
+ body: "Your order {{orderId}} is on the way",
+ variables: { orderId: "ORD-42" },
+ }
+);
+```
+
+### Orchestration
+
+The orchestrator coordinates delivery across channels through two Admin API entry points:
+
+| Admin route | Strategy | Behavior |
+|-------------|----------|----------|
+| `POST /send/multiple` | `BEST_EFFORT` or `ALL_OR_NOTHING` | Parallel send to listed channels; `ALL_OR_NOTHING` fails if any channel fails |
+| `POST /send/fallback` | Ordered chain | Try each channel in sequence with per-step `timeout` (ms) until one succeeds |
+
+`POST /send/multiple` returns `{ successCount, failureCount, results[] }`. `POST /send/fallback` returns `{ successfulChannel, messageId, attempts[] }`.
+
+Orchestration config (`retryAttempts`, `retryDelay`, `timeout`, `fallbackTimeout`) lives under `communications.orchestration`.
+
+### Migration from v0.16
+
+Standalone **email**, **sms**, and **push-notifications** modules are deprecated. Communications is a drop-in replacement:
+
+1. **Deploy** — register `Communications` instead of three separate modules.
+2. **Config** — nest legacy keys under `communications` (example below).
+3. **Code** — existing `grpcSdk.email`, `grpcSdk.pushNotifications`, `grpcSdk.sms` calls continue unchanged.
+4. **MCP** — use `?modules=communications` or aliases `?modules=email,push,sms`. `push-notifications` is **not** a valid alias.
+
+```yaml
+communications:
+ active: true
+ email:
+ active: true
+ transport: sendgrid
+ sendingDomain: example.com
+ transportSettings:
+ sendgrid:
+ apiKey: "…"
+ pushNotifications: # config key — Admin paths use /push
+ active: true
+ providerName: firebase
+ firebase:
+ projectId: "…"
+ sms:
+ active: true
+ providerName: twilio
+ twilio:
+ accountSID: "…"
+ authToken: "…"
+ orchestration:
+ retryAttempts: 3
+ fallbackTimeout: 5000
+```
+
+On first boot, communications can auto-merge legacy top-level `email`, `pushNotifications`, and `sms` config into the unified namespace when channel values still match defaults. Legacy gRPC service names are preserved on the unified `Communications` gRPC service.
+
+See [Migration guide](/docs/resources/migration-v0.16-to-v0.17).