[Feature] Push interview events to connected calendar integrations #19

Closed
opened 2026-03-16 20:30:43 -07:00 by pyr0ball · 0 comments
Owner

Overview

When a user saves an interview date on the Interviews kanban, a "📅 Add to Calendar" button should appear that pushes the event to their connected calendar integration.

Design decisions

  • Separate button — not auto-pushed on save; user may save a date before they are ready to block their calendar
  • Duration — default 1 hour from start; no time picker in v1 (noon UTC as default start time). Add a time slider later if users request it
  • Backends — implement both Apple Calendar (CalDAV) and Google Calendar for real; not stub
  • Idempotency — track calendar_event_id in staging.db; pushing again updates the event rather than creating a duplicate

Implementation scope

1. scripts/db.py

  • Add calendar_event_id TEXT column to jobs table (migration, nullable)
  • Add set_calendar_event_id(db_path, job_id, event_id) helper

2. scripts/integrations/apple_calendar.py

  • Add create_event(title, start_dt, end_dt, description) -> str using caldav library
  • Add update_event(event_id, title, start_dt, end_dt, description) for idempotent re-push

3. scripts/integrations/google_calendar.py

  • Add create_event(title, start_dt, end_dt, description) -> str using google-api-python-client (service account credentials JSON path already in config)
  • Add update_event(event_id, ...) for idempotent re-push

4. scripts/calendar_push.py (new)

  • push_interview_event(db_path, job_id, config_dir) -> dict — detects connected calendar integration, loads its config, creates/updates the event, persists calendar_event_id to db
  • Event title format: "{stage_label}: {job_title} @ {company}"
  • Event description: job URL + one-line company research summary if available
  • Returns {"ok": True, "provider": "apple_calendar", "event_id": "..."} or {"ok": False, "error": "..."}

5. app/pages/5_Interviews.py

  • After the date-picker form (phone_screen / interviewing stages), show "📅 Add to Calendar" button when:
    • interview_date is set, AND
    • at least one calendar integration config file exists
  • Button label changes to "🔄 Update Calendar" if calendar_event_id is already set
  • Tier gate: calendar integrations are paid tier

6. environment.yml

  • Add caldav and google-api-python-client (both are installed but not pinned)

Out of scope (v1)

  • Time-of-day picker (default noon, 1hr duration)
  • Multiple calendars simultaneously
  • iCalendar (.ics) file download fallback

Acceptance criteria

  • Saving a date on a phone_screen or interviewing card shows the calendar button
  • First push creates an event and stores calendar_event_id in db
  • Second push updates the existing event (idempotent)
  • Button is hidden if no calendar integration is configured
  • Works end-to-end with Apple CalDAV; Google Calendar tested with service account
  • environment.yml updated
  • Unit tests for calendar_push.py (mock integration classes)
## Overview When a user saves an interview date on the Interviews kanban, a **"📅 Add to Calendar"** button should appear that pushes the event to their connected calendar integration. ## Design decisions - **Separate button** — not auto-pushed on save; user may save a date before they are ready to block their calendar - **Duration** — default 1 hour from start; no time picker in v1 (noon UTC as default start time). Add a time slider later if users request it - **Backends** — implement both Apple Calendar (CalDAV) and Google Calendar for real; not stub - **Idempotency** — track `calendar_event_id` in `staging.db`; pushing again updates the event rather than creating a duplicate ## Implementation scope ### 1. `scripts/db.py` - Add `calendar_event_id TEXT` column to `jobs` table (migration, nullable) - Add `set_calendar_event_id(db_path, job_id, event_id)` helper ### 2. `scripts/integrations/apple_calendar.py` - Add `create_event(title, start_dt, end_dt, description) -> str` using `caldav` library - Add `update_event(event_id, title, start_dt, end_dt, description)` for idempotent re-push ### 3. `scripts/integrations/google_calendar.py` - Add `create_event(title, start_dt, end_dt, description) -> str` using `google-api-python-client` (service account credentials JSON path already in config) - Add `update_event(event_id, ...)` for idempotent re-push ### 4. `scripts/calendar_push.py` (new) - `push_interview_event(db_path, job_id, config_dir) -> dict` — detects connected calendar integration, loads its config, creates/updates the event, persists `calendar_event_id` to db - Event title format: `"{stage_label}: {job_title} @ {company}"` - Event description: job URL + one-line company research summary if available - Returns `{"ok": True, "provider": "apple_calendar", "event_id": "..."}` or `{"ok": False, "error": "..."}` ### 5. `app/pages/5_Interviews.py` - After the date-picker form (phone_screen / interviewing stages), show **"📅 Add to Calendar"** button when: - `interview_date` is set, AND - at least one calendar integration config file exists - Button label changes to **"🔄 Update Calendar"** if `calendar_event_id` is already set - Tier gate: calendar integrations are `paid` tier ### 6. `environment.yml` - Add `caldav` and `google-api-python-client` (both are installed but not pinned) ## Out of scope (v1) - Time-of-day picker (default noon, 1hr duration) - Multiple calendars simultaneously - iCalendar (.ics) file download fallback ## Acceptance criteria - [ ] Saving a date on a phone_screen or interviewing card shows the calendar button - [ ] First push creates an event and stores `calendar_event_id` in db - [ ] Second push updates the existing event (idempotent) - [ ] Button is hidden if no calendar integration is configured - [ ] Works end-to-end with Apple CalDAV; Google Calendar tested with service account - [ ] `environment.yml` updated - [ ] Unit tests for `calendar_push.py` (mock integration classes)
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: Circuit-Forge/peregrine#19
No description provided.