Skip to content

pkieszcz/calendar-sync

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

4 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Calendar Sync

Self-hosted calendar sync that creates busy blocks across calendars. Supports Google Calendar and CalDAV (iCloud, Fastmail, etc).

Prerequisites

  • Docker & Docker Compose
  • Google Cloud project with Calendar API enabled (for Google Calendar)
  • iCloud app-specific password (for iCloud)

Setup

1. Clone and configure

git clone https://github.com/pkieszcz/calendar-sync.git
cd calendar-sync
cp .env.example .env

2. Generate an encryption key

./scripts/generate-encryption-key.sh
# Paste the output into your .env file

3. Set up Google OAuth (optional)

  1. Go to Google Cloud Console
  2. Create a project and enable the Google Calendar API
  3. Create OAuth 2.0 credentials (Web application)
  4. Add http://localhost:8080/api/auth/google/callback as an authorized redirect URI
  5. Add GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET to .env

4. Start

make up
# or: docker compose up --build -d

5. Connect accounts

Google Calendar:

  1. Click "Connect Google" on the Accounts page
  2. Complete the OAuth flow

iCloud (CalDAV):

  1. Generate an app-specific password at appleid.apple.com
  2. Click "Add CalDAV" on the Accounts page
  3. Enter:
    • Name: anything (e.g. "iCloud")
    • Server URL: https://caldav.icloud.com
    • Username: your Apple ID email
    • Password: the app-specific password
  4. Click "Show Calendars" then "Refresh" to discover calendars

6. Enable sync

  1. Click "Show Calendars" on each account
  2. Check the calendars you want to sync (e.g. one from Google, one from iCloud)
  3. Sync rules are created automatically between calendars from different accounts
  4. Events sync as "Busy" blocks every 60 seconds

Architecture

┌──────────┐    ┌──────────┐    ┌──────────┐
│ Frontend │───>│ Backend  │───>│ Postgres │
│ Next.js  │    │   Go     │    │          │
└──────────┘    └────┬─────┘    └──────────┘
                     │
              ┌──────┴──────┐
              │ Sync Engine │ (polls every 30s)
              └──────┬──────┘
           ┌─────────┴─────────┐
           v                   v
    ┌────────────┐     ┌────────────┐
    │  Google    │     │  CalDAV    │
    │  Calendar  │     │  (iCloud)  │
    └────────────┘     └────────────┘
  • Backend: Go 1.23, Chi router, pgx v5, golang-migrate
  • Frontend: Next.js (App Router), TypeScript, Tailwind CSS
  • Database: PostgreSQL 16
  • Credentials: AES-256-GCM encrypted at rest

Configuration

Variable Required Description
DATABASE_URL Yes PostgreSQL connection string
ENCRYPTION_KEY Yes 32-byte hex-encoded AES key
GOOGLE_CLIENT_ID No Google OAuth client ID
GOOGLE_CLIENT_SECRET No Google OAuth client secret
GOOGLE_REDIRECT_URL No OAuth redirect (default: http://localhost:8080/api/auth/google/callback)
FRONTEND_URL No Frontend URL for CORS (default: http://localhost:3000)

Development

# Run everything
make up

# Logs
make logs

# Stop
make down

# Run backend locally
cd backend && go run ./cmd/server

# Run frontend locally
cd frontend && npm run dev

API

Method Endpoint Description
GET /api/health Health check
GET/POST /api/accounts List/create accounts
DELETE /api/accounts/:id Delete account
GET /api/accounts/:id/calendars List calendars
POST /api/accounts/:id/calendars/refresh Refresh from provider
PUT /api/calendars/:id/sync Toggle sync on/off
GET /api/events?start=&end= List events for calendar view
POST /api/sync-rules/:id/trigger Manually trigger sync
GET /api/sync-status Sync status overview

License

Apache 2.0

About

Self-hosted calendar sync - creates busy blocks across Google Calendar and CalDAV (iCloud)

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors