Überblick
Ein Terminplanungssystem, mit dem ein verteiltes Serviceteam Buchungen über viele Behandler hinweg annehmen kann, ohne je doppelt zu buchen, eine Zeitzone falsch zu behandeln oder einen Termin bei einer Wiederholung zu duplizieren – mit Google Calendar als einziger Quelle der Wahrheit.
Was gebaut wurde
Eine Buchungsplattform, direkt auf Google Workspace aufgesetzt. Kunden wählen einen Slot aus berechneter Verfügbarkeit; die Plattform reserviert, verifiziert und bestätigt den Termin als eine einzige idempotente Transaktion, schreibt das Ereignis in den Google Calendar des Behandlers und benachrichtigt beide Seiten. Es gibt keine separate führende Datenbank – der Kalender, in dem das Team ohnehin lebt, bleibt maßgeblich.
Für wen es ist
Ein Dienstleistungsunternehmen mit mehreren Behandlern, jeder mit eigenen Arbeitszeiten, Puffern und Abwesenheiten, das Buchungen aus einem Webformular, per E-Mail und dem gelegentlichen, nachträglich eingetragenen Telefonanruf annimmt.
Geschäftlicher Kontext
Der manuelle Prozess, den es ersetzte, verlor durch Doppelbuchungen und Zeitzonenfehler rund einen Slot pro Woche – gering in der Zahl, teuer im Vertrauen. Aufgabe der Plattform war es, den Kalender maßgeblich und die Buchung sicher zu machen, ohne ein zweites System hinzuzufügen, das aus dem Takt geraten würde.
Architektur
Ein schlanker, zustandsloser Koordinator vor Google Calendar. Eine Buchung ist eine kurze, idempotente Transaktion – reservieren, verifizieren, bestätigen – geleitet durch eine Warteschlange pro Behandler, sodass das Rennen, das Doppelbuchungen verursacht, gar nicht erst auftreten kann.
Warum eine Warteschlange pro Behandler
Doppelbuchung ist ein Rennen zwischen nebenläufigen Schreibern um eine Ressource. Statt zu verteilten Sperren zu greifen, läuft jede Anfrage für einen bestimmten Behandler durch eine FIFO-Warteschlange mit einem einzigen Konsumenten – ein langweiliges, debugbares Primitiv, das das Rennen unmöglich macht, statt es nur behebbar. Die Nebenläufigkeit über Behandler hinweg bleibt hoch; innerhalb eines Behandlers fällt sie auf eins.
Komponenten
Die Plattform ist aus neun Komponenten aufgebaut. Jede ist als eigener Engineering-Abschnitt dokumentiert – warum sie existiert, ihre Architektur, die Einschränkungen und Randfälle, die sie behandelt, die eingegangenen Trade-offs und die finale Implementierung. Klappe eine beliebige auf, um sie zu lesen.
›C1Mehrstufiger Buchungsablauf
- Warum sie existiert
- Verwandelt „eine Zeit finden“ in eine geführte, fortsetzbare Sequenz – Leistung → Behandler → Datum → Slot → Details → Bestätigung –, die nie einen Slot anbietet, den sie nicht einhalten kann.
- Architektur
- Ein zustandsloser Client, angetrieben von der Verfügbarkeits-Engine; jeder Schritt validiert erneut gegen live free/busy, sodass ein Slot, der sich mitten im Ablauf füllt, vor dem Absenden erkannt wird.
- Einschränkungen
- Muss aus einem Webformular, einem E-Mail-Link und einer manuell eingetippten Telefonbuchung funktionieren; kein Schritt darf sich auf die Geräteuhr des Clients verlassen.
- Randfälle
- Slot zwischen Anzeige und Absenden vergeben; erneutes Absenden per Zurück-Button; ein Behandler, der mitten in der Sitzung in den Urlaub geht.
- Trade-offs
- Das erneute Validieren jedes Schritts kostet einen zusätzlichen free/busy-Read, beseitigt aber den Fehler „der gewählte Slot ist weg“ beim Bestätigen.
›C2Verfügbarkeits-Engine
- Warum sie existiert
- Berechnet buchbare Fenster pro Behandler aus Arbeitszeiten, Puffern, bestehenden Ereignissen und Abwesenheiten – das Read-Modell, aus dem der gesamte Ablauf gerendert wird.
- Architektur
- Berechnet Fenster planmäßig und bei Kalenderänderungs-Webhooks vor und cacht sie in Firestore; der Ablauf liest auf dem heißen Pfad den Cache, nicht die Calendar API.
- Einschränkungen
- Muss korrekt bleiben, während Behandler ihre eigenen Kalender direkt bearbeiten; darf unter Last das Calendar-Read-Kontingent nicht überschreiten.
- Randfälle
- Überlappende Ereignisse, ganztägige Blockaden, wiederkehrende Sperren und DST-Grenzen, an denen ein „9 Uhr“-Fenster sich verschiebt.
- Trade-offs
- Eine kurze Cache-TTL tauscht ein paar Sekunden Veraltung gegen einen großen Rückgang an API-Aufrufen; der Bestätigungsschritt ist die Autorität, daher ist kurze Veraltung sicher.
›C3Buchungs-API (reservieren · verifizieren · bestätigen)
- Warum sie existiert
- Der transaktionale Kern: verwandelt eine Anfrage in genau ein Kalenderereignis, sicher, selbst unter Nebenläufigkeit und Wiederholungen.
- Architektur
- Jede Anfrage für einen Behandler läuft durch dessen FIFO-Warteschlange mit einem einzigen Konsumenten;
confirm()prüft free/busy innerhalb dieses Fensters und schreibt mit einem inhaltsadressierten Idempotenzschlüssel. - API-Vertrag
POST /booking → 201 {eventId} | 409 SlotTaken // idempotent: same intent ⇒ same eventId key = sha256(practitionerId, startUTC, clientId)
- Randfälle
- Nebenläufige Anfragen für einen Slot (wegserialisiert); Formular-/Netzwerk-Wiederholungen (durch das Ledger auf ein Ereignis zusammengefasst); Teilausfall nach dem Einfügen (der Ledger-Commit macht es wiederholsicher).
- Trade-offs
- Serialisierung pro Behandler fügt ein paar ms Latenz hinzu und entfernt das Rennen konstruktionsbedingt – gewählt statt verteilter Sperren.
›C4Google-Calendar-Integration
- Warum sie existiert
- Hält Google Calendar als Quelle der Wahrheit – liest free/busy und schreibt Ereignisse – sodass das Team nie das Werkzeug verlässt, das es ohnehin nutzt.
- Architektur
- Nutzt die aggregierte
freebusy-Abfrage für die Verfügbarkeit (keine Ereignisdetails) undevents.insertfür Schreibvorgänge und versieht jedes Ereignis in privaten erweiterten Eigenschaften mit seinem Buchungsschlüssel. - Einschränkungen
- Read-Kontingente pro Minute; Least-Privilege-Scopes; muss überstehen, dass Behandler Ereignisse von Hand bearbeiten.
- Randfälle
- Manuell gelöschte Ereignisse, externe Kalenderfreigaben und Abgleich, wenn Kalender und Ledger nicht übereinstimmen.
›C5Zeitzonen-Handhabung
- Warum sie existiert
- Garantiert, dass ein Slot für Kunde, Behandler und Server über Sommerzeitwechsel hinweg denselben Zeitpunkt bedeutet.
- Architektur
- Speichert den Zeitpunkt in UTC und die vom Nutzer beabsichtigte IANA-Zone als separates Feld; die beiden werden erst beim Rendern wieder kombiniert.
- Randfälle
- Lücken bei Vor-/Zurückstellung, Zonen, die DST an unterschiedlichen Daten beachten, und Kunden, die nach der Buchung ihre Gerätezone ändern.
- Trade-offs
- Eine explizite Zone mitzuführen ist mehr zu speichern als ein bloßer Zeitstempel, aber es ist der einzige Weg, das Versprechen „9 Uhr in Lissabon“ zu wahren.
›C6Authentifizierung & Berechtigungen
- Warum sie existiert
- Lässt die Plattform mit der geringsten Autorität, die ein Sicherheitsteam abnimmt, auf den Kalendern der Domäne agieren.
- Architektur
- Ein dedizierter Service-Account mit eng gefasster domänenweiter Delegation; jeder Account lässt sich zu einem Eigentümer und einem Entscheidungsrecord zurückverfolgen.
- Einschränkungen
- Keine breiten Scopes; Schlüssel planmäßig rotiert; Zugriff auf einem Kalender geprüft, nicht aus dem Gedächtnis.
- Trade-offs
- Least-Privilege bedeutet mehr Konfiguration vorab im Austausch für ein Modell, das die Prüfung ohne Ausnahmen besteht.
›C7Benachrichtigungen
- Warum sie existiert
- Bestätigt, erinnert und storniert für Kunde und Behandler, ohne je zweimal zu senden.
- Architektur
- At-least-once-Zustellung über Cloud Tasks mit Idempotenzschlüsseln und einer Dead-Letter-Queue, sodass eine Wiederholung nie doppelt sendet.
- Randfälle
- Provider-Drosselung, unzustellbare Adressen und eine Buchung, die storniert wird, bevor ihre Erinnerung ausgelöst wird.
›C8Google-Meet-Erzeugung
- Warum sie existiert
- Hängt an jede Remote-Buchung im Moment der Ereigniserstellung einen funktionierenden Videolink an.
- Architektur
- Fordert Konferenzdaten bei
events.insertan, sodass der Meet-Link Teil desselben atomaren Schreibvorgangs wie die Buchung ist. - Randfälle
- Fehler bei der Konferenzerstellung (die Buchung muss trotzdem gelingen) und verschobene Ereignisse, die ihren Link behalten.
›C9Google-Sheets-Reporting
- Warum sie existiert
- Gibt dem Betreiber eine vertraute, live aktualisierte Ansicht von Buchungen und Auslastung ohne ein maßgeschneidertes Dashboard.
- Architektur
- Append-only-Synchronisierung vom Ledger in ein Sheet, behandelt als Read-Replika – nie als Quelle der Wahrheit.
- Trade-offs
- Ein Sheet ist begrenzt und leicht verzögert, aber es ist für einen Nicht-Techniker sofort lesbar, und darum geht es.
Visuelles Ergebnis
Was das System für Kunde und Betreiber tatsächlich produziert. Dies sind Exponate aus dem laufenden System – jedes beschriftet und mit der Komponente verlinkt, die es erzeugt. Setze die echten Screenshots in die Rahmen ein.
Der Buchungsablauf
Die dreistufige Kundenreise: Leistung & Zeit → Kontaktdaten → Datum und Uhrzeit → Bestätigung. Jeder Schritt validiert erneut gegen die Live-Verfügbarkeit.

