Booking Engine

Architecture: Six focused services with the BookingService/SchedulingService overlap resolved by giving SchedulingService exactly one job, the transactional double-booking guard , while BookingService owns the create/reschedule/cancel workflow around it.

59 unit tests, 24 integration tests
This commit is contained in:
Stefan Lazic committed 2026-08-02 18:36:39 +01:00
1 parent 090646fdfd
commit 8b63cc66a9
28 files changed
+4853 -15

No files matched your search

+60
View File
@@ -0,0 +1,60 @@
import { z } from "zod";
/**
* Input shapes for the booking Server Actions. Kept separate from the
* scheduling services' own TS types deliberately — these describe what
* crosses the client→server boundary as JSON (dates as ISO strings, no
* Date objects), the services describe the domain.
*/
export const getAvailableServicesSchema = z.object({
businessId: z.string(),
categoryId: z.string().optional(),
staffId: z.string().optional(),
});
export const getAvailableBarbersSchema = z.object({
businessId: z.string(),
serviceIds: z.array(z.string()).min(1),
});
export const getAvailableDatesSchema = z.object({
businessId: z.string(),
serviceIds: z.array(z.string()).min(1),
staffId: z.string().optional(),
fromDate: z.string(),
toDate: z.string(),
});
export const getAvailableTimeSlotsSchema = z.object({
businessId: z.string(),
serviceIds: z.array(z.string()).min(1),
staffId: z.string().optional(),
date: z.string(),
});
export const createBookingSchema = z.object({
businessId: z.string(),
customerId: z.string(),
serviceIds: z.array(z.string()).min(1),
staffId: z.string().optional(),
startAt: z.iso.datetime(),
notes: z.string().optional(),
});
export const rescheduleBookingSchema = z.object({
appointmentId: z.string(),
staffId: z.string().optional(),
startAt: z.iso.datetime(),
});
export const cancelBookingSchema = z.object({
appointmentId: z.string(),
cancelledByUserId: z.string(),
reason: z.string().optional(),
});
export const updateBookingNotesSchema = z.object({
appointmentId: z.string(),
notes: z.string().max(2000),
});