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 Case | Command DTO | Ports touched | Emits event |
|---|---|---|---|
BookAppointmentUseCase | BookAppointmentCommand | AppointmentRepository, SlotRepository, EventPublisher, AuditClient | appointment.created |
RescheduleAppointmentUseCase | RescheduleAppointmentCommand | AppointmentRepository, SlotRepository, EventPublisher, AuditClient | appointment.updated |
UpdateAppointmentStatusUseCase | UpdateStatusCommand | AppointmentRepository, EventPublisher, AuditClient | status-specific event |
CancelAppointmentUseCase | CancelAppointmentCommand | AppointmentRepository, SlotRepository, WaitlistRepository, EventPublisher, AuditClient | appointment.cancelled, optionally waitlist.slot-available |
CheckInPatientUseCase | CheckInCommand | AppointmentRepository, EventPublisher, AuditClient | checkin.completed |
CreateScheduleUseCase | CreateScheduleCommand | ScheduleRepository, EventPublisher, AuditClient | schedule.published |
AddScheduleExceptionUseCase | AddExceptionCommand | ScheduleRepository, AuditClient | — |
CreateSlotUseCase | CreateSlotCommand | SlotRepository, ScheduleRepository, EventPublisher | slot.opened |
AddToWaitlistUseCase | AddWaitlistCommand | WaitlistRepository, AuditClient | — |
FulfillWaitlistEntryUseCase | FulfillWaitlistCommand | WaitlistRepository, EventPublisher | — |
BridgePortalAppointmentUseCase | PortalBridgeCommand | AppointmentRepository, EventPublisher | appointment.created (proposed) |
DispatchReminderUseCase | DispatchReminderCommand | ReminderDispatchPort, EventPublisher | appointment.reminder.sent |
2. Queries (read use cases)
| Use Case | Notes |
|---|---|
SearchAvailableSlotsUseCase | Aggregated free slots by providerId + locationId + date range |
GetSlotsByScheduleUseCase | Slots for one schedule with optional status filter |
GetAppointmentByIdUseCase | Single appointment with actor list |
ListPatientAppointmentsUseCase | Appointments for a patient; optional status filter |
GetCalendarViewUseCase | Staff calendar: appointments in [from, to) by facility/provider |
GetScheduleUseCase | Single schedule |
ListSchedulesUseCase | By actorId |
GetWaitlistUseCase | All waitlist entries by status |
PreviewAvailabilityPatternUseCase | Preview 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)
| Port | Description |
|---|---|
AppointmentRepository | CRUD + status machine enforcement for appointments |
SlotRepository | Slot CRUD + atomic markBusy / markFree |
ScheduleRepository | Schedule CRUD + exception management |
WaitlistRepository | CRUD + candidate match query |
EventPublisher | NATS JetStream CloudEvents |
AuditClient | Audit event emission |
ReminderDispatchPort | Async reminder scheduling (e.g., queued timer or cron) |
PatientCachePort | Local read-through cache of patient demographics from registration events |
5. Outbox / Patterns
| Pattern | Details |
|---|---|
| Outbox | All events written to outbox table in same transaction; relay publishes to NATS |
| Optimistic lock | Appointment + slot updates require version match |
| Portal bridge | Consume portal.appointment.requested via NATS inbox; create proposed appointment |
| Reminder dispatch | Async via cron-triggered DispatchReminderUseCase; retry on failure |
| Waitlist auto-fill | Triggered synchronously within CancelAppointmentUseCase — publishes event only; does not auto-book |
6. Error Handling
| Error code | HTTP | When |
|---|---|---|
SLOT_NOT_AVAILABLE | 409 | Slot is not free at booking time |
DOUBLE_BOOKING_DETECTED | 409 | Resource overlap and allowDoubleBooking not permitted |
DOUBLE_BOOKING_OVERRIDE_DENIED | 403 | allowDoubleBooking=true but caller lacks permission |
NEW_SLOT_NOT_AVAILABLE | 409 | Reschedule target slot not free |
OPTIMISTIC_LOCK_CONFLICT | 409 | version mismatch |
INVALID_STATUS_TRANSITION | 409 | Transition not in allowed graph |
APPOINTMENT_NOT_FOUND | 404 | Appointment missing or cross-tenant |
SCHEDULE_NOT_FOUND | 404 | Schedule missing |
SLOT_NOT_FOUND | 404 | Slot missing |
PATIENT_ID_CLAIM_REQUIRED | 400 | Self-book endpoint called without patient JWT claim |