# Employee Shift Progressive Form: Persistence Contract

Updated: 19 July 2026

## Purpose

The progressive form asks business questions that cannot always be reconstructed from the legacy calculation columns. The system therefore saves two representations:

1. Existing operational values used by attendance and payroll helpers.
2. A versioned answer snapshot used to restore the exact progressive interview in Edit mode.

The snapshot is not a replacement for the legacy tables and must never be used directly by payroll calculation helpers.

## Permanent tables

### `jos_app_empshift`

Continues to store the operational shift values, including timing, shift group, grace, lunch calculation fields, OT, camera, night-shift and other legacy flags.

### `jos_app_lmconfig` and `jos_app_lmconfig_grid`

Continue to store payroll-location late-mark policy headers and cutting slabs.

### `jos_app_empshift_policy_answers`

Stores one permanent progressive answer snapshot for each `shiftid`.

- `answers_json`: all form answers, LM rules and UI interview state.
- `schema_version`: allows future question changes and migrations.
- `setup_complete`: indicates that both LM and Lunch interviews were confirmed.
- `current_step`, `current_module`, `current_question`: restore and audit metadata.
- `answer_source`: `wizard` for newly confirmed answers; reserved `legacy_import` for a future confirmed migration of old shifts.
- `created_by`, `modified_by`, timestamps: ownership and audit metadata.

The unique `shiftid` key makes final saves idempotent: Edit updates the existing snapshot instead of inserting duplicates.

## Draft table

`jos_app_empshift_draft` remains temporary and user-specific. Its `form_data` JSON stores the same schema as the permanent answer snapshot, including:

- Timing and Shift Type decisions.
- Payroll locations.
- Explicit Late Mark tracking Yes/No.
- All Late Mark policy and slab-builder answers.
- Explicit Lunch Yes/No and all Lunch calculation answers.
- Current main step, LM question, Lunch question and question histories.

Draft behaviour:

- Text/number input is debounced briefly.
- Buttons, answer cards, Next, Back and accessible step navigation trigger an immediate save.
- Next/Back waits for the active save promise, preventing overlapping version writes.
- A successful final save writes the permanent snapshot in the same transaction and only then deletes the draft.
- A failed final transaction preserves the draft.

## Add and Edit behaviour

### Add

The browser collects schema version 4 and posts it in `policy_answers_json`. The server validates the payload, saves legacy values, LM configuration/slabs and the permanent snapshot in one transaction.

### Edit

The server first loads legacy calculation values, then overlays the exact permanent answer snapshot. Arrays such as payroll locations and LM policy locations and all generated rules are restored explicitly. The browser restores the saved interview state without guessing from grace, `lm_show`, lunch timing or Shift Type.

### Old records

Old shifts without a permanent snapshot continue to load from legacy columns. The form must not pretend that unrecorded LM answers were explicitly selected. Once the user reviews and saves that shift through the progressive form, a real `wizard` snapshot is created.

## Critical mappings

| Progressive answer | Operational persistence |
|---|---|
| Shift Type decision | `jos_app_empshift.shift` plus timing fields |
| Selected payroll locations | `jos_app_empshift_locationlog` |
| Lunch Yes/No | `jos_app_empshift.lunch_applicable` |
| Lunch details | Existing lunch fields in `jos_app_empshift` |
| Track Late Mark Yes/No | Explicitly retained in the answer snapshot |
| Shift grace/report display | Existing `in_grace`, `max_grace`, `lm_show` fields |
| Shared cutting policy | `jos_app_lmconfig` |
| Cutting slabs | `jos_app_lmconfig_grid` |

Important: explicit Late Mark Yes/No is now preserved for Edit and audit. Changing attendance calculation behaviour to consume a dedicated `lm_enabled` operational column requires a separate helper change and regression test; it must not be inferred from `lm_show`.

## Deployment order

1. Run `tools/sql/2026-07-19-employee-shift-policy-answers.sql`.
2. Deploy `employee-shifts-progressive.php`.
3. Test Add draft restore, Lunch restore, LM restore, final Add and final Edit.
4. Verify the legacy shift row, LM policy/slabs and policy-answer snapshot were committed together.

