Desktop calendar app for Microsoft 365 Exchange Online built with Electron.
- Microsoft sign-in via
@azure/msal-nodewith encrypted token cache - Multi-account support with calendar selection and custom colors
- Full event CRUD with drag-and-drop move/resize
- Optional physical-location autocomplete and map previews powered by Photon / OpenStreetMap, without an API key
- Meeting responses (accept/tentative/decline)
- Participant free/busy indicators when creating meetings, refreshed as attendees or times change
- Local SQLite cache with configurable periodic sync
- Desktop reminder popup with snooze/dismiss and meeting join
- System tray integration
- React 19 renderer with month/week/day views and mini calendar
- Internationalization (English/Italian)
- Auto-updates via GitHub Releases (stable/prerelease channels)
- Electron + electron-vite + TypeScript
- React 19 + FullCalendar + Zustand + TanStack Query
- better-sqlite3 (local cache), MSAL Node (auth), Microsoft Graph API
- Zod (validation), i18next (i18n), electron-updater (auto-updates)
- oxlint + oxfmt for linting/formatting, Vitest for testing, Husky for hooks
- Register a Microsoft Entra application for DefCalendar.
- Point
src/main/auth/app-registration.tsat your public-client app registration, or useMSAL_CLIENT_IDonly as a development override. - Configure the app for accounts in any organizational directory.
- Enable the public client desktop/mobile flow.
- Under
Authentication > Add a platform, addMobile and desktop applicationswith the redirect URIhttp://localhost. - Grant delegated Microsoft Graph permissions:
openid,profile,offline_accessUser.Read,User.ReadBasic.All,Calendars.ReadWrite,MailboxSettings.Read,Contacts.Read,People.Read
- Use
.env.examplefor optional development overrides; packaged end users should use the bundled app registration. - For tenant-specific development, override
MSAL_AUTHORITY.
npm run dev— Start development servernpm run build— Compile main, preload, and renderer intoout/npm run lint— Run oxlintnpm run lint:fix— Apply oxlint autofixesnpm run format— Format code with oxfmtnpm run format:check— Check formatting without changesnpm run test— Run Vitest suitenpm run test:watch— Run tests in watch modenpm run package— Create unpacked distributablenpm run dist— Create installer artifacts with electron-buildernpm run dist:publish— Create installer artifacts and publish a GitHub Release
- Targets Microsoft 365 work/school accounts only.
- Locations are plain text by default, including online meeting names. Use the icon selector to the left of the location field to switch from Location to Map for address suggestions and a small OpenStreetMap area preview. Hovering or focusing the preview reveals the link icon; clicking opens Google Maps. The physical-location choice and selected coordinates are saved locally for each event and retained through synchronization while the address remains unchanged. Map previews load only the visible tiles through Electron's HTTP cache, with an identifying DefCalendar User-Agent; no API key is required.
- Location suggestions use the public Photon API. Searches send only the typed location to Photon after at least three characters and a 500 ms pause. Requests run in the main process, are limited to one per second, and results are cached in memory for five minutes. Returning to a cached query displays results immediately; switching away from the app preserves the open popup and pending search. Previous suggestions remain visible but cannot be selected while a new search is pending. Italian uses local place names; English requests translated names. Street addresses with house numbers use structured searches and exclude conflicting streets or house numbers. When Photon only knows the street, suggestions retain the entered number and explicitly mark it as unverified. The public service permits moderate usage, may throttle requests, and has no availability guarantee. Manual locations remain available when offline or when no result matches. Map data is attributed to OpenStreetMap contributors.
- Participant profile photos use delegated
User.ReadBasic.Allto read other organizational users' basic profiles, including photos, andContacts.Readfor personal contact photos. See the Microsoft Graph photo permissions. When upgrading an existing Entra app registration, addUser.ReadBasic.Allto its delegated permissions and sign in again to grant the additional consent. Tenant consent policies may require administrator approval. IfGRAPH_SCOPESis overridden, includeUser.ReadBasic.Allthere as well; photos without sufficient permission retain initials. - Participant availability uses Microsoft Graph
getSchedulewith the existing delegatedCalendars.ReadWritepermission; no additional Microsoft 365 consent is required. Exchange calendar sharing and free/busy policies determine which schedules the signed-in account can see. Inaccessible or external mailboxes may show availability as unknown, never as free. Only availability is sent to the UI, without event titles or details. Recurring meetings check the selected time range only. AADSTS500113means the Entra app registration is missing the localhost redirect or public client flows are disabled.- Shared/delegate calendars are not implemented.
- Recurring events and attendee-managed meetings are shown but edited as read-only, with an Outlook handoff.
- Build Windows installers on native Windows or CI (WSL2 is not suitable).
- Auto-updates use GitHub Releases and are user-initiated from
Settings > Sync. - Publishing updates requires a
GH_TOKENwith repository release permissions.