Skip to content

Calendars & SLA Partial

Business calendars model where and when an organization actually works — named locations, their timezones, weekly business hours, and holidays — so that downstream work can be scheduled against real availability rather than raw wall-clock time. The companion SLA engine walks those business hours (skipping closed days, holidays and after-hours gaps across one or more locations) to turn a received timestamp plus an SLA budget (business days / business minutes) into a concrete due date.

Two capabilities are seeded for this surface in the engine registry (CapabilitySeed.java):

  • CALENDARBusiness Calendars — icon CalendarDays, route /calendars, tier STANDARD, status ACTIVE.
  • SLASLA Management — icon Timer, route /sla, tier PREMIUM, status ACTIVE.

Partial status

The Core UI feature is fully built — a dashboard, a six-tab detail workbench, a complete typed API client, and reference data for timezones / countries / regions / cities. The Core Engine side, however, only registers the two capabilities in CapabilitySeed; a search of luke-core-engine/src/main/java finds no calendar, location, business-hours, holiday, SLA or availability controller/service/entity. Every REST call the UI makes (/api/business-calendars/**, /api/process-calendars, /api/sla/calculate) is therefore against a backend that is not yet implemented. The endpoints below document the contract the UI expects, not code that ships today.

Components at a glance

Data model

Shapes are declared as TypeScript interfaces in luke-core-ui/src/features/calendars/api/endpoints.ts. They describe the JSON the UI sends and expects; the matching engine tables are not yet defined.

EntityKey fieldsNotes
BusinessCalendarid, calendarCode, name, description, active, createdAt, updatedAtTop-level named calendar, addressed everywhere by calendarCode.
CalendarLocationid, calendarId, locationCode, name, timezone, country, region, city, enabled, sortOrderA working site within a calendar; owns its own hours + holidays. timezone drives all conversions.
BusinessHoursid, locationId, dayOfWeek (1=Mon…7=Sun), startTime, endTime, label, partial, capacityPercent, partialReason, active, effectiveFrom, effectiveUntilWeekly recurring open window per location; partial + capacityPercent model reduced-capacity shifts.
Holidayid, locationId, date, name, type, openFrom, openUntil, closed, description, recurringPer-location date override; closed=true blocks the whole day, otherwise openFrom/openUntil narrow it.
ProcessCalendarAssociationid, processDefinitionKey, calendarCode, slaBusinessDays, slaBusinessMinutes, priority, activeBinds a Camunda process definition to a calendar + default SLA budget + priority (LOW/MEDIUM/HIGH/CRITICAL).
SlaResult (response)receivedDateTimeUtc, dueDateTimeUtc, dueDateTimeLocal, totalBusinessMinutesConsumed, calendarCode, locationsUsedOutput of /sla/calculate.
AvailabilityWindow (response)start, end, durationMinutes, activeLocationsContiguous open interval produced by /availability.

SLA calculation flow

The SlaTab collects a received datetime, its timezone, and an SLA budget, then calls calculateSla(...). The engine is expected to normalize the received time to UTC, then consume the budget by stepping through each location's business hours while skipping closed days, holidays and after-hours gaps, until the budget reaches zero — that landing point is the due date.

ConcernFunction / endpointWhere
Build the requestslaMutcalculateSla({ calendarCode, receivedDateTime, receivedTimezone, sla: { businessDays, businessMinutes } })CalendarDetailPage.tsx
Default the received timezoneuseEffect seeds slaForm.receivedTimezone from the first location's timezoneCalendarDetailPage.tsx
TransportPOST /api/sla/calculateendpoints.ts
Show the resultSlaTab renders receivedDateTimeUtc, dueDateTimeUtc, dueDateTimeLocal, totalBusinessMinutesConsumed, locationsUsedCalendarDetailPage.tsx
Bind a process defaultcreateProcessAssociation({ processDefinitionKey, calendarCode, slaBusinessDays, slaBusinessMinutes, priority })endpoints.ts

Availability & isOpen

Two lighter-weight reads complement the full SLA walk:

  • Availability windowsgetAvailability(calCode, from, to)GET /business-calendars/{code}/availability?from&to returns an ordered list of AvailabilityWindows (each start/end/durationMinutes plus the activeLocations open during it) for a date range. The AvailabilityTab defaults the range to the current Mon–Fri (getMonday/getFriday) and renders each window as a row; the query only fires while the Availability tab is active.
  • Currently openisCalendarOpen(calCode)GET /business-calendars/{code}/is-open returns { open, openLocations }. CalendarDetailPage runs this on an openQuery with refetchInterval: pollWithBackoff(60_000) and paints a live "Currently Open / Currently Closed" status bar, listing the open location codes.

Component reference

ComponentTypeResponsibilityKey methods / hooks
CalendarDashboardPagePageLanding grid: KPI cards + per-calendar cards, create/delete calendarsgetCalendars, createCalendar, deleteCalendar, KpiCard, CalendarCard
CalendarDetailPagePageOrchestrates the six-tab workbench, all queries + mutations, breadcrumb, detail panel, live status barcalendarQuery, locationsQuery, openQuery, hoursQuery, holidaysQuery, availabilityQuery, processQuery; handleTabChange, autoSelectFirst
LocationsTabSub-componentList/add/delete locations; select the "active" location that drives hours + holidayscreateLocationMut, deleteLocationMut; country→city cascade via CITIES[form.country]
BusinessHoursTabSub-componentPer-location weekly hours; add/delete; partial-day + capacitycreateHoursMut, deleteHoursMut; DAY_NAMES mapping
HolidaysTabSub-componentPer-location holidays; search, add, delete, auto-import by yeardeleteHolidayMut, autoImportMut; filteredHolidays memo
SlaTabSub-componentSLA calculator form + result panelslaMutcalculateSla
AvailabilityTabSub-componentDate-range availability windows tableavailabilityQuery, getMonday/getFriday
Processes tab (inline)Inline blockAssociate/unassociate process definitions with SLA defaults + prioritycreateProcessMut, deleteProcessMut; filters getProcessAssociations by calendarCode
endpoints.tsAPI clientTyped axios client; injects Basic auth + X-Tenant-Id; all CRUD + SLA/availability callscalApi instance + request interceptor
data/locations.tsReference dataTIMEZONES, COUNTRIES, REGIONS, CITIES option lists for the location form
CapabilitySeedEngine seedRegisters the CALENDAR (STANDARD) and SLA (PREMIUM) capabilitiesseed(new Capability(...))

Endpoints

All calls carry HTTP Basic auth (username/password from authStore) and an X-Tenant-Id header from tenantStore, injected by the calApi request interceptor. Base URL is ${VITE_API_BASE_URL}/api (or /api).

AreaMethod + pathClient function
CalendarsGET /business-calendars · GET/POST/PUT/DELETE /business-calendars/{code}getCalendars, getCalendar, createCalendar, updateCalendar, deleteCalendar
LocationsGET/POST /business-calendars/{cal}/locations · PUT/DELETE …/locations/{loc}getLocations, createLocation, updateLocation, deleteLocation
Business hoursGET/POST …/locations/{loc}/business-hours · DELETE …/business-hours/{id}getBusinessHours, createBusinessHours, deleteBusinessHoursById
HolidaysGET/POST …/locations/{loc}/holidays · POST …/holidays/auto-import?year= · GET …/holidays/preview?countryCode=&year= · GET …/holidays/available-countries · DELETE …/holidays/{id}getHolidays, createHoliday, autoImportHolidays, previewHolidays, getAvailableCountries, deleteHolidayById
Process associationsGET/POST /process-calendars · DELETE /process-calendars/{key}getProcessAssociations, createProcessAssociation, deleteProcessAssociation
SLAPOST /sla/calculatecalculateSla
AvailabilityGET /business-calendars/{code}/availability?from&togetAvailability
Is-openGET /business-calendars/{code}/is-openisCalendarOpen

Status & gaps

  • UI: complete and typed — dashboard, six-tab detail workbench, full API client, reference data.
  • Engine: only capability registration exists. No calendar/location/business-hours/holiday/SLA/availability controller, service, entity, or migration is present in luke-core-engine. Until those ship, the UI's reads and writes have nothing to talk to.
  • Add-holiday form: the manual "Create" button in HolidaysTab has no onClick wired to createHoliday, so only auto-import currently persists holidays.

See the Completeness Scorecard for where this sits against the rest of the fleet, and the related Core UI, Core Engine and Capabilities pages.

Lukeflow Manual · documentation snapshot July 2026