Neu veröffentlicht: E-Commerce mit Power Pages, Stripe & Analytics

· Webentwicklung  · 6 minuten Lesezeit

Chrome Extension Foundation mit Health-Dot und Retry-Queue

Phase 1 legt das Fundament: Health-Dot, Retry-Queue und Capture History machen die Chrome Extension im täglichen Einsatz zuverlässig und nachvollziehbar.

Phase 1 legt das Fundament: Health-Dot, Retry-Queue und Capture History machen die Chrome Extension im täglichen Einsatz zuverlässig und nachvollziehbar.

Inhalt

Warum Phase 1 keine neuen Features hat

Ich hatte ein lauffähiges System. Die Extension erkannte Instagram-Posts, extrahierte Metadaten, schnitt Screenshots zu und speicherte alles in einer Vektordatenbank. Das RAG-Backend beantwortete Fragen über die gespeicherten Posts.

Dann kam die Frage: Was kommt als nächstes?

Ich hatte sechzehn Feature-Ideen notiert. Carousel-Capture, Multi-Plattform-Support, Tags, Shortcut-Konfiguration, Offline-Queue. Alles interessant. Alles umsetzbar.

Aber bevor ich neue Fähigkeiten baue, muss die Basis stimmen. Eine Extension, die still scheitert, erzeugt kein Vertrauen. Eine Extension, bei der der Nutzer nicht weiß ob das Backend läuft, erzeugt keine Nutzungsgewohnheit. Eine Extension ohne Fehlertoleranz verliert Daten.

Phase 1 heißt deshalb „Foundation & Trust”. Vier Features. Keine davon fügt eine neue Capture-Fähigkeit hinzu. Alle davon machen das System spürbar robuster.

Die Roadmap zuerst

Bevor ich eine Zeile Code schrieb, habe ich eine fünfphasige Roadmap erstellt. Das Prinzip: Jede Phase ist unabhängig auslieferbar. Jede Phase baut auf der vorherigen auf. Schema-Änderungen kommen so früh wie möglich, bevor sie rückwärts-inkompatibel werden.

Die fünf Phasen:

  • Chrome Extension Foundation: Health-Dot, Retry-Queue, Capture-History
  • Phase 2, Capture Quality: Duplicate Detection, Visual Preview, Shortcut-Konfiguration
  • Phase 3, Content Enrichment: Tags, Notizen, Carousel-Capture
  • Phase 4, Power und Platform: Offline-Queue, Multi-Plattform, Bulk-Capture
  • Phase 5, Scale und Habit: Analytics, Privacy-Blocklist, Export

Die Roadmap liegt als ROADMAP.md im Projekt-Root. Das ist kein Task-Tracking-Dokument. Es ist ein Orientierungsrahmen, der erklärt warum die Features in dieser Reihenfolge kommen, nicht nur was kommt.

Übersicht der fünf Phasen der Extension-Roadmap Abbildung: Die fünf Phasen der Extension-Roadmap. Jede Phase ist eigenständig auslieferbar. Die Reihenfolge folgt dem Prinzip: erst Vertrauen aufbauen, dann neue Fähigkeiten ergänzen.

userId als Investition in die Zukunft

Das erste Feature aus Phase 1 ist das unauffälligste. Ich habe dem capturedBy-Objekt ein Feld userId: string | null hinzugefügt. Überall: in types.ts der Extension, im Backend und im Frontend.

Aktuell ist der Wert immer null. Kein Auth-System, kein Login. Nur das Feld.

capturedBy: {
  username: string;
  userId: string | null; // TODO: replace with authenticated provider userId
  capturedAt: string;
}

Der Grund: Wenn ich später Auth einbaue, muss ich keine Migration der bestehenden Daten in Qdrant vornehmen. Das Feld ist schon da. Es ist null, was semantisch korrekt ist: nicht bekannt. Sobald ein Auth-Provider existiert, wird null durch eine echte ID ersetzt.

Das kostet mich heute eine Zeile pro Datei. Und spart mir morgen eine Breaking Change.

Der Health-Dot: Macht das Backend sichtbar

Ein unsichtbares Problem ist ein ungelöstes Problem.

Wenn das Backend nicht erreichbar ist, scheitert jeder Capture still. Die Extension reagiert nicht. Keine Fehlermeldung. Kein Hinweis. Der Nutzer weiß nicht, ob er selbst etwas falsch macht oder ob der Server down ist.

Der Health-Dot löst das. Im Popup erscheint oben rechts ein kleiner Kreis. Grün bedeutet: Backend erreichbar. Rot bedeutet: kein Kontakt.

Das Popup ruft beim Öffnen GET /health auf, mit einem 4-Sekunden-Timeout.

async function checkHealth(): Promise<void> {
  try {
    const controller = new AbortController();
    const timeout = setTimeout(() => controller.abort(), 4000);

    const res = await fetch(HEALTH_ENDPOINT, { signal: controller.signal });
    clearTimeout(timeout);

    setHealthStatus(res.ok ? 'online' : 'error');
  } catch {
    setHealthStatus('offline');
  }
}

Das ist kein Monitoring. Das ist Feedback. Der Nutzer weiß in unter einer Sekunde, ob er arbeiten kann.

Popup-UI der Extension mit Health-Dot, Retry-Queue und Capture History Abbildung: Das Popup der Extension nach Phase 1. Oben der Health-Dot in grün oder rot, darunter die letzten Captures mit relativem Zeitstempel, ganz unten der Retry-Button falls Captures fehlgeschlagen sind.

