feat: series-aware schedule edits + waitlist ledger removal (M32)

PATCH /v1/catalog/class-schedules/:id patches a recurring rule and,
with applyToFuture, retimes materialized future sessions to the new
local start time on their existing dates — moving confirmed and
waitlisted bookings with them and re-arming reminders. Zones-page
schedule rows gain an inline editor (CS/EN).

Also drops the vestigial waitlist_entries table (migration 00020):
positions derive from bookings.created_at, so the ledger was written
but never read.

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
Tomas DvorakandDevin committed 2026-09-22 20:59:34 +02:00
1 parent 55fc0d06e3
commit 65a693cf38
17 files changed
+840 -230

No files matched your search

+51 -1
View File
@@ -429,7 +429,7 @@ export interface paths {
delete: operations["deleteClassSchedule"];
options?: never;
head?: never;
patch?: never;
patch: operations["updateClassSchedule"];
trace?: never;
};
"/v1/catalog/class-sessions": {
@@ -1912,6 +1912,16 @@ export interface components {
primaryColor?: string;
siteUrl?: string;
};
/** @description Patches a recurring rule; absent fields are kept. locationId set to the empty string clears the location. When applyToFuture is true and time or location changed, already-materialized future sessions move to the new start time (keeping their local date) and location, and their live bookings follow. A dayOfWeek change only steers sessions materialized afterwards. */
UpdateClassScheduleRequest: {
active?: boolean;
applyToFuture?: boolean;
dayOfWeek?: number;
/** @description Location UUID, or empty string to clear */
locationId?: string;
/** @description Tenant-local start time, HH:MM */
startsLocal?: string;
};
UpdateEmailTemplateRequest: {
body?: string;
isEnabled?: boolean;
@@ -2904,6 +2914,46 @@ export interface operations {
};
};
};
updateClassSchedule: {
parameters: {
query?: never;
header?: never;
path: {
scheduleID: string;
};
cookie?: never;
};
requestBody: {
content: {
"application/json": components["schemas"]["UpdateClassScheduleRequest"];
};
};
responses: {
/** @description Updated class schedule */
200: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["ClassSchedule"];
};
};
/** @description Invalid request */
400: {
headers: {
[name: string]: unknown;
};
content?: never;
};
/** @description Class schedule not found */
404: {
headers: {
[name: string]: unknown;
};
content?: never;
};
};
};
listClassSessions: {
parameters: {
query?: never;