Verified Programs calendar subscriptions for residents, with a protected operator console for delivery, health, and email management.

Documentation

AreaStart here
Subscription behaviorPrograms calendar flow
Runtime and request flowArchitecture
Routes and response contractsAPI reference
Tables and storageData model
External servicesIntegrations
Deployment and recoveryOperations guide

Live site: calendar.ihnyc-rc.org

Repository: dghauri0/ihnyc-rc-cal-landing

The Calendar home page with public Programs and council-only Internal calendar choices Calendar home · July 2026

The Programs subscription form with name, email, bot check, and Get my link button Programs subscription · June 2026

What a resident experiences

flowchart LR
  PERSON["1. Enter name and email"] --> MAIL["2. Receive a magic link"]
  MAIL --> VERIFY["3. Open the link"]
  VERIFY --> URL["4. Receive a private calendar URL"]
  URL --> APP["5. Calendar app refreshes the feed"]

The private URL contains a random calendar token. The service stores only its SHA-256 hash; it does not need the plaintext token after issuing the URL.

What runs behind that flow

  • Eleventy builds the public pages from src/ into dist/.
  • Cloudflare Pages Functions handle subscriptions, renewal, admin APIs, and feed delivery.
  • D1 stores subscribers, token hashes, access logs, email events, templates, and first-party product/security events.
  • R2 stores the generated programs.ics file.
  • Resend delivers magic-link and renewal email.
  • Turnstile can screen automated subscription requests.
  • A scheduled endpoint rebuilds programs.ics from selected Notion events every 15 minutes.
  • The legacy Internal calendar alone still proxies to n8n.
  • The admin Tools area edits each email’s subject, headline, body, button, supporting prose, and one shared footer. Preview uses the real email renderer and saves version history.
  • The admin uses the shared Admin Kit controls while keeping the Calendar visual system.

Mixpanel has been removed. Current analytics are first-party D1 records; see Calendar analytics.

Public Programs flow

  1. POST /api/subs/new?calendar_id=programs validates the request, applies the cooldown, and sends a short-lived magic link.
  2. GET /api/subs/verify?...&v=... consumes the one-time verification code and mints a calendar token.
  3. GET /cal/programs.ics?token=...&calendar_id=programs hashes the presented token, validates its record, and returns the R2 object.
  4. Renewal email contains a separate, expiring signed credential. It can extend the token record but cannot fetch the calendar feed.
sequenceDiagram
  participant Resident
  participant Calendar as Calendar service
  participant Email as Resend
  participant D1
  participant R2

  Resident->>Calendar: Request a subscription
  Calendar->>D1: Store one-time code hash
  Calendar->>Email: Send magic link
  Email-->>Resident: Verification link
  Resident->>Calendar: Open link
  Calendar->>D1: Consume code and store token hash
  Calendar-->>Resident: Private feed URL
  Resident->>Calendar: Calendar app fetches with token
  Calendar->>D1: Validate token hash
  Calendar->>R2: Read programs.ics
  R2-->>Resident: Calendar feed

Admin access has two gates

Every /api/admin/* request must pass both checks:

  1. Identity: the Cloudflare Access JWT is verified in application code.
  2. Authorization: the request is mapped to an action such as subscriber.revoke; RC Console confirms that the person’s current role includes it.

Unknown routes and policy-service failures are denied. See RC Console identity and access for the relationship.

Key routes

RouteMethodAccessPurpose
/subscribe-programsGETPublicResident subscription page
/api/subs/newPOSTPublic; Turnstile when configuredStart subscription
/api/subs/verifyGETOne-time magic linkMint the private feed token
/renewGETSigned renewal credentialShow the renewal confirmation
/api/subs/extendPOSTSigned renewal credential or legacy tokenExtend an existing token
/cal/programs.icsGET/HEADCalendar tokenServe Programs ICS from R2
/cal/internal.icsGET/HEADInternal access boundaryProxy the legacy Internal feed
/api/cron/regenerate-programs-icsPOSTCron bearer tokenRebuild the Programs feed from Notion
/api/cron/renewal-warningsPOSTCron bearer tokenSend renewal reminders
/api/admin/*VariesAccess JWT and RC Console roleOperate and observe the service

See the API reference for the complete admin action list.

Storage

flowchart LR
  CAL["Calendar Pages Functions"] --> SUBS[("D1: subscriptions and token hashes")]
  CAL --> EVENTS[("D1: events, email outcomes, templates")]
  CAL --> FEED[("R2: programs.ics")]
  NOTION["Notion Events"] -->|scheduled rebuild| CAL
  ADMIN["RC Console policy service"] -. allow or deny admin action .-> CAL

Detailed documentation

  • end-user — subscribe and troubleshoot as a resident
  • architecture — request routing and trust boundaries
  • programs-ics-generation — Notion-to-R2 feed generation, timed and all-day events
  • mixpanel — current D1 analytics and the retired Mixpanel path
  • api — routes, methods, and authorization
  • data — D1 and R2 data model
  • ops — development, deployment, and failure checks

5 items under this folder.