Die Retry-Queue: Kein Datenverlust bei Netzwerkfehlern

Captures scheitern manchmal. Das Backend antwortet nicht, das Netzwerk hängt, der Server startet gerade neu. Ohne Fehlerbehandlung sind die Daten verloren.

Die Retry-Queue speichert fehlgeschlagene Payloads in chrome.storage.local. Maximal fünf Einträge. Das Extension-Icon bekommt einen roten Badge mit der Anzahl der wartenden Captures.

async function enqueuePendingCapture(payload: AnalysisPayload): Promise<void> {
  const existing = (await getStorage<PendingCapture[]>('pendingCaptures')) ?? [];
  const updated = [
    ...existing.slice(0, 4), // max 5 entries
    { payload, enqueuedAt: new Date().toISOString() },
  ];

  await chrome.storage.local.set({ pendingCaptures: updated });
  await chrome.action.setBadgeText({ text: String(updated.length) });
  await chrome.action.setBadgeBackgroundColor({ color: '#ef4444' });
}

Im Popup gibt es einen „Alle wiederholen”-Button. Er holt die Queue, schickt jeden Eintrag erneut und räumt erfolgreich gesendete Einträge auf.

Ein wichtiges Detail: Die Queue greift nur, wenn der Fehler nach dem Aufbau des Payloads passiert. Wenn die Metadaten-Extraktion selbst fehlschlägt, gibt es keinen validen Payload zum Speichern.

Die Capture History: Schließt den Feedback-Loop

Wann habe ich was captured? Von welchem Channel? Auf welcher Plattform?

Ohne Feedback ist jede Interaktion mit der Extension ein Akt des Glaubens. Du drückst Ctrl+Q, siehst kurz das Overlay, bestätigst. Und dann? Nichts. Du weißt nicht ob es funktioniert hat.

Die Capture History speichert nach jedem erfolgreichen Capture einen Eintrag in chrome.storage.local:

type CaptureHistoryEntry = {
  capturedAt: string;
  channel: string;
  platform: string;
};

Im Popup erscheinen die letzten fünf Captures. Mit relativem Zeitstempel: „Vor 3 Minuten”, „Vor 2 Stunden”. Das reicht, um die wichtigste Frage zu beantworten: Hat der letzte Capture funktioniert?

function relativeTime(isoString: string): string {
  const diff = Date.now() - new Date(isoString).getTime();
  const minutes = Math.floor(diff / 60_000);

  if (minutes < 1) return 'Gerade eben';
  if (minutes < 60) return `Vor ${minutes} Minute${minutes > 1 ? 'n' : ''}`;

  const hours = Math.floor(minutes / 60);
  if (hours < 24) return `Vor ${hours} Stunde${hours > 1 ? 'n' : ''}`;

  const days = Math.floor(hours / 24);
  return `Vor ${days} Tag${days > 1 ? 'en' : ''}`;
}

Kein externes Package. Keine Formatierungs-Library. Dreißig Zeilen.

Was Phase 1 tatsächlich ist

Die vier Features aus Phase 1 haben keine gemeinsame technische Klammer. Es gibt keinen neuen Service, keine neue Architekturebene.

Was sie gemeinsam haben: Sie machen das System beobachtbar. Der Nutzer sieht den Systemzustand. Der Nutzer sieht was passiert ist. Der Nutzer kann auf Fehler reagieren, ohne Debug-Logs zu öffnen.

Das ist das eigentliche Ziel von Phase 1. Nicht Features. Vertrauen.


Alle Artikel der Serie

  1. Vision und Systemübersicht: Chrome Extension, RAG-Architektur, Projekthintergrund: Artikel lesen
  2. RAG-System Aufbau: Qdrant, Embeddings, Cosine-Ähnlichkeit in TypeScript: Artikel lesen
  3. AI Provider Abstraktion: Ollama vs. OpenAI, Interface-Design, kein Vendor-Lock-in: Artikel lesen
  4. Chrome Extension MV3: Drei isolierte Laufzeitkontexte, Message Passing, Strategy Pattern: Artikel lesen
  5. Docker Compose Strategie: Override-Pattern, von lokal zu Azure: Artikel lesen
  6. Ollama lokal vs. Docker: Die Entscheidung und ihre Konsequenzen: Artikel lesen
  7. Ollama Auto-Pull Entrypoint: Automatisiertes Modell-Setup beim Container-Start: Artikel lesen
  8. tsconfig und Vite: Node16 vs. bundler, warum Vite eigene Regeln hat: Artikel lesen
  9. Instagram Caption mit MutationObserver vollständig laden: Artikel lesen
  10. Chrome Extension Foundation mit Health-Dot und Retry-Queue (dieser Artikel)
  11. Phase 2 Features: Shadow DOM Overlay, Tailwind v4, Duplicate Detection: Artikel lesen
  12. Race Condition bei der Plattformerkennung: Wie ein UI-Event die Instagram-Erkennung bricht: Artikel lesen
  13. PostId-Extraktion in zwei Instagram-Layouts: querySelector vs. Ancestor-Traversal: Artikel lesen

Du planst eine Browser-Extension oder ein System mit Offline-Resilience und Nutzerfeedback? Lass uns das gemeinsam einschätzen.

Zurück zum Blog

Ähnliche Beiträge

Alle Beiträge ansehen