Objective
- Keep company holidays as the default closure for normal weekly availability.
- Allow temporary slots (manual / one-off or recurring extra openings) on a holiday date to supersede that closure so selected inspectors can still be booked.
- Give schedulers a reliable mixed-holiday workflow without inverted per-inspector block workarounds.
Background
- Product feedback describes two awkward options today: company Holidays (blocks everyone) or per-inspector blocks/vacations (inverted model when only some people work).
- Current behavior: holidays are company-wide (
holidaymodel has_companyIdonly). Scheduling treats holiday dates as closed for all inspectors: calendarAvailabilityIndex.isSlotAvailablereturnsfalseon any holiday date.buildSlotsByDateForRangemarks projected slotsavailable: falseon holidays.- Online/internal slot discovery in
schedule.tsskips holiday dates entirely when building candidate days. - Temporary slots today do not help: manual historic slots (
slotOrigin: 'manual'inhistoricSlots) still pass through the same holiday gate and are blocked. Code review confirmed temporary slots do not currently override holiday closure. - Desired direction (product): only temporary slots — not standard recurring weekly inspection slots — should override a company holiday for the inspector(s) who have those openings.
Product Decisions
Locked
- Override mechanism — Temporary slots supersede company holiday closure for booking availability.
- Scope of override — Applies to manual / temporary openings only (
slotOrigin: 'manual'historic slots created via inspector temporary-slot UI). Standard weekly template slots remain blocked on holidays. - Default holiday behavior unchanged — Company holidays still close normal availability by default; override is explicit via temporary slot creation.
- Problem type — Feature enhancement to scheduling/holiday interaction, not a change to how holidays are stored at company level (unless engineering requires a small schema flag).
Open (Remaining product clarifying decisions)
- Online vs internal — Should holiday-overriding temporary slots respect
offeredOnline(online scheduler only whentrue), or should internal scheduler always see them regardless? - Answer: should be visible both online and internal when a temporary slot is added to a holiday date
- Holiday date discovery — When temporary slots exist on a holiday, should the scheduler include that holiday date in date search (today it is skipped entirely), or only surface slots when staff navigate to that date manually?
- Answer: Automatically include holiday date only for open temporary slots
- Recurring temporary series — If a temporary slot is part of a recurring series (
temporarySeriesId/temporarySeriesRecurrence), should every occurrence on a holiday override closure, or only explicitly one-off temps? - Answer: all occurances.
- Inspector scope — Confirm override is per inspector who has the temporary slot only; other inspectors without a temp slot on that holiday remain closed.
- Answer: Correct
- UI affordance — Should the temporary-slot UI warn or label that a slot will override a company holiday, so schedulers understand why booking is possible?
- Answer: Yes.
- Original transcript breadth — The earlier discussion also mentioned general “inspector available on holiday without a temp slot.” Is that out of scope now that the chosen path is temporary-slot override only?
- Answer: Out of scope. Let's focus only on Temporary slots.
Scope
Backend — holiday gate (primary change)
attik-backend/src/util/functions/slots/calendarAvailabilityIndex.ts—isSlotAvailablecurrently returnsfalsefor all slots onholidayDates; needs an exception path for manual/temporary historic slots.attik-backend/src/util/functions/slots/buildSlotsByDateForRange.ts— historic and projected day logic setsavailable: falsewhendayIsHoliday; temporary manual slots loaded here must be able to remain available.attik-backend/src/util/functions/slots/weeklySlotProjection.ts—projectFutureDayBucketreturns empty holiday buckets; standard weekly projection should stay closed; manual historic slots handled separately.attik-backend/src/util/functions/slots/calcAvailableSlots.ts— maps slots throughcalendar.isSlotAvailable; must reflect override behavior.attik-backend/src/routes/schedule.ts—findAvailableSlotsskips holiday dates when buildingdates; must include holiday dates when qualifying temporary manual slots exist (or alternate discovery path).attik-backend/src/util/functions/slots/historicSlotsForScheduling.ts— loads manual historic slots for schedule dates;offeredOnlinefiltering for client-facing scheduler.
Backend — data model
attik-backend/src/models/holidaySchema.ts— company-wide holiday records (likely unchanged).attik-backend/src/models/slotsSchema.ts—HistoricSlotswithslotOrigin: 'manual',temporarySeriesId,temporarySeriesRecurrence,offeredOnline.attik-backend/src/routes/slot.ts— creates/updates manual and temporary slot series.
Frontend
attik-frontend/src/app/tools/settings/inspectors/[id]/TemporaryInspectorSlots.tsx— UI for one-off/recurring temporary openings.attik-frontend/src/app/tools/settings/inspectors/[id]/EditTemporarySlotModal.tsx— create/edit includingofferedOnlineon recurring edits.attik-frontend/src/app/tools/settings/holidays/page.tsx— company holiday management (calendar-adminpermission); unchanged authoring, but behavior downstream changes.
Out of scope (unless product expands)
- Opening standard recurring weekly grid slots on holidays without creating a temporary slot.
- Per-inspector holiday opt-out lists separate from temporary slots (original transcript option).
- Changing payroll/forecast holiday handling (
payrollContext.ts,getMonthlyForecastRange.ts) unless booking availability changes require it.
References
attik-backend/src/util/functions/slots/calendarAvailabilityIndex.tsattik-backend/src/routes/schedule.tsattik-backend/src/models/slotsSchema.tsattik-frontend/src/app/tools/settings/inspectors/[id]/TemporaryInspectorSlots.tsx