# CreateShifts

## Permission Scope

shift

## Overview

createShifts bulk-creates many `Shift` records in a single all-or-nothing transaction. It shares its per-shift validation (segment resolution from a `ShiftPattern`, segment gap/break checks, shiftType/segment-count consistency) with `createShift` via the same internal validation functions, so the two commands can never drift on what makes a shift valid. It exists for generation logic (e.g. a periodic-rotation shift schedule generator) that must materialize hundreds or thousands of Shifts for a date range without issuing one command call per row.

## Business Rules

- Accepts an array of per-shift inputs, each with the same shape as `createShift`'s input
- The input array must be non-empty and must not exceed the batch size limit (5,000 entries)
- Validation runs for **every** entry before any row is inserted; if **any** entry fails validation, the whole batch is rejected and **nothing** is inserted (all-or-nothing)
- Each entry is validated with exactly the same rules as `createShift` (segment resolution from `shiftPatternId` when segments are omitted, segment gap/break checks, shiftType/segment-count consistency)
- All inserted Shifts are created with no status of its own, identical to `createShift`
- Referenced `shiftPatternId` values are batch-loaded once (not once per entry) to keep the transaction efficient at scale

## Process Flow

```mermaid
flowchart TD
    A[Receive array of shift inputs] --> B{Array non-empty and<br/>within batch size limit?}
    B -->|No| BX[Return error: BULK_INPUT_EMPTY / BULK_INPUT_TOO_LARGE]
    B -->|Yes| C[Batch-load referenced ShiftPatterns]
    C --> D[Validate every entry:<br/>same rules as createShift]
    D -->|Any entry invalid| DX[Return error from the first<br/>invalid entry; insert nothing]
    D -->|All valid| E[Insert all Shifts in one transaction]
    E --> F[Return created shifts]
```

## External Dependencies

- [shiftSchedule::ShiftPattern](../model/ShiftPattern.md) model - batch-loaded to resolve segments for entries that reference a pattern
- Shares validation logic with [CreateShift](./CreateShift.md) (same module-internal functions, not duplicated)

## Error Scenarios

- **MISSING_REQUIRED_FIELD**: a required field is missing
- **SHIFT_SCHEDULE_NOT_FOUND**: no ShiftSchedule exists for the given id
- **SHIFT_DATE_OUT_OF_PERIOD**: the shift's date falls outside its ShiftSchedule's period
- **BULK_INPUT_EMPTY**: the input array is empty
- **BULK_INPUT_TOO_LARGE**: the input array exceeds the batch size limit
- **SHIFT_PATTERN_NOT_FOUND**: no ShiftPattern exists for the given id
- **SEGMENT_REQUIRED**: no segments were provided, or the change would leave zero segments
- **SEGMENT_GAP_INVALID**: two consecutive segments do not leave a positive gap
- **SEGMENT_BREAK_INVALID**: breakMinutes is negative or not strictly less than the segment's gross span
- **SHIFT_TYPE_SEGMENT_MISMATCH**: segment count is inconsistent with shiftType

## Test Cases

- creates multiple Shifts in one call, all with status PLANNED
- resolves segments from a shared ShiftPattern for multiple entries without re-querying it per entry
- rejects the entire batch and inserts nothing when one entry among many fails segment validation
- throws BULK_INPUT_EMPTY when the shifts array is empty
- throws BULK_INPUT_TOO_LARGE when the shifts array exceeds the batch size limit
- throws MISSING_REQUIRED_FIELD when the shifts array itself is missing
