Scheduling Context¶
The Scheduling context manages staff shift planning, assignment, time tracking, shift swaps, and coverage. It provides the foundation for labor reporting in the Reporting context.
Purpose¶
Every restaurant location needs to schedule staff across roles (host, server, bartender, chef, cook, dishwasher, manager). The Scheduling context handles the lifecycle of each shift from creation through assignment, clock-in/out, and potential swaps or cancellations.
Types¶
type ShiftId is Id(Scheduling.Shift) with {
briefly "Shift identifier"
described by "Unique identifier for a shift."
}
type EmployeeId is UUID with {
briefly "Employee identifier"
described by "Unique identifier for an employee."
}
type ShiftStatus is any of {
ScheduledStatus,
AssignedStatus,
InProgressStatus,
ShiftCompletedStatus,
ShiftCancelledStatus
} with {
briefly "Shift status"
described by "Current status of a shift."
}
type ShiftRole is any of {
HostRole,
ServerRole,
BartenderRole,
ChefRole,
CookRole,
DishwasherRole,
ManagerRole
} with {
briefly "Shift role"
described by "The role for this shift."
}
The ShiftRole enumeration maps directly to the personas
interviewed — Host, Server, Bartender, Chef, Cook — plus
Dishwasher and Manager.
Entity: Shift¶
The Shift entity has a 6-command lifecycle:
entity Shift is {
command CreateShift is {
shiftId is ShiftId
shiftDate is Date
shiftStart is TimeStamp
shiftEnd is TimeStamp
shiftRole is ShiftRole
}
command AssignEmployee is {
shiftId is ShiftId
employeeId is EmployeeId
employeeName is String(1, 100)
}
command SwapShift is {
shiftId is ShiftId
originalEmployeeId is EmployeeId
replacementEmployeeId is EmployeeId
replacementName is String(1, 100)
}
command ClockIn is {
shiftId is ShiftId
clockedInAt is TimeStamp
}
command ClockOut is {
shiftId is ShiftId
clockedOutAt is TimeStamp
}
command CancelShift is {
shiftId is ShiftId
shiftCancelReason is String(1, 500)
}
// Events: ShiftCreated, EmployeeAssigned, ShiftSwapped,
// ClockedIn, ClockedOut, ShiftCancelled
state ActiveShift of Shift.ShiftStateData
handler ShiftHandler is {
on command CreateShift {
morph entity Scheduling.Shift to state
Scheduling.Shift.ActiveShift
with command CreateShift
tell event ShiftCreated to
entity Scheduling.Shift
}
on command AssignEmployee {
tell event EmployeeAssigned to
entity Scheduling.Shift
}
on command SwapShift {
tell event ShiftSwapped to
entity Scheduling.Shift
}
on command ClockIn {
tell event ClockedIn to
entity Scheduling.Shift
}
on command ClockOut {
tell event ClockedOut to
entity Scheduling.Shift
}
on command CancelShift {
tell event ShiftCancelled to
entity Scheduling.Shift
}
}
}
The lifecycle: Create → Assign Employee → Clock In → Clock Out (with optional Swap or Cancel at any point).
The SwapShift command tracks both the original and replacement
employee, maintaining an audit trail of who was originally
assigned. This matters for labor compliance and reporting.
Repository¶
repository ShiftRepository is {
schema ShiftData is relational
of shifts as Shift
index on field Shift.shiftId
index on field Shift.shiftDate
index on field Shift.employeeId
}
The index on shiftDate enables schedule-by-day views. The
index on employeeId supports employee-centric schedule views
("What are my shifts this week?").
Design Decisions¶
Why no projectors? The Scheduling context is focused on
write operations — creating and managing shifts. The
schedule view could be a projector, but the
Reporting context already handles the read-model
side with the LaborReport projector that listens to
scheduling events.
Foundation for labor reporting: The ClockedIn and
ClockedOut events flow to the Reporting context's
LaborReport projector, which calculates hours worked,
completed shifts, and average shift duration. Scheduling
doesn't need to know about reports — it just emits events.