Flutter · Serverpod · MCP

Für Entwickler

Lass deinen Coding-Agenten Lotse einbauen, mit den Skills aus dem SDK, oder mach es von Hand. Ein Paket, ein Init-Aufruf und ein Backend, das man lesen kann: Lotse läuft auf Serverpod.

Mit deinem Coding-Agenten

Claude Code, Cursor oder Codex können die Integration übernehmen. Das Paket lotse bringt Skills mit, die deinem Agenten das SDK und, ab lotse 0.2.0, die Server-API beibringen, und über den MCP-Server liest er danach dein Projekt.

  1. 1

    Paket und Skills einbinden

    Im Ordner deiner App ausführen. Die skills-CLI kopiert die Skills des Pakets lotse in dein Projekt, wo dein Agent sie findet. Nach jedem Update von lotse skills get erneut ausführen.

    Terminal
    flutter pub add lotse
    dart pub global activate skills
    skills get --package lotse --all
    
  2. 2

    Den Agenten beauftragen

    Vorher in der Console ein Projekt und einen API-Key anlegen. Der Agent fragt nach dem Public Key und deinem Handle und sagt dir, was du in der Console eintragen musst. Ein Secret braucht er nie.

    Prompt
    Binde Lotse mit dem Skill lotse-setup in diese App ein. Richte danach Deep Links mit lotse-deep-links und Push mit lotse-push ein.
    
  3. 3

    MCP-Server verbinden

    Mit einem Token aus den Projekteinstellungen liest dein Agent Funnels, Feedback und Links, prüft die Einrichtung und legt, wenn das Token es erlaubt, Links und Segmente an. Hier die Zeile für Claude Code. Cursor, VS Code und Codex stehen auf der Seite KI-Agenten.

    Terminal
    claude mcp add --transport http --scope local lotse https://api.lotse.dev/mcp --header 'Authorization: Bearer ${LOTSE_MCP_TOKEN}'
    

Quickstart von Hand

Dieselben Schritte ohne Agenten, von der Registrierung bis zum ersten Deep Link auf einem Gerät, unter Android und iOS.

  1. 1

    Projekt anlegen

    In der Console registrieren, ein Projekt anlegen und sein Handle wählen. Aus dem Handle wird die Link-Domain dein-handle.lotse.dev. Die Android-App mit Paketnamen und dem SHA-256-Fingerprint des Signaturschlüssels hinzufügen, die iOS-App mit Bundle ID und Team ID. Dann einen API-Key erzeugen; sein Public Key kommt in die App.

  2. 2

    Paket einbinden

    Das SDK ist das Paket lotse auf pub.dev.

    Terminal
    flutter pub add lotse
    
  3. 3

    Initialisieren

    Ein Aufruf registriert das Gerät, meldet die Session und löst einen Deferred Link auf. Er wirft nie in die App: Fehler werden geloggt, und der Link ist null.

    Dart
    Future<void> main() async {
      WidgetsFlutterBinding.ensureInitialized();
      await Lotse.init(
        publicKey: 'lt_pk_…',
        serverUrl: 'https://api.lotse.dev/',
      );
    
      // Set on the first start after an install that came from a link.
      final link = await Lotse.instance.deferredLink;
      runApp(MyApp(initialLocation: link?.targetPath ?? '/'));
    }
    
  4. 4

    Links die App öffnen lassen

    Die Link-Domain im Android-Manifest eintragen, unter iOS die Capability Associated Domains mit applinks:dein-handle.lotse.dev. Lotse liefert assetlinks.json und apple-app-site-association für das Projekt aus. Im Router /l/:slug an Lotse.instance.resolveLink(slug) geben und zu dessen targetPath navigieren.

    XML
    <!-- android/app/src/main/AndroidManifest.xml, inside <activity> -->
    <intent-filter android:autoVerify="true">
      <action android:name="android.intent.action.VIEW"/>
      <category android:name="android.intent.category.DEFAULT"/>
      <category android:name="android.intent.category.BROWSABLE"/>
      <data android:scheme="https"
            android:host="your-handle.lotse.dev"
            android:pathPrefix="/l/"/>
    </intent-filter>
    
  5. 5

    Push einschalten

    Firebase wie gewohnt in die App einbinden und den Service-Account in der Console hochladen. Für iPhones zusätzlich einen APNs-Schlüssel (.p8) zur iOS-App hochladen; ohne ihn gehen Pushes an iOS über FCM. Das SDK fragt nach der Berechtigung, meldet das Token und sagt Bescheid, wenn ein Push geöffnet wurde.

    Dart
    // A push tapped while the app was closed, and pushes tapped while it runs.
    final push = await Lotse.instance.initialPush;
    Lotse.instance.pushOpened.listen((push) => router.go(push.targetPath ?? '/'));
    

