Skip to main content

Scheduling Service — Application Logic

Status: populated Owner: TBD Last updated: 2026-04-17 Companion: Service Template · 03 platform-services · 02 DDD

1. Commands (write use cases)

Use CaseCommand DTOPorts touchedEmits event
BookAppointmentUseCaseBookAppointmentCommandAppointmentRepository, SlotRepository, EventPublisher, AuditClientappointment.created
RescheduleAppointmentUseCaseRescheduleAppointmentCommandAppointmentRepository, SlotRepository, EventPublisher, AuditClientappointment.updated
UpdateAppointmentStatusUseCaseUpdateStatusCommandAppointmentRepository, EventPublisher, AuditClientstatus-specific event
CancelAppointmentUseCaseCancelAppointmentCommandAppointmentRepository, SlotRepository, WaitlistRepository, EventPublisher, AuditClientappointment.cancelled, optionally waitlist.slot-available
CheckInPatientUseCaseCheckInCommandAppointmentRepository, EventPublisher, AuditClientcheckin.completed
CreateScheduleUseCaseCreateScheduleCommandScheduleRepository, EventPublisher, AuditClientschedule.published
AddScheduleExceptionUseCaseAddExceptionCommandScheduleRepository, AuditClient
CreateSlotUseCaseCreateSlotCommandSlotRepository, ScheduleRepository, EventPublisherslot.opened
AddToWaitlistUseCaseAddWaitlistCommandWaitlistRepository, AuditClient
FulfillWaitlistEntryUseCaseFulfillWaitlistCommandWaitlistRepository, EventPublisher
BridgePortalAppointmentUseCasePortalBridgeCommandAppointmentRepository, EventPublisherappointment.created (proposed)
DispatchReminderUseCaseDispatchReminderCommandReminderDispatchPort, EventPublisherappointment.reminder.sent

2. Queries (read use cases)

Use CaseNotes
SearchAvailableSlotsUseCaseAggregated free slots by providerId + locationId + date range
GetSlotsByScheduleUseCaseSlots for one schedule with optional status filter
GetAppointmentByIdUseCaseSingle appointment with actor list
ListPatientAppointmentsUseCaseAppointments for a patient; optional status filter
GetCalendarViewUseCaseStaff calendar: appointments in [from, to) by facility/provider
GetScheduleUseCaseSingle schedule
ListSchedulesUseCaseBy actorId
GetWaitlistUseCaseAll waitlist entries by status
PreviewAvailabilityPatternUseCasePreview expanded windows from pattern template

3. Orchestration Flows

3.1 Appointment Booking Flow

3.2 Cancellation + Waitlist Auto-fill

3.3 Portal Bridge Flow

4. Ports (Interfaces)

PortDescription
AppointmentRepositoryCRUD + status machine enforcement for appointments
SlotRepositorySlot CRUD + atomic markBusy / markFree
ScheduleRepositorySchedule CRUD + exception management
WaitlistRepositoryCRUD + candidate match query
EventPublisherNATS JetStream CloudEvents
AuditClientAudit event emission
ReminderDispatchPortAsync reminder scheduling (e.g., queued timer or cron)
PatientCachePortLocal read-through cache of patient demographics from registration events

5. Outbox / Patterns

PatternDetails
OutboxAll events written to outbox table in same transaction; relay publishes to NATS
Optimistic lockAppointment + slot updates require version match
Portal bridgeConsume portal.appointment.requested via NATS inbox; create proposed appointment
Reminder dispatchAsync via cron-triggered DispatchReminderUseCase; retry on failure
Waitlist auto-fillTriggered synchronously within CancelAppointmentUseCase — publishes event only; does not auto-book

6. Error Handling

Error codeHTTPWhen
SLOT_NOT_AVAILABLE409Slot is not free at booking time
DOUBLE_BOOKING_DETECTED409Resource overlap and allowDoubleBooking not permitted
DOUBLE_BOOKING_OVERRIDE_DENIED403allowDoubleBooking=true but caller lacks permission
NEW_SLOT_NOT_AVAILABLE409Reschedule target slot not free
OPTIMISTIC_LOCK_CONFLICT409version mismatch
INVALID_STATUS_TRANSITION409Transition not in allowed graph
APPOINTMENT_NOT_FOUND404Appointment missing or cross-tenant
SCHEDULE_NOT_FOUND404Schedule missing
SLOT_NOT_FOUND404Slot missing
PATIENT_ID_CLAIM_REQUIRED400Self-book endpoint called without patient JWT claim