# ConfirmShiftSchedule

## Permission Scope

shiftSchedule

## Overview

confirmShiftSchedule commits a whole shift schedule period to workers in one act (公開) — the operation that previously required calling `publishShift` once per slot. Confirming freezes the period's shift definitions; staffing stays changeable afterwards.

## Business Rules

- Only a `DRAFT` shift schedule may be confirmed; an already-`CONFIRMED` shift schedule rejects this command
- Confirmation applies to every Shift in the period at once; there is no per-slot publish step
- `confirmedAt` is stamped at the moment of confirmation
- Once `CONFIRMED`, `updateShift` is rejected for the period's shifts; a change to a slot means cancelling it (`cancelShift`) or adding a new one
- A Shift added to a `CONFIRMED` shift schedule is committed immediately
- Confirmation does **not** freeze staffing: `createShiftPlacement`, `swapShiftPlacement`, and `releaseShiftPlacement` remain available, including on the shift date itself, because a substitution is a change of plan rather than a republication of the table
- Confirming a period with no shifts is allowed and is not an error

## Process Flow

```mermaid
flowchart TD
    A[Receive shiftScheduleId] --> B{ShiftSchedule exists?}
    B -->|No| BX[Return error: SHIFT_SCHEDULE_NOT_FOUND]
    B -->|Yes| C{status = DRAFT?}
    C -->|No| CX[Return error: SHIFT_SCHEDULE_ALREADY_CONFIRMED]
    C -->|Yes| D[Set status = CONFIRMED and stamp confirmedAt]
    D --> E[Return confirmed shiftSchedule]
```

## External Dependencies

- [shiftSchedule::ShiftSchedule](../model/ShiftSchedule.md) model - the state-scoped entity this command transitions to CONFIRMED
- [shiftSchedule::Shift](../model/Shift.md) model - every shift in the period becomes committed by this transition

## Error Scenarios

- **SHIFT_SCHEDULE_NOT_FOUND**: no ShiftSchedule exists for the given id
- **SHIFT_SCHEDULE_ALREADY_CONFIRMED**: the shift schedule is already CONFIRMED

## Test Cases

- confirmShiftSchedule transitions a DRAFT shiftSchedule to CONFIRMED and stamps confirmedAt
- commits the whole period in one act rather than one slot at a time
- confirming a period with no shifts is allowed
- throws SHIFT_SCHEDULE_ALREADY_CONFIRMED when the shiftSchedule is already CONFIRMED
- throws SHIFT_SCHEDULE_NOT_FOUND when the shiftSchedule does not exist