Die Oberfläche des SDK

Die Aufrufe, die die meisten Apps brauchen. Der generierte Serverpod-Client bleibt dahinter verborgen.

static Future<void> Lotse.init({required String publicKey, required String serverUrl})
Verbindet, registriert das Gerät, meldet session_start. Ein zweiter Aufruf tut nichts.
Future<LotseLink?> get deferredLink
Der Link, über den eine Installation kam. Wird einmal geliefert, null, wenn es keinen gab.
Future<LotseLink?> resolveLink(String slug)
Macht aus dem Slug eines geöffneten Links Ziel-Route und Kampagne.
Future<void> track(String name, {Map<String, String>? props})
Schreibt ein Event mit String-Properties in den Strom.
Future<void> identify(String userId, {Map<String, String>? traits, String? userHash})
Verbindet das Gerät mit einem angemeldeten Nutzer, mit Traits. userHash kommt aus deinem Backend, sobald das Projekt Identitäten prüft.
Future<void> reset()
Für den Logout: Die nächsten Events gehören nicht mehr zum Nutzer.
LotseScreenObserver({String? Function(Route<dynamic> route)? screenName})
Im Router eingehängt, wird jeder Screenwechsel zum Event screen_view. screenName bestimmt den Namen, sonst gilt der Routenname.
Future<LotsePush?> get initialPush
Der Push, der die App gestartet hat, falls es einen gab.
Stream<LotsePush> get pushOpened
Pushes, die bei laufender App angetippt werden.
Future<void> showFeedback(BuildContext context, {Map<String, String>? metadata, bool askForEmail = false, LotseFeedbackTexts? texts})
Öffnet das Feedback-Sheet: Screenshot, Markierungen, Text und Kategorie. metadata wird mit der Meldung gespeichert, askForEmail ergänzt ein optionales E-Mail-Feld.

Aus deinem Backend

Auch dein Server arbeitet mit Lotse: eine REST-API mit Server-Keys, und signierte Webhooks in die andere Richtung.

Server-API

Als Nächstes

Links anlegen, Kampagnen und Pushes an einzelne Nutzer senden, Events melden und Nutzer löschen, aus jeder Sprache.

Webhooks

Als Nächstes

Feedback, Umfrageantworten, zugeordnete Installationen, abgeschlossene Kampagnen und mehr, an dein Backend geschickt und signiert nach Standard Webhooks.

Was Serverpod hier tut

Lotse ist keine dünne Schicht über einem fremden Backend. Jeder Teil nutzt ein Stück Serverpod.

Modelle und Migrationen

Projekte, Links, Klicks, Geräte, Events, Kampagnen und Zustellungen sind .spy.yaml-Modelle. Das Schema wandert mit generierten Migrationen.

Ein generierter, typisierter Client

Console und SDK sprechen über den generierten Client mit dem Server. Das SDK kapselt ihn, die App sieht nie ein generiertes Symbol.

Drei Wege der Authentifizierung

Console-Nutzer melden sich über das Auth-Modul an. Das SDK nutzt einen Public Key, der nur schreiben und sich selbst lesen darf. Backends nutzen einen Server-Key mit Scopes, gespeichert als Hash.

Routen des Webservers

Der Link-Router /l/:slug und die .well-known-Dateien sind Relic-Routen. Sie finden das Projekt über den Host-Header und halten die Weiterleitung nie für die Klickerfassung auf.

Future Calls

Aus einer Kampagne werden Zustellzeilen. Ein Worker beansprucht sie in Batches, wiederholt mit Backoff und markiert abgelehnte Tokens als ungültig.

Ein Server für alles

Derselbe Serverpod liefert die API, die Link-Domains und die Flutter-Web-Console aus, darunter Postgres.

Mandantentrennung

Jeder Endpoint löst das Projekt aus dem Schlüssel auf und filtert jede Abfrage danach. Integrationstests mit zwei Projekten sichern Endpoints und Link-Router ab.

Kurs setzen.Das erste Projekt in zehn Minuten.

Kostenlos während der Beta. Registrieren, Projekt anlegen, SDK einbinden.