Editing a recurring event prompts choice of 'this only', 'this and future', or 'all'
Why it matters
Without a scope prompt, editing a single weekly-recurring slot rewrites every past and future occurrence, corrupting historical schedules and silently changing appointments customers have already booked. Hosts lose the ability to handle one-off changes (vacation, a shifted single week) without breaking the entire series. This erodes trust in the scheduling tool, forces manual database fixes, and can cause calendar-invite mismatches where the host's system shows one time and the attendee's another.
Severity rationale
Info because this is a capability gap rather than an active defect, but absence blocks common scheduling workflows and causes data churn when workarounds are used.
Remediation
Before applying any edit to a recurring event, open a dialog offering three choices: 'this only' (insert a row into availability_exceptions with the occurrence date), 'this and future' (set a new dtstart on a cloned rule), and 'all' (mutate the original rrule). Branch your persistence logic on the returned scope. See src/components/RecurringEditScopeDialog.tsx:
const scope = await showScopeDialog() // 'this' | 'thisFuture' | 'all'
if (scope === 'this') await db.availabilityExceptions.create({ recurringId, exceptionDate })
Detection
-
ID:
recurring-edit-scope -
Severity:
info -
What to look for: Search for recurring event edit UI components. Count all edit scope options presented to the user. Look for a dialog, modal, or prompt that offers at least 3 choices when editing a recurring event instance:
- "Edit this only" — applies change to this single instance (creates an exception).
- "Edit this and future" — applies change to this and all future occurrences (modifies rule dtstart).
- "Edit all" — applies change to the entire series (modifies the rule itself).
Verify that the code branches on the user's choice and applies the correct update. Examine files matching
src/components/*RecurringEdit*,src/components/*ScopeDialog*,src/components/*Schedule*.
-
Pass criteria: Enumerate all edit scope options in the recurring edit UI. At least 3 scope options must be presented ("this only", "this and future", "all"). Each option must trigger a distinct code path (exception creation, rule modification from date, or full rule update). Report: "Edit scope options: [list]. X of 3 required scopes implemented."
-
Fail criteria: No scope prompt appears when editing a recurring event, or only 1 scope option exists (e.g., always edits all occurrences).
-
Skip (N/A) when: Platform does not support editing recurring schedules, or does not have recurring schedule features.
-
Detail on fail: Example:
"Editing a recurring Wednesday availability updates all occurrences, even past ones. No option to edit just future occurrences." -
Cross-reference: Check
rule-based-storage— edit scopes require rule-based storage to function properly. -
Cross-reference: Check
exception-handling— "edit this only" creates an exception that must be applied in real time. -
Cross-reference: Check
data-freshness— after editing scope, the calendar must refetch to reflect the change. -
Remediation: Add a scope prompt when editing recurring schedules:
async function handleEditRecurring(eventId) { const scope = await showScopeDialog() // Options: 'this', 'thisFuture', 'all' if (scope === 'this') { // Create exception for this date only await db.availabilityExceptions.create({ recurringId: eventId, exceptionDate: selectedDate, isAvailable: false, }) } else if (scope === 'thisFuture') { // Update rule with new dtstart await db.recurringAvailability.update({ where: { id: eventId }, data: { rrule: updatedRRule }, }) } else if (scope === 'all') { // Update entire recurring rule await db.recurringAvailability.update({ where: { id: eventId }, data: { rrule: updatedRRule }, }) } }
Taxons
History
- 2026-04-18·v1.0.0·Initial import from booking-calendar-availability·automated