Eine Channel-Integration schreiben
Das ist eine Entwickler-Referenz für alle, die Structura um einen neuen Channel erweitern. Wenn du suchst, wie du bestehende Channels nutzt, siehe stattdessen Wie Channels funktionieren.
Diese Anleitung führt durch das Hinzufügen einer neuen Integration zum Channels-System. Wir verwenden eine hypothetische „Mailchimp”-Integration als Beispiel.
Schritt 1: Capabilities wählen
Entscheide, welche Capability-Interfaces deine Integration braucht:
| Wenn deine Integration… | Implementiere |
|---|---|
| Fire-and-forget-Benachrichtigungen sendet | NotifiableIntegration |
| Inhalt per KI für die Plattform umschreibt | AdaptableIntegration |
| Inhalt an die API der Plattform postet | PublishableIntegration |
| OAuth 2.0 zur Authentifizierung nutzt | OAuthIntegration |
| Über das Einfügen einer URL konfiguriert wird | WebhookIntegration |
Capabilities sind kombinierbar. LinkedIn implementiert OAuth + Adapt + Publish. Slack implementiert Webhook + Notify. IndexNow implementiert nur Notify.
Schritt 2: Die Integrations-Klasse erstellen
Erstelle
functions/src/channels/integrations/MailchimpIntegration.ts:
import type { FetchLike } from "../contracts/Integration.js";
import type {
Integration,
IntegrationMetadata,
HealthStatus,
ConnectionRecord,
} from "../contracts/Integration.js";
import type { NotifiableIntegration, NotifyContext, NotifyResult } from "../contracts/Integration.js";
export const MAILCHIMP_INTEGRATION_ID = "mailchimp";
export class MailchimpIntegration implements Integration, NotifiableIntegration {
constructor(private readonly fetch: FetchLike = globalThis.fetch) {}
readonly metadata: IntegrationMetadata = {
id: MAILCHIMP_INTEGRATION_ID,
name: "Mailchimp",
category: "email",
sku: "channels", // or "free" for free integrations
capabilities: ["notify"],
authType: "apikey", // or "oauth2", "webhook", "none"
iconUrl: "/icons/mailchimp.svg",
};
async healthCheck(connection: ConnectionRecord): Promise<HealthStatus> {
if (connection.status === "connected") return { status: "healthy" };
return { status: "unhealthy", reason: connection.lastError?.message };
}
async notify(ctx: NotifyContext): Promise<NotifyResult> {
// Implementation here
}
}Schlüsselregeln:
- Akzeptiere
FetchLikeüber den Konstruktor zur Testbarkeit. - Hardcode niemals HTTP-Aufrufe — nutze immer das
injizierte
fetch. - Klassifiziere HTTP-Fehler konsistent (siehe Fehlerklassifizierungs-Tabelle in Channel-Integrations-Verträge).
Schritt 3: Die Integration registrieren
Füge deine Klasse zu
functions/src/channels/registry/IntegrationRegistry.ts
hinzu:
import { MailchimpIntegration } from "../integrations/MailchimpIntegration.js";
const CATALOG: Integration[] = [
// ... existing integrations
new MailchimpIntegration(),
];Schritt 4: Einen Katalog-Eintrag hinzufügen
Füge einen Eintrag zu
functions/src/channels/registry/catalog.ts hinzu:
{
id: "mailchimp",
name: "Mailchimp",
description: "Send email campaigns when posts are published",
category: "email",
capabilities: ["notify"],
authType: "apikey",
gating: {
requiredPlan: "free", // Minimum plan
requiredAddon: "channels", // null if free, "channels" if paid
},
iconUrl: "/icons/mailchimp.svg",
}Schritt 5: Tests schreiben
Erstelle
functions/src/channels/__tests__/MailchimpIntegration.test.ts:
import { describe, it, expect, vi } from "vitest";
import { MailchimpIntegration } from "../integrations/MailchimpIntegration.js";
describe("MailchimpIntegration", () => {
it("has correct metadata", () => {
const integration = new MailchimpIntegration();
expect(integration.metadata.id).toBe("mailchimp");
expect(integration.metadata.capabilities).toContain("notify");
});
it("sends notification on publish", async () => {
const stubFetch = vi.fn().mockResolvedValue({
ok: true, status: 200, json: async () => ({}),
});
const integration = new MailchimpIntegration(stubFetch);
const result = await integration.notify(/* NotifyContext */);
expect(result.status).toBe("ok");
expect(stubFetch).toHaveBeenCalledOnce();
});
// Test error classification for each HTTP status...
});Aktualisiere IntegrationRegistry.test.ts, um die neue
Integration in den erwarteten Zählwerten aufzunehmen.
Schritt 6: Das WordPress-Plugin aktualisieren (falls nötig)
Für credential-basierte oder webhook-basierte Integrationen
sind keine Plugin-Änderungen nötig — die bestehenden
Endpunkte channelsSaveCredentialConnection und
channelsSaveWebhookConnection behandeln alle Auth-Typen
generisch.
Für OAuth-Integrationen behandeln die bestehenden Endpunkte
channelsOAuthInit und channelsOAuthCallback den Flow.
Du musst möglicherweise neue defineSecret()-Einträge für
die Client-ID/das Secret des Anbieters hinzufügen.
Schritt 7: Dokumentation hinzufügen
Erstelle docs/pages/channels/integrations/mailchimp.mdx
mit:
- Wie die Integration funktioniert
- Metadaten-Tabelle
- Form des entschlüsselten Geheimnisses
- Setup-Anweisungen für die Verbindung
- Fehlerbehandlungs-Tabelle
Aktualisiere docs/pages/channels/integrations/_meta.json,
um die neue Seite aufzunehmen.
Checkliste
- Integrations-Klasse, die korrekte Capability-Interfaces implementiert
-
FetchLike-Dependency-Injection - Fehlerklassifizierung für alle HTTP-Statuscodes
- Locale-bewusste Nachrichten (falls NotifiableIntegration)
- Health-Check-Implementierung
- In
IntegrationRegistryregistriert - Katalog-Eintrag mit korrektem Gating
- Unit-Tests (Metadaten, Happy Path, Fehlerfälle, Edge Cases)
- Registry-Test mit neuen erwarteten Zählwerten aktualisiert
- Dokumentationsseite
- Geheimnisse konfiguriert (falls OAuth oder API- Schlüssel)