DokumentationMethacore Apps

Externe Apps & SDK

11 min Lesezeit · zuletzt aktualisiert 23. September 2026

Eine externe App ist deine eigene Web-App – HTML, React, Next.js, egal – unter deiner eigenen Adresse. Methacore lädt sie im Dashboard in einem Iframe und in der Mitglieder-App in einer WebView. Mit @methacore/sdk meldet sie sich an, spricht die APIs, nutzt den App-Speicher und exportiert Dateien.

Gehostete Apps aus dem Studio brauchen das SDK nicht. Es ist ausschließlich für externe Apps gedacht.

Voraussetzungen

WasRegel
Adressenur https://, mit gültigem Zertifikat
Domainder Host der Adresse muss zu den autorisierten Domains des DevHub-Projekts gehören
Einbettendeine Seite muss sich im Dashboard (https://admin.methacore.de) einbetten lassen – kein X-Frame-Options: DENY, und falls du frame-ancestors setzt, muss das Dashboard darin stehen
Eintragim DevHub unter Methacore-App: Art Extern, die Adresse unter „Externe Adresse“
OAuth-Clientein Client der API „Methacore Apps“ mit den Scopes deiner App

Installieren

npm install @methacore/sdk

Das Paket gibt es als ES-Modul und CommonJS, mit Typen. Einen globalen Build (<script>) gibt es nicht; nimm einen Bundler.

Einstieg

import { createMethacore } from "@methacore/sdk";

export const mc = createMethacore({
  clientId: "cl_7d2e41a9",
  scopes: ["mc.me.profile:read", "mc.me.events:read"],
});

const profil = await mc.api.apps.me.profile();
const { items: termine } = await mc.api.apps.me.events();

createMethacore erkennt selbst, wo die App läuft:

ModusWannWoher das Token kommt
Hostim Iframe des Dashboards oder in der WebView der Mitglieder-Appvom Host über die Bridge. Der Host führt die Zustimmung durch – du baust keinen Login.
Eigenständigdirekt im Browser unter deiner Adressevom SDK selbst: OAuth mit PKCE gegen den DevHub

mc.inHost() sagt dir, welcher Modus gilt.

Im Host

Im Host fragt das SDK den Host per postMessage nach Kontext und Token. Nichts davon musst du selbst anstoßen:

import { createMethacore, host } from "@methacore/sdk";

const mc = createMethacore({ clientId: "cl_7d2e41a9", scopes: ["mc.me.groups:read"] });

if (mc.inHost()) {
  const context = await host.context();
  // { organisation: { id, name }, user: { id, firstName }, theme, locale, target, endpoints }
  document.documentElement.dataset.theme = context.theme;
  host.on("theme", ({ theme }) => (document.documentElement.dataset.theme = theme));
}

const gruppen = await mc.api.apps.me.groups();
await host.toast(`${gruppen.items.length} Gruppen geladen`, "green");
AufrufBedeutung
host.context()Verein, Mitglied, Thema, Sprache, Plattform und die Adressen (endpoints)
host.token(scopes?)ein Access-Token, bei Bedarf mit Zustimmung
host.toast(message, color?)Hinweis im Host
host.navigate(path)zu einer Seite des Hosts wechseln
host.download({ filename, mime, base64 })Datei herunterladen bzw. teilen
host.close()App schließen
host.on("theme", handler)Themenwechsel des Hosts

Die Bridge ist dasselbe Protokoll, das auch gehostete Apps sprechen: Nachrichten { mc: 1, id, type, payload }, Antworten { mc: 1, id, ok, result | error }. Ohne Antwort bricht eine Anfrage nach 15 Sekunden ab.

Das Iframe im Dashboard erlaubt externen Apps Skripte, Formulare, Downloads, Pop-ups und die eigene Origin – localStorage und Cookies deiner Domain funktionieren also. In der Mitglieder-App gilt, was eine WebView erlaubt.

Eigenständig: Anmeldung mit PKCE

Öffnet jemand deine App direkt, meldet sie sich selbst an:

import { createMethacore, AuthError } from "@methacore/sdk";

const mc = createMethacore({
  clientId: "cl_7d2e41a9",
  scopes: ["mc.me.profile:read"],
  redirectUri: "https://app.example.de/callback",
});

// auf /callback
if (location.pathname === "/callback") {
  await mc.auth.handleRedirect(); // prüft state, tauscht code + verifier gegen Tokens
  history.replaceState(null, "", "/");
}

try {
  const profil = await mc.api.apps.me.profile();
} catch (error) {
  if (error instanceof AuthError && error.code === "login_required") await mc.auth.login();
  else throw error;
}
MethodeBedeutung
auth.login()leitet zur Zustimmung des DevHub weiter
auth.beginLogin()liefert nur die Autorisierungs-URL, z. B. für einen eigenen Knopf
auth.handleRedirect(url?)verarbeitet die Rückkehr, speichert die Tokens
auth.getToken()gültiges Access-Token, erneuert es mit dem Refresh-Token
auth.logout()vergisst die Tokens

Tokens liegen standardmäßig im localStorage unter mc.sdk.token.<clientId>; eigene Ablage über die Option storage. Der Client ist öffentlich – es gibt kein Client-Secret im Browser.

Redirect-URIs

  • Im Host brauchst du keine: der Host meldet sich über https://apps-run.methacore.de/oauth/callback an, und diese Adresse lässt der DevHub für jeden Client der API „Methacore Apps“ zu.
  • Eigenständig muss die Redirect-URI auf einer autorisierten Domain des Projekts liegen und https sprechen. Für die Entwicklung ist http://localhost bzw. http://*.localhost erlaubt.

Ohne redirectUri nimmt das SDK die aktuelle Seite (Origin und Pfad).

Lokal entwickeln

import { configure } from "@methacore/sdk";

configure({
  authBase: "http://localhost:8000",               // DevHub-API
  apiBase: "http://{section}.api.localhost:8080/v1", // {section} wird ersetzt, z. B. apps
  redirectUri: "http://localhost:3000/callback",
});

Im Host gelten immer die Adressen, die der Host im Kontext mitschickt; configure wirkt nur eigenständig.

Scopes nachfordern

Antwortet die API mit 403 und does not carry the <scope> scope, holt das SDK den Scope nach:

  • im Host einmal über auth.token mit reauthorize: true – der Host zeigt „Zugriff erweitern“ – und wiederholt den Aufruf einmal,
  • eigenständig mit einer neuen Anmeldung, die den zusätzlichen Scope verlangt (die Seite wird dabei verlassen).

API-Client

await mc.api.apps.me.profile();        // Profile
await mc.api.apps.me.groups();         // { items: Group[] }
await mc.api.apps.me.events();         // { items: EventItem[] }
await mc.api.apps.me.trainingplans();
await mc.api.apps.me.competitions();
await mc.api.apps.me.membercard();     // { card: … | null }

await mc.api.apps.storage.list("notizen", { scope: "user", limit: 50 });
await mc.api.apps.storage.put("notizen", "n-1", { text: "Hallo" });

// jede andere Methacore-API
await mc.api.request("members", "/members", { query: { limit: 20 } });

Fehler kommen als ApiError mit status, message und dem Antwortkörper. Welche Endpunkte es gibt, steht unter Entwickler-API, der Speicher unter App-Speicher.

Exporte

await mc.exportRows(rows, {
  format: "xlsx",               // "csv" | "xlsx" | "pdf"
  filename: "teilnehmer",
  columns: [{ key: "name", label: "Name" }, { key: "gruppe", label: "Gruppe" }],
});

Im Host geht die Datei über die Bridge (Dashboard: Download, Handy: Teilen), eigenständig als normaler Browser-Download. xlsx und pdf-lib lädt das SDK erst beim ersten Export. Einzeln gibt es mc.export.toCsv, toXlsx und toPdf.

Die Warnung beim ersten Öffnen

Externe Apps prüft Methacore nicht. Deshalb sieht jedes Mitglied beim ersten Öffnen einen Hinweis mit dem Anbieter (Name deines DevHub-Teams) und einem Link zur Datenschutzerklärung – beides aus deinem DevHub-Projekt. Danach folgt die Zustimmung zu den Berechtigungen; erst dann lädt der Host deine Seite. Die Bestätigung merkt sich Methacore je Mitglied.

Im App Store trägt eine externe App den Hinweis „Extern – nicht von Methacore geprüft“.

Täglicher Check

Einmal am Tag ruft Methacore die Adresse deiner App auf. Antwortet sie nicht über https mit gültigem Zertifikat, gilt die App als nicht erreichbar, und der Store zeigt sie so an, bis der nächste Check gelingt. Adressen, die auf private oder interne Netze zeigen, bestehen den Check nie.

Checkliste

  • Adresse mit https, gültiges Zertifikat, Domain autorisiert
  • Einbetten durch https://admin.methacore.de erlaubt
  • Client der API „Methacore Apps“, Scopes so eng wie möglich
  • Datenschutzerklärung und Nutzungsbedingungen im DevHub hinterlegt
  • Im Host getestet (Dashboard und, falls target mobile/both, Handy) und eigenständig