# Time Clock Punching

## Overview

Time Clock Punching is the recording of **raw punch events** as they happen, from any source a worker uses — web, mobile, kiosk, IC card, biometric reader, PC logon, Slack, or bulk import. Each punch (clock-in, clock-out, break start/end, step-out/step-in) is stored as an immutable `TimeClockEvent` against the worker's `Assignment`. Nothing here is ever edited or deleted: a mistaken punch is retracted by appending a record to the separate append-only `TimeClockEventVoid` table that points back at the original, so the full punch trail survives (ADR-014, ADR-023).

Punches carry only what happened in the real world — an instant, a type, and a source — and deliberately do not decide which workday they belong to. That decision is made later by a **day-breaker** during calculation, so an overnight clock-out after midnight can still belong to the prior workday. This raw layer is the immutable foundation the reported and calculated layers are built on.

## Business Purpose

- Preserve the raw punch record immutably so audit and labor-dispute defense always have the original events (ADR-014)
- Support Japan's diverse punch culture — IC-card and biometric readers, kiosks, PC logon — plus modern ambient/mobile punching (issues #10, #11)
- Correct punches without destroying data, using void records in a separate table rather than mutation (the antidote to "punches disappearing / not being fixable", issue #6)
- Keep occurred-time and workday separate so overnight and cross-midnight shifts are handled correctly by the day-breaker (issue #7)
- Provide a future seam to alert on anomalous punches (e.g. clock-in while on leave) via the notification module (ADR-004)

## Process Flow

```mermaid
flowchart TD
    A[Worker punches via a source: WEB/MOBILE/KIOSK/IC_CARD/BIOMETRIC/PC_LOGON/SLACK/IMPORT] --> B[Resolve Assignment effective on occurredAt]
    B --> C[Append immutable TimeClockEvent with eventType, occurredAt, source]
    C --> D{On-leave clock-in?}
    D -- Yes, future seam --> E[Emit alert event via notification]
    D -- No --> F[Event available for block formation]
    E --> F
    F --> G{Punch was a mistake?}
    G -- Yes --> H[Append TimeClockEventVoid VOID referencing targetEventId; original preserved]
    G -- No --> I[Day-breaker assigns workday during block formation]
    H --> I
```

## Scenario Patterns

- **Standard day punch**: CLOCK_IN then CLOCK_OUT from one source forms the basis of a work block
- **Break and step-out**: BREAK_START/BREAK_END and STEP_OUT/STEP_IN punches record non-work intervals within a shift
- **Multi-source**: an IC-card clock-in and a mobile clock-out on the same day are both valid events on the same Assignment
- **Overnight shift**: a CLOCK_OUT after midnight is recorded with its real occurredAt; the day-breaker assigns it to the prior workday later
- **Mistaken punch**: an erroneous or duplicate punch is voided by a TimeClockEventVoid record; the original is never mutated or deleted
- **Bulk import**: punches from an external time-clock device or file are appended with source = IMPORT / IC_CARD
- **On-leave clock-in (future)**: a punch on a day the worker is on leave raises an alert via the notification seam (deferred)

## Test Cases

- recording a punch appends a TimeClockEvent linked to the Assignment effective on its occurredAt
- events are never modified or deleted; a correction appends a TimeClockEventVoid record referencing the original
- `eventType` and `source` are stored with normalized enum naming
- a TimeClockEventVoid record references a prior, not-already-voided event of the same Assignment
- an overnight clock-out is stored with its real occurredAt and is not itself assigned a workday at punch time
- the punch's source, once recorded, is part of the immutable event
- raw events are not read directly by payroll (only CalculatedTimeBlock is)

## Reference Links

- Data-model design research (Reported/Calculated separation, day-breaker, Rule Analysis traceability): https://github.com/tailor-sandbox/Omakase-ERP-attendance/issues/7
- Market pain points (punches disappearing / not being fixable): https://github.com/tailor-sandbox/Omakase-ERP-attendance/issues/6
- UI / ambient-punch trends: https://github.com/tailor-sandbox/Omakase-ERP-attendance/issues/10
- IC-card / biometric punch culture and sources: https://github.com/tailor-sandbox/Omakase-ERP-attendance/issues/11
