RuntimePurposeState
Module of the Pub Cloudflare Worker with D1 storageCollect availability, generate assignments, record review state, and send schedule emailActive; the former n8n implementation is retired

The Pub Scheduler handles the weekly staffing cycle: opening shifts, collecting tender availability, generating fair assignments, and emailing the schedule. It runs inside the Cloudflare Worker (worker.js) with data in D1—no external automation platform is involved.

Three n8n workflows handled this work in the past. They moved into the Worker in May and June 2026 and are no longer used. This page describes the current system.

Admin UI: https://pub.ihnyc-rc.org/admin/pub-schedule (Cloudflare Access required)


Weekly state flow

The scheduler follows a 4-step weekly cycle, visible as a progress bar in the admin UI:

flowchart LR
  SHIFTS["1. Create shifts"] --> FORM["2. Collect availability"]
  FORM --> ASSIGN["3. Generate and review assignments"]
  ASSIGN --> SEND["4. Approve and send"]
StepWhat happensTriggered by
1. ShiftsOperator creates or seeds shifts for the week (Wed/Thu/Fri/Sat). Shift templates provide one-click seeding.Manual (admin UI)
2. Form & AvailabilityOperator opens the Formbricks availability form. Tenders receive an email with their personalized link. Submissions stream in live.Manual (admin opens form)
3. AssignmentsOperator clicks “Generate assignments”. The algorithm matches tenders to shifts based on availability, fairness history, and staff-needed counts. Operator reviews and can hold/release individual assignments.Manual (admin generates)
4. SendOperator approves and sends the mass schedule email to all active tenders. The email includes shift times, assigned tenders, and ICS calendar links.Manual (admin approves + sends)

The weekly anchor is “week of” — the Sunday that starts the week, computed in America/New_York time.


Data model

All scheduler data lives in CONTENT_DB (Cloudflare D1).

TablePurpose
pub_tendersTender roster: name, email, active status, bio, payment links, profile photo
pub_shiftsWeekly shift slots: date/time range, staff needed, status (Draft/Approved/Sent)
pub_shift_templatesReusable presets (day + time + staff count) for one-click week seeding
pub_assignmentsWhich tender works which shift. Supports hold/release gating
pub_submissionsFormbricks availability responses, one row per response_id
pub_schedule_runsWeekly run state: formOpenedAt, generatedAt, sentAt, status
pub_supervisorsSupervisor contacts shown in email templates
pub_specialsDrink/food specials shown on the right bar TV
pub_admin_auditAudit log of every admin mutation
pub_email_logRecord of every email sent

Admin interface

This Week (/admin/pub-schedule)

The main operator view. A 4-step wizard showing the current week’s progress:

Pub scheduler This Week wizard showing the weekly scheduling steps and their status Weekly scheduling wizard

  • Shifts panel — shows the week’s shifts with status badges. “Apply template” seeds from saved presets.
  • Form & Availability panel — live feed of who has submitted, who is outstanding, and who said “not available this week”. Includes a “Remind outstanding” button to re-email non-responders.
  • Assignments panel — after generating, shows the proposed schedule. Each assignment can be held (excluded from the email) or released. An “Edit assignments” button opens a detailed view.
  • Send panel — preview the email, send to all active tenders, or send a full update if the schedule changes after the initial send. There is no separate “correction” recipient subset.
  • Fairness brief — preview or send the operator-only fairness report to supervisors who opted in.

An Expert toggle shows all four panels at once.

Pub Setup (/admin/pub-setup)

Card grid for less-frequent operations:

Pub Setup page for scheduling defaults, tender access, and service configuration Scheduling configuration and access defaults

  • Tenders — add/edit/archive tenders, upload photos, set payment links
  • Shifts — manage shift templates, edit individual shifts
  • Email Templates — edit the HTML/text templates for schedule, availability, and update emails
  • Supervisors — manage supervisor contacts shown in email footers
  • Email Log — audit trail of every email the scheduler sent
  • Stats — fill rate, opportunity-adjusted fairness, history, and per-tender assignment counts
  • Raw Database — Tabulator grid for direct CRUD on all entities

Assignment algorithm

worker/lib/pub-scheduler/assign.js

  1. Takes the latest finished submission per tender (deduped by token, latest timestamp wins; finished beats unfinished)
  2. Tenders who said “not available” contribute zero slot keys — excluded from assignment
  3. Groups candidates by shift slot key
  4. Fisher-Yates shuffles candidates per slot
  5. Selects up to staff_needed per shift
  6. Fairness: opportunity-adjusted fill rate (assignments / weeks available) breaks ties so under-scheduled tenders get priority

Emails

Three email types, all with customizable HTML/text templates:

TypeWhenWhat
AvailabilityStep 2 (form opens)Personalized Formbricks link per tender
ScheduleStep 4 (send)Full weekly schedule with shift times, assigned tenders, ICS calendar links
UpdateAfter initial sendFull current schedule plus the added/removed-assignment diff; sent to all active recipients with the normal subject prefixed by [UPDATE]

Templates are editable at /admin/pub-setup > Email Templates. Each type has four styles (Branded, Classic, Clean, Minimal). The branded style uses the AVI + Affective Technologies joint logo with a navy/teal-green palette.

Emails are sent via the worker’s configured email provider. Every send is logged in pub_email_log with recipient, subject, timestamp, and send result.

The fairness brief is separate from the tender schedule. It summarizes assignment opportunity and outcomes for opted-in supervisors; it is not sent to tenders.


Shift templates

Reusable presets stored in pub_shift_templates. Each template specifies:

  • Day of week (0=Sun through 6=Sat)
  • Start and end time (HH:MM, supports overnight spans)
  • Staff needed count
  • Display label

“Apply to week” stamps a template into pub_shifts for a specific week, computing the correct date with America/New_York DST handling.

Managed via the Shifts page under Pub Setup, or the Templates tab in the Raw Database view.


Availability polling

The worker’s scheduled() cron polls Formbricks for new responses on a cadence (configurable, typically during the Fri-Sun availability window). Each response is normalized and upserted into pub_submissions keyed by response_id.

If a tender submits multiple times, all rows are stored. The checklist and assignment algorithm deduplicate at read time: latest finished submission per tender wins.


Specials

Drink and food specials managed at /admin/pub-specials. Each special has a title, price label, description, optional image, and an active toggle. Active specials appear in the right bar TV’s rotation on their linked shift days.


Weekly auto-remind

A cron job (scheduled()) sends a single reminder email per week to the operator listing outstanding tenders who haven’t submitted their availability form. The reminder fires once per pub_schedule_runs row (tracked by reminded_at).


Migration history

Migrations are in migrations/content/ and applied manually via wrangler d1 execute CONTENT_DB --remote --file=<path>. Key migrations:

MigrationWhat
0005pub_submissions table
0006available + slots_offered columns on submissions
0008pub_tenders + pub_shifts tables
0009pub_admin_audit table
0010FK indexes on pub_assignments
0011pub_shift_templates table
0012Sent-assignments snapshot for update-email diff
0013Shift status rename (CreatedDraft, ArchivedSent)
0014Assignment hold/release columns
0015Supervisor contacts table
0016Email log table
0017Pub specials table
0018Schedule run reminded_at column
0020Specials shift_ids column
0021Tutorial versions table
0052Email-log attachments
0053Per-supervisor fairness-report delivery

0 items under this folder.