After iterating with Claude.ai I opted for executing this generated Claude Code instruction to see if a google calendar sync could be built. This prompting session took about an hour. The Claude code is running now. I did have to pay for $100 Claude code premium seat so this will be evaluated to see if it is worthwhile.
This solution is targeted to reduce a projected $120 / yr subscription cost for something like reclaim.ai
π― Phase 1: Local Development First
- JSON-based configuration – easy to share and backup
- Docker Compose for simple setup
- File-based storage – no database complexity
- Portable configs between team members
- Git repo for version control and collaboration
π Project Structure
calendar-sync/
βββ docker-compose.yml # Complete local environment
βββ Dockerfile # App container
βββ requirements.txt # Python dependencies
βββ README.md # Setup instructions
βββ .env.example # Environment template
βββ .gitignore # Ignore secrets and data
β
βββ app/
β βββ main.py # FastAPI web app
β βββ sync_engine.py # Core sync logic
β βββ scheduler.py # Background sync scheduler
β βββ google_auth.py # Google OAuth handling
β βββ models.py # Data models
β
βββ config/
β βββ user_config.json # User's calendar connections
β βββ sync_rules.json # Sync rule definitions
β βββ settings.json # App settings
β
βββ data/
β βββ credentials/ # Google OAuth tokens (gitignored)
β βββ logs/ # Sync operation logs
β βββ sync_history.json # Record of past syncs
β
βββ web/
βββ index.html # Simple web interface
βββ style.css # Basic styling
βββ app.js # Frontend JavaScript
π§ Configuration Files (Portable JSON)
config/settings.json – App Settings
{
"app": {
"name": "Calendar Sync",
"version": "1.0.0",
"host": "0.0.0.0",
"port": 8000
},
"sync": {
"interval_minutes": 30,
"window_days_ahead": 30,
"window_days_behind": 7,
"max_retries": 3,
"timeout_seconds": 300
},
"google_api": {
"scopes": [
"https://www.googleapis.com/auth/calendar"
],
"credentials_file": "data/credentials/google_credentials.json"
},
"logging": {
"level": "INFO",
"file": "data/logs/calendar-sync.log",
"max_size_mb": 10,
"backup_count": 5
}
}
config/user_config.json – User’s Connected Calendars
{
"user_id": "john_doe",
"google_accounts": [
{
"email": "john@gmail.com",
"nickname": "Personal",
"calendars": [
{
"id": "john@gmail.com",
"name": "Personal Calendar",
"access": "read_write",
"color": "#4285F4"
}
],
"credentials_file": "data/credentials/john_personal.json"
},
{
"email": "john@company.com",
"nickname": "Work",
"calendars": [
{
"id": "john@company.com",
"name": "Work Calendar",
"access": "read_write",
"color": "#34A853"
}
],
"credentials_file": "data/credentials/john_work.json"
}
],
"created_at": "2024-11-17T10:00:00Z",
"last_updated": "2024-11-17T10:00:00Z"
}
config/sync_rules.json – Sync Rules Configuration
{
"sync_rules": [
{
"id": "personal_to_work",
"name": "Personal β Work",
"enabled": true,
"source": {
"calendar_id": "john@gmail.com",
"account_email": "john@gmail.com"
},
"targets": [
{
"calendar_id": "john@company.com",
"account_email": "john@company.com"
}
],
"sync_event_template": {
"title": "Busy (Personal)",
"description": "Auto-synced from personal calendar",
"visibility": "private",
"show_as": "busy"
},
"filters": {
"exclude_all_day": true,
"exclude_declined": true,
"exclude_tentative": false,
"exclude_keywords": ["test", "maybe"],
"only_show_as_busy": true
}
},
{
"id": "work_to_personal",
"name": "Work β Personal",
"enabled": true,
"source": {
"calendar_id": "john@company.com",
"account_email": "john@company.com"
},
"targets": [
{
"calendar_id": "john@gmail.com",
"account_email": "john@gmail.com"
}
],
"sync_event_template": {
"title": "Busy (Work)",
"description": "Work commitment",
"visibility": "private",
"show_as": "busy"
},
"filters": {
"exclude_all_day": true,
"exclude_declined": true,
"exclude_tentative": true,
"exclude_keywords": ["lunch", "optional"],
"only_show_as_busy": true
}
}
],
"global_settings": {
"sync_marker": "[AUTO-SYNC]",
"conflict_resolution": "skip",
"cleanup_old_events": true,
"max_events_per_sync": 100
}
}
data/sync_history.json – Operation History
{
"sync_operations": [
{
"id": "sync_20241117_100000",
"timestamp": "2024-11-17T10:00:00Z",
"duration_seconds": 12.5,
"rules_processed": [
{
"rule_id": "personal_to_work",
"events_read": 15,
"events_created": 8,
"events_updated": 2,
"events_skipped": 5,
"errors": []
}
],
"total_events_processed": 15,
"total_events_synced": 10,
"status": "success"
}
],
"last_sync": "2024-11-17T10:00:00Z",
"total_syncs": 47,
"success_rate": 0.98
}
π³ Docker Compose Setup
docker-compose.yml
version: '3.8'
services:
calendar-sync:
build: .
container_name: calendar-sync-app
ports:
- "8000:8000"
volumes:
# Config files (editable)
- ./config:/app/config
# Data directory (credentials, logs, history)
- ./data:/app/data
# Web assets
- ./web:/app/web
environment:
- PYTHONPATH=/app
- CONFIG_DIR=/app/config
- DATA_DIR=/app/data
restart: unless-stopped
command: >
sh -c "
python -m app.main &
python -m app.scheduler
"
# Optional: Simple file browser for config management
config-manager:
image: filebrowser/filebrowser
container_name: calendar-sync-files
ports:
- "8001:80"
volumes:
- ./config:/srv/config
- ./data/logs:/srv/logs:ro
environment:
- FB_BASEURL=/files
profiles: ["tools"] # Optional service
volumes:
calendar_data:
driver: local
Dockerfile
FROM python:3.11-slim
WORKDIR /app
# Install dependencies
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# Copy application code
COPY app/ ./app/
COPY web/ ./web/
# Create directories for config and data
RUN mkdir -p /app/config /app/data/credentials /app/data/logs
# Set proper permissions
RUN chmod +x /app
EXPOSE 8000
CMD ["python", "-m", "app.main"]
π Quick Start Instructions
1. Initial Setup (5 minutes)
# Clone the repository
git clone https://github.com/your-team/calendar-sync.git
cd calendar-sync
# Copy environment template
cp .env.example .env
# Create initial config directories
mkdir -p data/credentials data/logs
mkdir -p config
# Copy example configs
cp config.examples/* config/
2. Google OAuth Setup
# 1. Go to Google Cloud Console
# 2. Create new project or select existing
# 3. Enable Google Calendar API
# 4. Create OAuth 2.0 credentials (Desktop application)
# 5. Download credentials.json to data/credentials/
3. Run Locally
# Start the application
docker-compose up -d
# Check if running
curl http://localhost:8000
# View logs
docker-compose logs -f
# Access web interface
open http://localhost:8000
4. Configuration Setup
# Edit your calendar connections
nano config/user_config.json
# Setup sync rules
nano config/sync_rules.json
# Adjust settings
nano config/settings.json
# Restart to apply changes
docker-compose restart
π Usage Workflow
For Each Team Member:
- Clone repo:
git clone ... - Setup Google OAuth: Download their credentials
- Edit user_config.json: Add their calendar details
- Edit sync_rules.json: Configure their sync preferences
- Run:
docker-compose up -d - Verify: Check web interface at
localhost:8000
Config Sharing Between Team:
# Share base configuration (without credentials)
git add config/settings.json
git add config/sync_rules.json.example
git commit -m "Update sync configuration template"
# Each person customizes locally
cp config/sync_rules.json.example config/sync_rules.json
# Edit with personal calendar details
π Simple Web Interface
web/index.html (Simple & Clean)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Calendar Sync</title>
<script src="https://cdn.tailwindcss.com"></script>
</head>
<body class="bg-gray-100 min-h-screen py-8">
<div class="max-w-4xl mx-auto px-4">
<h1 class="text-3xl font-bold text-gray-900 mb-8">Calendar Sync Dashboard</h1>
<!-- Status Overview -->
<div class="grid grid-cols-1 md:grid-cols-3 gap-6 mb-8">
<div class="bg-white p-6 rounded-lg shadow">
<h3 class="text-lg font-semibold text-gray-900 mb-2">Sync Status</h3>
<div id="sync-status" class="text-sm text-gray-600">Loading...</div>
</div>
<div class="bg-white p-6 rounded-lg shadow">
<h3 class="text-lg font-semibold text-gray-900 mb-2">Connected Calendars</h3>
<div id="calendar-count" class="text-2xl font-bold text-blue-600">-</div>
</div>
<div class="bg-white p-6 rounded-lg shadow">
<h3 class="text-lg font-semibold text-gray-900 mb-2">Active Sync Rules</h3>
<div id="rules-count" class="text-2xl font-bold text-green-600">-</div>
</div>
</div>
<!-- Actions -->
<div class="bg-white p-6 rounded-lg shadow mb-8">
<h2 class="text-xl font-semibold text-gray-900 mb-4">Actions</h2>
<div class="space-x-4">
<button id="manual-sync" class="bg-blue-500 hover:bg-blue-600 text-white px-6 py-2 rounded">
π Run Sync Now
</button>
<button id="reload-config" class="bg-gray-500 hover:bg-gray-600 text-white px-6 py-2 rounded">
βοΈ Reload Config
</button>
</div>
</div>
<!-- Sync History -->
<div class="bg-white p-6 rounded-lg shadow">
<h2 class="text-xl font-semibold text-gray-900 mb-4">Recent Sync Operations</h2>
<div id="sync-history" class="space-y-2">
<p class="text-gray-600">Loading sync history...</p>
</div>
</div>
</div>
<script src="app.js"></script>
</body>
</html>
π Development Roadmap
Phase 1: Local MVP (This Weekend)
- β JSON-based configuration system
- β Docker Compose environment
- β Basic calendar sync engine
- β Simple web dashboard
- β Manual sync trigger
Phase 2: Enhanced Local (Next Weekend)
- β Automated scheduling (every 30 minutes)
- β Better error handling and logging
- β Config validation
- β Sync history tracking
- β Team documentation
Phase 3: Server Deployment (Later)
- π Multi-user support
- π Web-based config editor
- π User authentication
- π Azure Container Apps deployment
- π Shared team dashboard
π Benefits of This Approach
β Immediate Benefits
- 5-minute setup per team member
- No server costs during development
- Complete data privacy (everything local)
- Easy to debug and modify
- Version controlled configurations
β Team Collaboration
- Shared repo for code updates
- Template configs for easy setup
- Documentation in the repo
- Issue tracking via GitHub
- Easy deployment when ready
β Future Growth
- Proven architecture ready for server deployment
- Portable configs can move to database later
- Team can scale from local to hosted
- Investment protected – code translates directly
This gives you a working calendar sync solution in hours, not days, while building the foundation for a more sophisticated server-based system later!