# Checkin module

The public, unauthenticated **QR web check-in lane**. A customer scans a
store's QR (`/c/{token}`), fills a mobile form, and is registered into the
store's buy queue as a `Buy { source: qr_code, status: remote_check_in }`
before walking in. Implements design spec `2026-06-15-remote-checkin-qr-lane`
(decisions D1–D18).

## Endpoints (`/v1/checkin/*`)

| Method | Path | Notes |
|---|---|---|
| GET | `/checkin/{token}` | Store branding. `checkin.store` + `checkin.acceptable` + `throttle:checkin-branding`. Cacheable. |
| POST | `/checkin/{token}/requests` | Create the remote check-in. Adds `idempotency` + `throttle:checkin-create` + `verify.turnstile`. 201 new / 200 durable replay / 409 key-reuse / 410 dead link / 423 paused-or-suspended. |
| GET | `/checkin/status/{status_token}` | Signed status read, keyed by the unguessable `status_token` (NOT behind the per-store middleware). `throttle:checkin-status`. |

## Principal & abuse model

The lane authenticates as a **store check-in link** (opaque signed token →
store), never a device or user. Anonymous, internet-facing traffic is guarded
by Turnstile, layered rate limits (IP / phone-HMAC / token / global), an
opaque non-enumerable store token, and an unguessable per-buy status token. An
optional Sanctum bearer attaches the buy to a logged-in user; an absent or
invalid bearer is ignored (the lane never 401s for it).

## Deferred capture (D1) & loyalty timing (D3) — do not "fix"

The legally-sensitive parts of a buy — **driver's license, the binding terms
signature, and `terms_version`** — are NOT captured on the public web. They are
populated in-store at the POS `convert` step (`remote_check_in → queued`).

**Loyalty is granted at `convert`, not at check-in.** A customer who later
resolves to `no_buy`/`declined` still keeps the loyalty join — they joined the
program by showing up, consistent with the kiosk granting at `queued`. The grant
is one-join guarded by the existing ledger marker. Do not move the grant to the
remote-check-in create step or to the terminal `complete` step.

## Reused services

`BuyIntakeService` (generalized off `KioskDevice`), `KioskCustomerResolver`,
`LoyaltyWriter`, `KioskQueueService`, and the `idempotency` middleware are all
shared with the kiosk lane.
