docs(alerting): add BL-002 for native provider integrations + Mustache auto-complete
BL-002 / gitea#138 tracks deferred native provider types (Slack Block Kit, PagerDuty Events v2, Teams connector) with shipped templates as a post-v1 fast-follow once usage data informs which providers matter. Spec §13 folds in context-aware variable auto-complete for the shared <MustacheEditor /> component used in rule editor, webhook overrides, and outbound-connection admin. Available variables filter by condition kind. Completion engine choice added to §20 as a planning-phase decision. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -37,6 +37,38 @@ Deferred items surfaced during design / planning / execution that we've decided
|
||||
|
||||
---
|
||||
|
||||
### BL-002 — Native provider integrations for alerting (Slack, Teams, PagerDuty with shipped templates)
|
||||
|
||||
**Opened:** 2026-04-19
|
||||
**Surfaced by:** [Alerting design](specs/2026-04-19-alerting-design.md) — §2 Out of scope
|
||||
**Tracking:** [gitea#138](https://gitea.siegeln.net/cameleer/cameleer-server/issues/138)
|
||||
**Status:** Open
|
||||
|
||||
**Context.** Alerting v1 ships with generic outbound webhooks + JMustache templates — users paste their Slack incoming webhook URL (or PagerDuty Events API key, or Teams connector URL) and write the body from scratch. A natural fast-follow is to elevate the most common providers to first-class connection types with tuned default templates, provider-specific config hints, and test actions that speak each provider's native format.
|
||||
|
||||
**What's deferred.**
|
||||
- `SLACK_INCOMING_WEBHOOK` connection type with Block Kit default body template and URL-shape validation.
|
||||
- `PAGERDUTY_EVENTS_V2` with routing-key input (not URL) and default body tuned to the Events API v2 — including `dedup_key` tied to alert-instance id, severity mapping, and auto-resolve via `event_action: resolve` on alert RESOLVED.
|
||||
- `MS_TEAMS_CONNECTOR` with adaptive-card/MessageCard default.
|
||||
- Optional follow-ons: Discord, OpsGenie.
|
||||
|
||||
**Acceptance criteria.**
|
||||
- Decide on the first 2 providers based on usage data from alerting v1 (likely Slack + PagerDuty).
|
||||
- Ship templates as versioned resources (`outbound-templates/slack-v1.mustache`) so they can iterate without breaking existing connections.
|
||||
- Golden-file tests per provider type — payload matches current documented format.
|
||||
- Provider-integration guide in docs.
|
||||
|
||||
**Why we're not doing it now.**
|
||||
- Generic webhook + Mustache covers every target today; not a blocker.
|
||||
- Provider schemas drift (Slack deprecated old JSON once; Teams connectors are on a deprecation path as of late 2025); shipping baked-in templates is a maintenance commitment.
|
||||
- Usage data will tell us which providers actually matter — shipping three speculatively is wasted work.
|
||||
|
||||
**Links.**
|
||||
- `cameleer-server-core/src/main/java/com/cameleer/server/core/outbound/` (v1 connection model — extend with `OutboundConnectionType` sealed hierarchy)
|
||||
- Related (different concern): BL-001 / [gitea#137](https://gitea.siegeln.net/cameleer/cameleer-server/issues/137)
|
||||
|
||||
---
|
||||
|
||||
## Closed
|
||||
|
||||
_(nothing yet)_
|
||||
|
||||
@@ -882,6 +882,41 @@ New sidebar/top-nav entry visible to `VIEWER+`. Authoring actions (`POST /rules`
|
||||
4. **Notify** — title + message templates with *Preview* button; targets multi-select (users / groups / roles with typeahead); outbound connections multi-select filtered by current env + `allowed_environment_ids`.
|
||||
5. **Review** — summary card, enabled toggle, save.
|
||||
|
||||
### Template editor — Mustache with variable auto-complete
|
||||
|
||||
Every Mustache template-editable field — notification title, notification message, webhook URL, webhook header values, webhook body — uses a shared `<MustacheEditor />` component with **variable auto-complete**. Users never have to guess what context variables are available.
|
||||
|
||||
**Behavior.**
|
||||
- Typing `{{` opens a dropdown of available variables at the caret position.
|
||||
- Each suggestion shows the variable path (`alert.firedAt`), its type (`Instant`), a one-line description, and a sample rendered value from the canned context.
|
||||
- Filtering narrows the list as the user keeps typing (`{{ale…` → filters to `alert.*`).
|
||||
- `Enter` / `Tab` inserts the path and closes `}}` automatically.
|
||||
- Arrow keys + `Esc` follow standard combobox semantics (ARIA-conformant).
|
||||
|
||||
**Context-aware filtering.** The available variables depend on the rule's condition kind and scope. The editor is aware of both:
|
||||
- Always shown: `env.*`, `rule.*`, `alert.*`
|
||||
- `ROUTE_METRIC` with `route.id` set: adds `route.id`, `app.*`
|
||||
- `EXCHANGE_MATCH`: adds `exchange.*`, `app.*`, `route.id` (if scoped)
|
||||
- `AGENT_STATE`: adds `agent.*`, `app.*`
|
||||
- `DEPLOYMENT_STATE`: adds `deployment.*`, `app.*`
|
||||
- `LOG_PATTERN`: adds `log.*`, `app.*`
|
||||
- `JVM_METRIC`: adds `metric.*`, `agent.*`, `app.*`
|
||||
|
||||
Variables that *might not* populate (e.g., `alert.resolvedAt` while state is FIRING) are shown with a grey "may be null" badge — users still see them so they can defensively template.
|
||||
|
||||
**Syntax checks inline.**
|
||||
- Unclosed `{{` / unmatched `}}` flagged with a red underline + hover hint.
|
||||
- Reference to an out-of-scope variable (e.g., `{{exchange.id}}` in a ROUTE_METRIC rule) flagged with an amber underline + hint ("not available for this rule kind — will render as literal").
|
||||
- Checks run client-side on every keystroke (debounced); server-side render preview is still authoritative (§8).
|
||||
|
||||
**Shared implementation.** Same `<MustacheEditor />` component is used in:
|
||||
- Rule editor — Notify step (title, message)
|
||||
- Rule editor — Webhook overrides (body override, header value overrides; URL not editable per rule, it's the connection's)
|
||||
- Admin **Outbound Connections** editor — default body template, default header values, URL (URL gets a reduced context: only `env.*` since a connection URL is rule-agnostic)
|
||||
- *Test render* inline preview — rendered output updates live as user types
|
||||
|
||||
**Completion engine.** Specific library choice (CodeMirror 6 with a custom completion extension vs Monaco vs a lighter custom overlay on `<textarea>`) is deferred to planning — see §20.
|
||||
|
||||
### Silences, History, Rules list, OutboundConnectionAdminPage
|
||||
|
||||
Structure described in design presentation; no new design-system components required. Reuses `Select`, `Tabs`, `Toggle`, `Button`, `Label`, `InfiniteScrollArea`, `PageLoader`, `Badge` from `@cameleer/design-system`.
|
||||
@@ -1039,3 +1074,4 @@ These are not design-level decisions — they're implementation-phase tasks to b
|
||||
4. **Bell component keyboard shortcut.** Optional; align with existing CMD-K shortcut conventions.
|
||||
5. **Target picker UX.** How to mix user / group / role in one multi-select with typeahead. Small UX design task.
|
||||
6. **Env-delete cascade audit.** Before merge, verify the full cascade chain empirically in a PG integration test — POC safety depends on it.
|
||||
7. **`<MustacheEditor />` completion engine choice.** Decide between CodeMirror 6 with a custom completion extension, Monaco, or a lighter custom-overlay-on-`<textarea>` implementation. Criteria: bundle-size cost, accessibility (ARIA combobox semantics), existing design-system integration. The variable metadata registry (`{path, type, description, sampleValue, availableForKinds[]}`) is the same regardless of engine.
|
||||
|
||||
Reference in New Issue
Block a user