# README

## Overview

The shiftSchedule module owns the **PLANNED side of work** (シフト・勤務予定・ロスター) for the enterprise attendance platform. It defines the reusable シフトパターン (`ShiftPattern`), the shift schedule period (`ShiftSchedule`) that a シフト表 is confirmed as a whole, the concrete シフト (`Shift`) placed on dates within it — including 中抜け / 通し / 宿直 / 応援 and unassigned open shifts — and the shift schedule placements (`ShiftPlacement`) that staff them. It is the WFM predicted layer that ADR-017 makes a first-class scope of the redesign.

shiftSchedule deliberately owns only the *plan*. The 所定 planned-time baseline (`WorkSchedule`) and employment-regime classification (`WorkRegime`) both remain in **workforce**, and jurisdiction-specific rule configuration belongs in the consuming application. The 会社休日 calendar (`CompanyHoliday`) lives in **time-tracking**, referenced to determine 所定日 / 休日. Actual worked time lives in **time-tracking** (`ReportedTimeBlock` / `CalculatedTimeBlock`); shiftSchedule reads it only to derive predicted-vs-actual variance (遅刻 / 早退 / 未出勤 / 超過). "Whose" is always resolved through a workforce `Assignment`, and only ever through `ShiftPlacement`: a Shift names nobody, so an open shift is simply one no ACTIVE placement references. Placements are superseded or cancelled rather than deleted, so a confirmed shift schedule can be read back as "who was planned here, and when did that change".

AI demand forecasting, automatic shift generation, self-scheduling (availability / swaps), and fatigue prediction are **out of scope** — shiftSchedule models the container only, leaving the optimization engine to a later GO decision gated on ROI thresholds (ADR-017; issues #11, #6).

## Key Features

- [Shift Planning](docs/feature/shift-planning.md) — ShiftSchedule periods, ShiftPattern definition and Shift creation, both composed of ordered segments so 中抜け is genuine multi-segment (通し / 宿直 / open shifts too); 所定日 / 休日 determination by reading time-tracking CompanyHoliday; DRAFT → CONFIRMED at the ShiftSchedule level; future room for interval (勤務間インターバル) and 36協定 pre-checks
- [Shift Schedule and Support Assignment](docs/feature/shift-schedule-and-support-assignment.md) — shift schedule placement, 応援 (support) and multi-site open-shift fill, and predicted-vs-actual variance read from time-tracking actuals

## Module Scope

### In Scope

- Reusable シフトパターン (ShiftPattern) — 早番 / 遅番 / 日勤 / 夜勤 / 宿直 / 中抜け templates keyed by a stable code, composed of one or more embedded segments (`segments`)
- ShiftSchedule period (ShiftSchedule) — the シフト表 itself, with `startDate` / `endDate` and a DRAFT → CONFIRMED lifecycle; confirming commits the whole period to workers in one act. Periods may overlap: membership is the explicit `Shift.shiftScheduleId` FK
- Concrete シフト (Shift) on dates within a ShiftSchedule — 通常 / 中抜け / 通し / 宿直 / 応援 and unassigned open shifts — composed of one or more embedded segments (`segments`; 中抜け = 2+ segments with a real gap). The Shift carries no lifecycle of its own; only `cancelledAt`, for withdrawing a single slot out of a confirmed period
- ShiftSchedule placement (ShiftPlacement) — staffing a Shift with an Assignment, including 応援 (support) and multi-site fills; ACTIVE / SUPERSEDED / CANCELLED with a swap chain, so substitutions are kept as history rather than deleted
- Reading time-tracking CompanyHoliday for 所定日 / 休日 determination
- Deriving predicted-vs-actual variance by reading time-tracking actuals against the planned shift, over ACTIVE placements only

### Out of Scope

- 会社休日 calendar (CompanyHoliday) — owned by time-tracking; shiftSchedule reads it for 所定日 / 休日 determination
- Work / pay rules, rounding, 割増 — owned by time-tracking (旧 work-rules rule sub-domain, ADR-020); shiftSchedule only surfaces future planning-time warnings against them. 36協定 thresholds are modeled by neither module — shiftSchedule leaves structural room for a planning-time pre-check only (ADR-017)
- Time punches, worked/overtime minutes, ReportedTimeBlock / CalculatedTimeBlock — owned by time-tracking; shiftSchedule reads actuals for variance only
- Worker / employment / Assignment master data — owned by workforce; a Shift resolves "whose" via an Assignment id
- 所定 planned-time baseline (WorkSchedule) per Assignment — owned by workforce; it is an employment condition, not a plan placed on dates
- AI demand forecasting, automatic shift generation, self-scheduling (availability submission / swaps), fatigue prediction — deferred to a future GO decision (ADR-017; issues #11, #6)
- Multi-dimensional labor allocation and cost attribution — deferred with structural room only; the Assignment-level (one-dimensional) placement seam is threaded now (ADR-018)
- Jurisdiction-specific labor-regime configuration, including Japanese variable-working clearing periods and deemed-hours settings — supplied by the consuming app through custom fields and app-owned models

### Scope Decision Rationale

shiftSchedule is scoped to the **plan**: what work is supposed to happen, for whom, and where — patterns, shifts, and shift schedules. It is separated from time-tracking because the plan, the rules that calculate pay from the plan, and the actuals that realize it each have a distinct consistency boundary and change cadence; conflating them was the legacy mistake where a single record mixed plan, calculation, and punch (ADR-011, ADR-014). Holidays (`CompanyHoliday`) live in time-tracking because calculation must evaluate them for 割増. The 所定 baseline and employment-regime identity are both resolved through workforce rather than duplicated here, while country-specific parameters stay outside the bundled module so applications can evolve them with their local rules.

The AI / optimization layer (demand forecast, auto-generation, self-scheduling, fatigue) is deliberately excluded so this phase delivers a clean, modelable container. ADR-017 defers the engine to a GO decision gated on the #6 ROI thresholds (残業例外削減 8–12%, 需要予測精度 +15%); building the container without the engine keeps the schema stable for when that decision is made, and the Assignment-level placement seam keeps future multi-dimensional labor allocation (ADR-018) retrofittable without a migration.

## Module Dependencies

- workforce — `Assignment` resolves "whose" for ShiftPlacement; a Shift never references one, so a slot has no Assignment until placed. `getAssignment` is injected into the placement commands so they can verify the Assignment is effective on the shift's date (shiftSchedule cannot join workforce's tables)
- time-tracking — `TimeEntryCode` and `WorkRule` referenced for future planning-time warnings
- time-tracking — `CompanyHoliday` read for 所定日 / 休日 determination; `ReportedTimeBlock` / `CalculatedTimeBlock` read to derive predicted-vs-actual variance (shiftSchedule never writes actuals)
- organization (bundled) — `Site` referenced by Shift for multi-site placement and 応援
- approval (bundled) — reserved for future shift-publish / shift schedule approval routing; not wired in this design phase (ADR-017)
- notification (bundled) — reserved for future shift-publish / open-shift events; not wired in this design phase