Echter Screenshot aus dem laufenden SystemKomponente: Mehrstufiger Buchungsablauf
Der Lead-Datensatz
Wo die Antworten des Kontaktschritts landen: eine an das Google Sheet angehängte Zeile – Name, Firma, geschäftliche E-Mail, Quelle und Zeitstempel der Einreichung. Anonymisierte oder Beispieldaten verwenden.

Echter Screenshot · Beispiel- / anonymisierte DatenKomponente: Google-Sheets-Reporting
Kalenderereignis erstellt
Die Buchungs-API schreibt direkt in den Google Calendar des Behandlers – Titel, Zeit, Zeitzone, beide Teilnehmer, ein Google-Meet-Link und der Aufnahmekontext in der Beschreibung. Beleg, dass das System ein natives Kalender-Artefakt erzeugt, keine private Datenbankzeile.

Kundeneinladung & -bestätigung
Was der Kunde erhält – die Google-Calendar-Einladung und -Bestätigung, mit Meeting-Details und dem Meet-Link.

Echter Screenshot · Empfängerdaten schwärzenKomponente: Benachrichtigungen · Google-Meet-Erzeugung
Interne Benachrichtigung
Was das Team sieht, wenn eine Buchung eintrifft – die interne Benachrichtigung mit dem erfassten Qualifizierungskontext und dem Quell-Workflow.
Echter Screenshot · anonymisiertKomponente: Benachrichtigungen
Fehler & Wiederherstellung
Die Zustände, die Produktivdenken beweisen: ein zwischen Anzeige und Absenden vergebener Slot und die erfolgreiche Wiederholung, die folgt. Links: Konflikt. Rechts: Wiederherstellung.
Wirkung
Objektive Ergebnisse, die aus dem Produktivbetrieb der Plattform hervorgingen – Belege, keine Werbung.
- Geschäft
- Ersetzte einen Scheduling-Stack aus Calendly plus Zapier durch ein einziges selbst betriebenes System.
- Beseitigte die wiederkehrenden Drittanbieter-Abokosten und den Kleber, der die Werkzeuge verband.
- Kunde
- Sofortige, zuverlässige Bestätigung im Moment der Buchung.
- Weniger Terminplanungsfehler – kein angebotener Slot, der nicht eingehalten werden kann.
- Betrieb
- Doppelbuchungen beseitigt.
- Zeitzonen-Handhabung durchgängig automatisiert.
- Manuelle Kalendereinträge aus dem Alltag des Teams entfernt.
- Engineering
- Eine einzige Quelle der Wahrheit – keine parallele Buchungsdatenbank, die aus dem Takt gerät.
- Wiederholsichere, idempotente Schreibvorgänge; weniger bewegliche Teile im Betrieb.
- Umfang
- ~4,000 Buchungen / Monat.
- Null Doppelbuchungen, seit die v2-Serialisierung live ging.
Technische Dokumente
Chronologische Engineering-Records, geschrieben während des Baus der Plattform – die Entscheidungen, Sackgassen und Vorfälle, wie sie geschahen. Neueste zuerst.
Fallstudie
Eine Retrospektive auf die Plattform aus geschäftlicher Sicht – warum sie existiert, der gewählte Ansatz und wie es ausging.
- Problem
- Ein Serviceteam führte seinen Kalender von Hand und verlor durch Doppelbuchungen und Zeitzonenfehler etwa einen Slot pro Woche – billig zu zählen, teuer im Kundenvertrauen.
- Ziel
- Den Kalender maßgeblich und die Buchung sicher machen, von einer Person betreibbar, ohne ein zweites System of Record.
- Einschränkungen
- Google Calendar bleibt die Quelle der Wahrheit; Least-Privilege-Sicherheit; korrekt unter Nebenläufigkeit und Wiederholungen; innerhalb der Calendar-API-Kontingente.
- Ansatz
- Ein schlanker, zustandsloser Koordinator vor der Calendar API; Serialisierung pro Behandler, um das Rennen zu entfernen; inhaltsadressierte Idempotenz, um Duplikate zu entfernen; UTC-plus-Absicht für die Zeit.
- Architektur
- Aufnahme → Edge-Validierung → FIFO-Warteschlange pro Behandler → reservieren/verifizieren/bestätigen-Koordinator → Google Calendar, mit einem kleinen Idempotenz-Ledger. Keine parallele Buchungsdatenbank.
- Trade-offs
- Eine langweilige, beweisbar korrekte Warteschlange statt verteilter Sperren gewählt; Sekunden an Verfügbarkeits-Veraltung für eine große Kontingent-Ersparnis akzeptiert; den Zustand in der Plattform belassen, die ihn ohnehin besitzt.
- Ergebnis
- Im Produktivbetrieb seit Feb 2024, ~4,000 Buchungen/Monat, null Doppelbuchungen seit die v2-Serialisierung live ging; „ist meine Buchung durchgegangen?“ wurde zum Nicht-Ereignis, weil Wiederholungen sicher sind.
- Lektionen
- Serialisiere die umkämpfte Ressource; sperre nicht die ganze Welt.
- Idempotenz ist ein Feature, keine Absicherung.
- Lass die Plattform den Zustand behalten, den sie ohnehin besitzt.
- Zukunft
- Ein Self-Service-Umbuchungsablauf und das Verlagern der TTL-Aufräumung des Ledgers von Cron auf Dokumentablauf.
