Skip to content

calendar access migration - implementation checklist #216

@abe-101

Description

@abe-101

calendar access migration - implementation checklist

overview

migrate myhebrewdates.com from public calendar urls to authenticated user-based subscriptions for enhanced security and user-specific features.

current: myhebrewdates.com/calendars/a1b2c3d4-5e6f-7a8b-9c0d-1e2f3a4b5c6d.ics (78 chars)
new: myhebrewdates.com/c/tjqfbixfh3b.ics (43 chars - 35 chars shorter!)


implementation status

✅ phase 1: core infrastructure (completed)

database models

  • install shortuuid package (v1.0.13)
  • create usercalendarsubscription model
    • 11-character short uuid (subscription_id)
    • user and calendar foreign keys
    • alarm_time field (default: 9)
    • last_accessed timestamp
    • unique constraint on (user, calendar)
  • update calendar model
    • add migrated_at timestamp field
    • add subscribers m2m relationship (through usercalendarsubscription)
    • add is_migrated property
    • add migrate_to_authenticated() method
  • create migrations
    • initial subscription models migration
    • add alarm_time field migration
    • add calendar subscribers m2m migration
    • data migration for existing owner subscriptions

url routing

  • add top-level subscription route: /c/<subscription_id>.ics
  • add /calendars/<uuid>/subscribe/ endpoint
  • add htmx alarm update endpoint: /update-subscription-alarm-htmx/<subscription_id>/

views

  • calendar_subscription_file - serve .ics using subscription_id (uses db alarm_time)
  • calendar_subscribe_view - quick subscribe redirect (handles auth via allauth)
  • update_subscription_alarm_htmx - update alarm preference via htmx
  • update calendar_file - check migration status, return 410 if migrated
  • update calendar_detail_view - auto-create subscriptions for authenticated users
  • update create_calendar_view - auto-create owner subscription on calendar creation
  • update calendar_list_view - show owned + subscribed calendars

templates

  • _calendar_subscribe_links.html - reusable subscription links (apple, google, office365, outlook)
  • _calendar_links_htmx.html - htmx wrapper for legacy calendar alarm updates
  • calendar_migration_required.html - 410 gone page for migrated calendars
  • update calendar_detail.html - show alarm selector for migrated calendars
  • update calendar_list.html - conditional subscribed calendars section

admin

  • usercalendarsubscriptionadmin - list display with alarm_time, filters
  • update calendaradmin - show migration status, subscription count
  • admin action: "enable migration" (sets migrated_at, creates owner subscription)
  • admin action: "send migration email" (placeholder for future implementation)

📋 phase 2: testing & validation (todo)

unit tests

  • usercalendarsubscription model creation with alarm_time
  • 11-character subscription_id uniqueness
  • alarm time defaults to 9
  • get_calendar_url() returns url without alarm parameter
  • calendar_subscription_file uses subscription.alarm_time from db
  • update_subscription_alarm_htmx updates alarm without changing url
  • auto-subscription creation on calendar creation
  • auto-subscription creation on calendar view (authenticated users)
  • legacy calendar_file blocks migrated calendars (410 response)

integration tests

  • full subscribe flow: visit url → login redirect → subscription created
  • calendar file generation via subscription_id
  • alarm time update doesn't change subscription url
  • legacy url returns 410 after migration
  • reusable template works for both migrated and non-migrated
  • admin migration action creates subscriptions

manual testing

  • create calendar → verify owner subscription auto-created
  • view calendar as authenticated user → verify subscription auto-created
  • subscribe to calendar via new flow
  • change alarm time → verify url stays the same
  • test apple calendar subscription with new url
  • test google calendar subscription with new url
  • verify subscription url is 35 characters shorter
  • test migration required page (410 response)
  • test calendar list shows subscribed calendars section

🚀 phase 3: rollout strategy (todo)

week 1-2: deploy & verify

  • deploy all changes to production
  • run migrations
  • verify all calendars remain unmigrated (migrated_at=null)
  • test with internal accounts
  • verify subscriptions auto-created on calendar creation
  • verify subscriptions auto-created when users view calendars

week 3: pilot migration (5-10 calendars)

  • select pilot calendars (internal/test users)
  • enable migration via admin action
  • notify users via email (using placeholder function)
  • monitor logs for migration page visits
  • gather user feedback

week 4-8: gradual rollout

  • week 4: migrate 10% of calendars
  • week 5: migrate 25% of calendars
  • week 6: migrate 50% of calendars
  • week 7: migrate 75% of calendars
  • week 8: migrate 100% of calendars

monitoring metrics:

  • subscription creation rate
  • migration page visits
  • support tickets
  • user feedback

week 9+: completion

  • all calendars migrated
  • legacy urls return 410 gone
  • monitor stragglers
  • document lessons learned

📧 phase 4: email notifications (todo)

  • implement send_migration_notification_email() function
  • create email template for migration notification
  • create email template for migration success
  • test email sending with real addresses
  • update admin action to send actual emails

key features

alarm time management

database-driven - alarm preference stored on usercalendarsubscription
stable urls - subscription url never changes when alarm is updated
htmx updates - live alarm changes without page reload
user flexibility - change alarm anytime without resubscribing

auto-subscription creation

on calendar creation - owner subscription created automatically
on calendar view - authenticated viewers get subscriptions
pre-migration - subscriptions ready before migration happens
idempotent - get_or_create prevents duplicates

security & privacy

authenticated access - migrated calendars require login
per-user urls - each subscriber gets unique subscription_id
short urls - 11-character ids like youtube (vs 36-char uuids)
backwards compatible - legacy urls work until migration


technical notes

url comparison

legacy:  https://myhebrewdates.com/calendars/a1b2c3d4-5e6f-7a8b-9c0d-1e2f3a4b5c6d.ics (78 chars)
new:     https://myhebrewdates.com/c/tjqfbixfh3b.ics (43 chars)
savings: 35 characters shorter!

subscription id security

  • 11 characters from base57 alphabet
  • ~10^19 combinations (extremely low collision risk)
  • django-enforced uniqueness at database level
  • similar to youtube video ids (familiar ux)

migration states

  1. not migrated (migrated_at = null)

    • legacy url works: /calendars/<uuid>.ics
    • subscription url available but not required
    • htmx updates change url with alarm parameter
  2. migrated (migrated_at != null)

    • legacy url returns 410 gone
    • only subscription urls work: /c/<subscription_id>.ics
    • alarm from db, url stays stable

reference

implementation files:

  • models: my_hebrew_dates/hebcal/models.py
  • views: my_hebrew_dates/hebcal/views.py
  • urls: my_hebrew_dates/hebcal/urls.py + config/urls.py
  • templates: my_hebrew_dates/templates/hebcal/
  • admin: my_hebrew_dates/hebcal/admin.py
  • migrations: my_hebrew_dates/hebcal/migrations/

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions