Skip to content

Triggers #4 — Webhook triggers as detached resources #931

Description

@Griphu

Part of the triggers-detachment epic (part of epic #927).

Goal

Make webhook a table-backed trigger resource. The catch-all webhook route resolves
against the triggers table instead of definition.triggers. Independent of Issues #2/#3.

Depends on

Issue #1 (core model). Independent of #2/#3.

Key fact (settled during grilling)

The webhook callable URL is derived, never stored — the route is a catch-all
[...path] and WebhookRouter.route() computes everything from
namespace/workflowName/path at request time. So a webhook trigger is fully portable as
{ method, path, payloadSchema? }; the only instance-specific part is the host, which the
target already knows. Nothing instance-bound is persisted.

Implementation

  1. Handlers/CLI/UI: extend trigger CRUD to --type webhook with config
    { method, path, payloadSchema? }. Add a "Webhook" panel to the Triggers tab. On
    create, report the derived callable URL
    (https://<host>/api/triggers/webhook/<ns>/<wf>/<path>) — it is a computed view, not
    stored. Enforce webhook-path uniqueness (the partial unique index from Issue Configure Mend Bolt for GitHub #1).

  2. Flip resolution: packages/workflow-engine/src/triggers/webhook-router.ts:88
    (findMatchingWebhookTrigger(definition, suffix)) currently reads def.triggers.
    Inject the trigger repo and resolve against
    triggers WHERE type='webhook' AND enabled AND config->>'path' matches suffix,
    keeping exact-path + method checks.

  3. Payload schema source: today WebhookTrigger takes a schemaRegistry: Map<name, ZodType>. Source those schemas from the trigger rows' config.payloadSchema instead of
    wherever they are populated now, so validation follows the detached trigger.

  4. Backfill migration/seed: create type='webhook' rows from every existing definition's
    webhook triggers ({ method, path }), so existing webhook endpoints keep resolving.

Tests

  • L2: router resolves against the table; 404 when no enabled webhook row matches path;
    405 on method mismatch; payload validation from config.payloadSchema.
  • L3 API-E2E: attach webhook trigger → POST the derived URL → run starts; remove → 404.

Done when

Webhook firing resolves entirely from the triggers table; create reports the derived URL;
CLI + Triggers tab manage webhook triggers; existing webhooks still resolve; suite green.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions