Builders are the structural assembly layer of Shiftly’s domain. Each builder receives raw inputs — a shift, a day’s accumulated shifts, or a month’s calendar metadata — and produces a typed data structure suitable for reducers or UI consumption. Builders are deliberately free of business logic: they delegate segment classification to resolvers and pay computation to calculators, keeping their own responsibility narrowly scoped to orchestrating that delegation and combining the results into the correct output shape.Documentation Index
Fetch the complete documentation index at: https://mintlify.com/dmaman86/shiftly/llms.txt
Use this file to discover all available pages before exploring further.
The Builder Interface
Every builder in the domain implements the same single-method contract from core-behaviors.ts:
Builders Overview
ShiftSegmentBuilder
Splits a shift into labeled time segments by delegating to
ShiftSegmentResolver, handling cross-midnight shifts and DST offsets.ShiftMapBuilder
Combines segment labels with per-shift regular, extra, and special calculators to produce a complete
ShiftPayMap.DayPayMapBuilder
Aggregates multiple
ShiftPayMaps for a single day and computes daily per-diem and meal allowance.WorkDaysForMonthBuilder
Iterates over all days in a month, classifies each using holiday event data, and sets cross-day continuation flags.
ShiftSegmentBuilder
ShiftSegmentBuilder is the first builder invoked for any shift. It takes a Shift and its WorkDayMeta context and returns an ordered list of LabeledSegmentRange values — time windows with a pay rate key attached to each window.
Signature
Type Reference
How It Works
- Validates the shift — calls
shiftService.isValidShiftDuration(shift); returns[]for zero-duration or inverted shifts. - Splits on midnight — computes end minutes relative to the start date using
ShiftService.getMinutesFromMidnight. If the shift extends beyond 30:00 (06:00 the next day), it creates asecondPartpoint. - Resolves each part — delegates each
PointtoShiftSegmentResolver.resolve({ point, meta }), which maps the point against the correct time-window map forRegular,SpecialPartialStart, orSpecialFulldays. - Handles the second day — the second part uses a synthetic
metaNextDaywheretypeDayis set toSpecialFullifmeta.crossDayContinuationis true, otherwiseRegular. All resulting segment points are shifted by +1440 minutes so they sit in a continuous coordinate space. - Merges and sorts — combines both part arrays and sorts by
point.start.
DST Awareness
The special-day start time (Friday/eve-of-holiday) is either 17:00 or 18:00 depending on whether the system clock’s UTC offset is −3h (Israel Summer Time) or −2h (Winter Time).ShiftSegmentResolver reads new Date(date).getTimezoneOffset() at resolve time, so DST transitions are handled correctly without any manual configuration.
DefaultShiftMapBuilder
DefaultShiftMapBuilder takes a validated shift and produces a ShiftPayMap — the complete pay breakdown for one shift including regular brackets, evening/night bonuses, special-day hours, and per-diem metadata.
Signature
Output Type
Construction Logic
- Calls
segmentBuilder.build({ shift, meta })to getLabeledSegmentRange[]. - Computes
totalHoursviashiftService.getDurationShift(shift). - Passes segments to
extraCalculator.calculate(labeledSegments)→ExtraBreakdown. - Passes segments to
specialCalculator.calculate(labeledSegments)→SpecialBreakdown. - Subtracts special hours from
totalHoursto getregularHours(Shabbat hours are not double-counted in the regular bracket). - Passes
{ totalHours: regularHours, standardHours, meta }toregularCalculator.calculate(...)→RegularBreakdown. - Constructs and returns the
ShiftPayMap.
DefaultDayPayMapBuilder
DefaultDayPayMapBuilder aggregates all ShiftPayMaps recorded for a single calendar day into a unified WorkDayMap. It also handles sick and vacation days, computes per-diem eligibility, and determines meal allowance.
Signature
Output Type
Construction Logic
- Normal Day
- Sick / Vacation Day
- Accumulates
extraandspecialbreakdowns across all shifts using theExtraCalculatorandSpecialCalculatorreducers. - Deducts total Shabbat hours (
shabbat150 + shabbat200) fromtotalHoursbefore passing toRegularByDayCalculator. - Calls
calculatePerDiem(perDiemShifts, year, month)— resolves the applicable historical rate viaTimelinePerDiemRateResolverbefore computing. - Classifies meal allowance day info: night hours are the sum of
hours50andshabbat200. A day is considered a “meaningful night” shift only if night hours ≥ 4. - Calls
MealAllowanceResolver.resolve({ day, rates })to getMealAllowance. - Sets
hours100Sickandhours100Vacationto zero-hour segments; setsextra100Shabbatto the total Shabbat hours.
DefaultWorkDaysForMonthBuilder
DefaultWorkDaysForMonthBuilder iterates over every day in a given year/month, classifies it using holiday event data fetched from Hebcal, and constructs a WorkDayInfo[] array that forms the calendar skeleton for the month.
Signature
Output Element Type
Construction Logic
For each calendar day in the month:- Looks up
eventMap[formattedDate]to get the array of Hebcal event titles for that date. - Calls
holidayResolver.resolve({ weekday, eventTitles })to determineWorkDayType:- Saturday or a paid holiday →
SpecialFull - Friday or an eve-of-holiday event →
SpecialPartialStart - Otherwise →
Regular
- Saturday or a paid holiday →
- Resolves the
holidayKeyfrom the event titles using a prefix-match againsthebrewHolidayNames. - Sets
crossDayContinuationon dayn-1totruewhen daynisSpecialFull— this tells the shift builder that a shift ending the following morning is still in Shabbat/holiday time. - After all days are processed, checks the first day of the next month to correctly set the last day’s
crossDayContinuationflag.
The
crossDayContinuation flag is set on the previous day, not the special day itself. A Friday shift that ends at 02:00 Saturday morning must be split: the Saturday portion carries SpecialFull rates. ShiftSegmentBuilder reads this flag from the current day’s WorkDayMeta to construct the correct metaNextDay.