Event check-in
Members check themselves — and their household — in to events via QR.
The QR is the share surface; the actual record is one row per
attendee in event_checkins. This is also the first producer of
attendance records: a future dashboard Attendance KPI (Phase 6) reads
from this table.
The check-in surface is module-gated via module_checkin in
Community settings. When the module is off, the admin
QR option and the member check-in entry points hide; the link itself
still resolves so an existing link an admin already shared keeps working
during the toggle window.
Per-event QR (admin)
Open Events in the admin sidebar. On any non-trashed event, the row's overflow menu now carries Check-in QR. Tapping it opens a sheet with:
- The QR image — sized for a phone scan from across a foyer.
- The deep-link URL below it (
https://psalmly.app/c/<slug>/checkin/<code>). Inside the Psalmly app that URL is also reachable via thepsalmly://scheme. - Download PNG + Copy link — print it for a kiosk poster, share it in the volunteer team chat, or paste it into a Sunday-morning email.
- A live attendance list that updates every time someone scans in.
The checkin_code is opaque and unique — guessing one is not viable.
Rotating a code is a future fast-follow; for now if a code leaks the
admin should delete + recreate the event (a future "Reset code" button
will avoid that).
Self check-in (member)
Two paths:
- Mobile (in-app): on the church Home, tap the Check in quick-action tile (shown when the check-in module is on) → the in-app camera opens → point at the event QR and the app drops into the Confirm view automatically.
- Web / OS camera: scanning the printed QR with the phone's camera —
or opening the deep link directly (paste into the browser, follow a
shared link) — opens the web check-in. The QR encodes an https URL
and the app declares only the
psalmly://scheme (no associated domains), so an OS-camera scan resolves on the web, not in the app. The link routes to/c/<slug>/checkin/<code>and resolves into the same Confirm view.
In Confirm, the member sees the event identity (title + start + place) plus one toggle per subject:
- Me — the signed-in member themselves.
- One toggle per household member (a parent's kids show up here from the 4.2 household model). The viewer's own row is excluded — that's the Me toggle.
Toggle the people checking in and tap Check in. Idempotent: a duplicate check-in (re-scanning by accident) shows "Already checked in" — no error, no double count.
What's stored
Each event_checkins row stamps:
| Column | Meaning |
|---|---|
event_id | The event the check-in is for. |
church_id | Denormalised; lets RLS gate without a join. |
user_id OR household_member_id | The attendee. Exactly one is set. |
checked_in_at | When the row was inserted. |
checked_in_by | The signed-in member who performed the check-in (always = auth.uid() on insert). |
A (event_id, user_id) / (event_id, household_member_id) partial
unique index makes double-checkin a no-op (Postgres 23505).
Who sees what
| Item | Member | Admin |
|---|---|---|
| Their own check-in | ✅ | ✅ |
| Their household's check-ins | ✅ | ✅ |
| Another member's check-in | ❌ | ✅ |
| The full per-event attendance list | ❌ | ✅ |
RLS enforces all of this on the database — the client doesn't filter.
Privacy + safety
- Minor data stays in-household. A child's check-in is visible to any adult in their household and to church admins; never to other members of the church.
- Check-in does NOT post to the prayer board or any community feed. It's an attendance record, not a social signal.
- The QR is not a credential — knowing the code lets you confirm attendance for yourself at a specific event. RLS still demands the caller is a member of the church, and a leader/admin can audit any anomaly via the attendance list.
Future / fast-follows
- Code rotation — a button on the admin sheet to refresh
checkin_code(invalidates the old QR). Useful if a code leaks or for recurring events that re-use a printed poster. - Children's check-in with printed labels + guardian claim tags — Phase 6. This slice is the lightweight precursor.
- Geofenced / auto-checkin — out of scope (privacy + battery).
- Dashboard Attendance KPI consuming these rows — Phase 6 (the data spine ships now; the metric lands later).
More topics