CalendarSync: van dagelijkse ergernis naar een eigen macOS-app
Het begon zoals zoveel dingen beginnen: met frustratie. Niet de grote, dramatische soort, maar die kleine, terugkerende irritatie die me elke dag een paar minuten kostte. Minuten die optellen tot uren, en uren die ik nooit meer terugkrijg.
Het probleem dat simpel klinkt maar het niet is
Bij ons werken we met twee Google Calendars. Eentje die collega's kunnen inkijken om meetings in te plannen, en eentje gekoppeld aan Teamleader waar de echte planning in staat. Mijn focusblokken, mijn deep work momenten, mijn tijd om geconcentreerd aan projecten te werken.
Het probleem: die twee agenda's praatten niet met elkaar.
Het resultaat was voorspelbaar. Collega's planden een meeting in op een moment dat in hun ogen vrij was, terwijl ik in Teamleader een focusblok had staan. Ik kreeg een uitnodiging, zag de overlap, en dan begon het schuiven. Of erger: ik zag het niet, accepteerde automatisch, en kwam er pas later achter dat mijn hele planning in de war was.
Gewoon zelf bouwen dan maar
Wat ik wilde was simpel: een tool die automatisch events van Teamleader naar de gedeelde agenda kopieert. Eenrichting, zodat collega's kunnen zien wanneer ik beschikbaar ben. Elke dertig seconden checken of er iets nieuws is. En als ik een focusblok verwijder of verplaats, moet dat ook aan de andere kant weg. Geen zombie-events die blijven rondsluimeren en voor verwarring zorgen.
De eerste versie kwam redelijk snel in elkaar. OAuth2-authenticatie, Google Calendar API-integratie, een simpele interface met SwiftUI. Het kon events kopiëren via een klik, via drag-and-drop, of in bulk. Het werkte.
Maar "het werkt" is nog niet hetzelfde als "het werkt goed".
De bugs die ik niet zag aankomen
De automatische synchronisatie was de volgende stap. Een timer die elke dertig seconden triggert, nieuwe events detecteert, en ze overzet. Klinkt simpel. Was het niet.
De eerste grote bug ontdekte ik pas na uitgebreid testen: verwijderde events bleven bestaan aan de andere kant. De root cause bleek pijnlijk simpel. Gekopieerde events kregen dezelfde ID als het origineel. Voor Google Calendar waren ze technisch hetzelfde event, waardoor de hele tracking in de soep draaide.
De fix was één regel code. Het vinden ervan kostte me uren.
Een tweede probleem was performance. De auto-sync laadde tweehonderdvijftig events, wat alles traag maakte. De oplossing: enkel events van vandaag tot volgende maand ophalen. Het resultaat was een reductie van bijna tachtig procent. Soms zit winst in beperking.
De details die het verschil maken
Een vraag die later kwam van een collega: kun je ervoor zorgen dat er in de menubalk een icoontje staat? Zodat je ziet dat de app draait?
Het klinkt als een klein ding, maar het is precies het soort detail dat bepaalt of mensen een tool effectief blijven gebruiken. Visuele feedback. Weten dat er iets gebeurt op de achtergrond. Een idle-icoon als alles rustig is, een sync-icoon als er gesynchroniseerd wordt.
Het zijn die kleine toevoegingen die een technisch werkende app veranderen in iets dat aangenaam is om te gebruiken.
Wat het nu doet
CalendarSync v1.1 draait nu als een volledig functionele native macOS-app. Gebouwd in Swift 5.9 met SwiftUI, draaiend op macOS Ventura en nieuwer, als universal binary voor zowel Intel als Apple Silicon.
De features waar ik het meest tevreden mee ben:
- OAuth2-authenticatie met Google
- Meerdere calendars beheren vanuit één interface
- Event kopiëren via klik, bulk selectie, of drag-and-drop
- Automatische synchronisatie elke 30 seconden
- Drie sync-richtingen: bidirectioneel, of eenrichting naar keuze
- Intelligente deletion sync en duplicate detection
- Menu bar status indicator
- Calendar selection die bewaard blijft tussen sessies
Alles draait volledig lokaal. Geen externe dependencies, geen servers. Credentials zitten veilig in de Keychain, voorkeuren in UserDefaults.
De architectuur is bewust simpel gehouden:
Sources/
├── Models/
│ ├── Calendar.swift
│ ├── CalendarEvent.swift
│ └── CalendarSyncPair.swift
├── Services/
│ ├── AuthenticationManager.swift
│ ├── GoogleCalendarAPI.swift
│ ├── AutoSyncManager.swift
│ ├── SyncManager.swift
│ └── MenuBarManager.swift
└── Views/
├── MainView.swift
├── EventListView.swift
└── SyncPairsView.swift
Het resultaat is een tool die in seconden is geconfigureerd, op de achtergrond draait, automatisch agenda's sync houdt, intelligent omgaat met verwijderde events, data lokaal houdt, en native macOS-performance biedt.
Niet meer dan dat. Maar ook niet minder.
De les erachter
Achteraf gezien zit de waarde niet enkel in de app zelf. Het zit ook in het proces. In het ontdekken dat sommige problemen simpeler op te lossen zijn dan ik dacht, en andere complexer. Dat één regel code uren debuggen kan kosten. Dat de features waar gebruikers om vragen vaak niet de grote zijn, maar de kleine: een icoontje in de menubalk, een duidelijke statusmelding.
Marcus Aurelius schreef ooit dat we niet moeten klagen over wat ons overkomt, maar moeten kijken naar wat we eraan kunnen doen. Bij kleine ergernissen vergeet ik dat soms. Ik accepteer ze als deel van het leven, terwijl ze soms gewoon oplosbaar zijn.