# `checkins` — Guest Check-in Records

**Module:** Attendance  
**Soft Delete:** No (immutable event records)

---

## Purpose

Records each guest check-in event on the wedding day. Supports both QR scan and manual check-in, with correction capability for fixing mistakes.

---

## Columns

| Column | Type | Nullable | Default | Description |
|--------|------|----------|---------|-------------|
| `id` | `BIGINT UNSIGNED AUTO_INCREMENT` | No | — | — |
| `guest_id` | `BIGINT UNSIGNED` | No | — | → `guests.id` |
| `wedding_event_id` | `BIGINT UNSIGNED` | No | — | → `wedding_events.id` (which ceremony) |
| `workspace_id` | `BIGINT UNSIGNED` | No | — | Denormalized for isolation enforcement |
| `operator_id` | `BIGINT UNSIGNED` | No | — | → `users.id` (Crew or Couple who checked in) |
| `checkin_method` | `VARCHAR(10)` | No | — | `qr_scan \| manual` |
| `actual_pax` | `TINYINT UNSIGNED` | No | `1` | Actual attendees at check-in (minimum 1) |
| `has_angpao` | `TINYINT(1)` | No | `0` | Whether guest brought gift envelopes |
| `angpao_count` | `TINYINT UNSIGNED` | No | `0` | Number of envelopes (0 if has_angpao = 0) |
| `notes` | `VARCHAR(500)` | Yes | NULL | Operator note |
| `is_correction` | `TINYINT(1)` | No | `0` | Whether this corrects a previous check-in |
| `corrects_id` | `BIGINT UNSIGNED` | Yes | NULL | → `checkins.id`. Self-reference for corrections |
| `checked_in_at` | `DATETIME` | No | `CURRENT_TIMESTAMP` | Immutable event timestamp |

---

## Primary Key / Indexes

| Name | Columns | Type |
|------|---------|------|
| `PRIMARY` | `id` | Primary |
| `idx_checkins_workspace_event` | `workspace_id, wedding_event_id` | Index |
| `idx_checkins_guest_event` | `guest_id, wedding_event_id` | Index |
| `idx_checkins_checked_in_at` | `workspace_id, checked_in_at` | Index |
| `idx_checkins_has_angpao` | `workspace_id, has_angpao` | Index |

---

## Foreign Keys

| Column | References | On Delete |
|--------|-----------|-----------|
| `guest_id` | `guests.id` | RESTRICT |
| `wedding_event_id` | `wedding_events.id` | RESTRICT |
| `operator_id` | `users.id` | RESTRICT |
| `corrects_id` | `checkins.id` (self) | SET NULL |

---

## Referenced By

| Table | Column |
|-------|--------|
| `label_print_jobs` | `checkin_id` |

---

## Business Rules

- `actual_pax` can differ from `invited_pax` — the couple decides how many physically arrived
- Correction records set `is_correction = 1` and reference the original checkin via `corrects_id`
- RESTRICT delete ensures guest and event records are preserved after check-in
- `checked_in_at` is immutable — never updated after creation
