mirror of
https://github.com/Dvorinka/Bookra.git
synced 2026-10-28 15:51:15 +00:00
feat(classes): weekly recurring schedules with lazy session materialization
class_schedules rules generate concrete session rows for a rolling 28-day horizon — no cron; materialize runs idempotently on dashboard and public reads via a partial unique index on (schedule_id, starts_at). Rule delete stops future sessions; existing sessions keep bookings and overrides. Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
1 parent
7b9080eb1c
commit
ad60167a31
15 files changed
+1029
-7
No files matched your search
@@ -396,6 +396,42 @@ export interface paths {
|
||||
patch?: never;
|
||||
trace?: never;
|
||||
};
|
||||
"/v1/catalog/class-schedules": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path?: never;
|
||||
cookie?: never;
|
||||
};
|
||||
/**
|
||||
* Weekly recurring rules for class sessions
|
||||
* @description Each rule materializes concrete class_sessions for a rolling 28-day horizon in the tenant timezone. Sessions are written idempotently on read (list class sessions or public availability), so no background job is needed. Deleting a rule stops future materialization; sessions already created stay in place and keep their bookings.
|
||||
*/
|
||||
get: operations["listClassSchedules"];
|
||||
put?: never;
|
||||
post: operations["createClassSchedule"];
|
||||
delete?: never;
|
||||
options?: never;
|
||||
head?: never;
|
||||
patch?: never;
|
||||
trace?: never;
|
||||
};
|
||||
"/v1/catalog/class-schedules/{scheduleID}": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path?: never;
|
||||
cookie?: never;
|
||||
};
|
||||
get?: never;
|
||||
put?: never;
|
||||
post?: never;
|
||||
delete: operations["deleteClassSchedule"];
|
||||
options?: never;
|
||||
head?: never;
|
||||
patch?: never;
|
||||
trace?: never;
|
||||
};
|
||||
"/v1/catalog/class-sessions": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
@@ -1315,6 +1351,23 @@ export interface components {
|
||||
*/
|
||||
planCode: "starter" | "pro" | "business";
|
||||
};
|
||||
ClassSchedule: {
|
||||
active: boolean;
|
||||
/** @description 0=Sunday ... 6=Saturday */
|
||||
dayOfWeek: number;
|
||||
/** Format: uuid */
|
||||
id: string;
|
||||
/** Format: uuid */
|
||||
locationId?: string;
|
||||
locationName?: string;
|
||||
/** @description Tenant-local start time, HH:MM:SS */
|
||||
startsLocal: string;
|
||||
/** Format: uuid */
|
||||
templateId: string;
|
||||
templateTitle: string;
|
||||
/** Format: uuid */
|
||||
tenantId: string;
|
||||
};
|
||||
ClassSession: {
|
||||
bookedCount: number;
|
||||
capacity: number;
|
||||
@@ -1325,6 +1378,11 @@ export interface components {
|
||||
/** Format: uuid */
|
||||
locationId?: string;
|
||||
locationName?: string;
|
||||
/**
|
||||
* Format: uuid
|
||||
* @description Recurring rule that generated this session; absent for manual sessions
|
||||
*/
|
||||
scheduleId?: string;
|
||||
/** Format: date-time */
|
||||
startsAt: string;
|
||||
/** Format: uuid */
|
||||
@@ -1375,6 +1433,16 @@ export interface components {
|
||||
/** @enum {string} */
|
||||
status: "confirmed" | "waitlisted";
|
||||
};
|
||||
CreateClassScheduleRequest: {
|
||||
/** @description 0=Sunday ... 6=Saturday */
|
||||
dayOfWeek: number;
|
||||
/** Format: uuid */
|
||||
locationId?: string;
|
||||
/** @description Tenant-local start time, HH:MM */
|
||||
startsLocal: string;
|
||||
/** Format: uuid */
|
||||
templateId: string;
|
||||
};
|
||||
CreateClassSessionRequest: {
|
||||
capacity?: number;
|
||||
/** Format: uuid */
|
||||
@@ -2677,6 +2745,91 @@ export interface operations {
|
||||
};
|
||||
};
|
||||
};
|
||||
listClassSchedules: {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path?: never;
|
||||
cookie?: never;
|
||||
};
|
||||
requestBody?: never;
|
||||
responses: {
|
||||
/** @description Recurring class schedules */
|
||||
200: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["ClassSchedule"][];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
createClassSchedule: {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path?: never;
|
||||
cookie?: never;
|
||||
};
|
||||
requestBody: {
|
||||
content: {
|
||||
"application/json": components["schemas"]["CreateClassScheduleRequest"];
|
||||
};
|
||||
};
|
||||
responses: {
|
||||
/** @description Class schedule created (sessions materialized immediately) */
|
||||
201: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["ClassSchedule"];
|
||||
};
|
||||
};
|
||||
/** @description Invalid request */
|
||||
400: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content?: never;
|
||||
};
|
||||
/** @description Template or location not found */
|
||||
404: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content?: never;
|
||||
};
|
||||
};
|
||||
};
|
||||
deleteClassSchedule: {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path: {
|
||||
scheduleID: string;
|
||||
};
|
||||
cookie?: never;
|
||||
};
|
||||
requestBody?: never;
|
||||
responses: {
|
||||
/** @description Class schedule deleted */
|
||||
200: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content?: never;
|
||||
};
|
||||
/** @description Class schedule not found */
|
||||
404: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content?: never;
|
||||
};
|
||||
};
|
||||
};
|
||||
listClassSessions: {
|
||||
parameters: {
|
||||
query?: never;
|
||||
|
||||
Reference in new issue
Block a user