· 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.

Inhalt
- Warum Phase 1 keine neuen Features hat
- Die Roadmap zuerst
- userId als Investition in die Zukunft
- Der Health-Dot: Macht das Backend sichtbar
- Die Retry-Queue: Kein Datenverlust bei Netzwerkfehlern
- Die Capture History: Schließt den Feedback-Loop
- Was Phase 1 tatsächlich ist
- Alle Artikel der Serie
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.
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.
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
- Vision und Systemübersicht: Chrome Extension, RAG-Architektur, Projekthintergrund: Artikel lesen
- RAG-System Aufbau: Qdrant, Embeddings, Cosine-Ähnlichkeit in TypeScript: Artikel lesen
- AI Provider Abstraktion: Ollama vs. OpenAI, Interface-Design, kein Vendor-Lock-in: Artikel lesen
- Chrome Extension MV3: Drei isolierte Laufzeitkontexte, Message Passing, Strategy Pattern: Artikel lesen
- Docker Compose Strategie: Override-Pattern, von lokal zu Azure: Artikel lesen
- Ollama lokal vs. Docker: Die Entscheidung und ihre Konsequenzen: Artikel lesen
- Ollama Auto-Pull Entrypoint: Automatisiertes Modell-Setup beim Container-Start: Artikel lesen
- tsconfig und Vite:
Node16vs.bundler, warum Vite eigene Regeln hat: Artikel lesen - Instagram Caption mit MutationObserver vollständig laden: Artikel lesen
- Chrome Extension Foundation mit Health-Dot und Retry-Queue (dieser Artikel)
- Phase 2 Features: Shadow DOM Overlay, Tailwind v4, Duplicate Detection: Artikel lesen
- Race Condition bei der Plattformerkennung: Wie ein UI-Event die Instagram-Erkennung bricht: Artikel lesen
- 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.



