Bug
checkInParticipant() in app/src/lib/checkInService.js runs a transaction that writes to the participant document:
```js
transaction.set(
participantRef,
{ checkInStatus: "checked-in", checkedInAt, checkedInBy: organizerId },
{ merge: true },
);
```
But firestore.rules for events/{eventId}/participants/{participantId} only allow a participant to update their own doc and only the keys `status`, `buddyPreference`, `updatedAt`:
```text
allow update: if request.auth != null && request.auth.uid == participantId &&
validateAttendanceStatus(request.resource.data) &&
request.resource.data.diff(resource.data).affectedKeys().hasOnly([`status`, `buddyPreference`, `updatedAt`]);
```
The check-in runs as the organizer (not the participant), and writes `checkInStatus` / `checkedInAt` / `checkedInBy` — both conditions fail. Because Firestore transactions are atomic, this one denied write fails the whole transaction, so `checkInParticipant` always returns `Check-in failed`.
Reproduction
- Create an event (free, no ticket).
- Attendee RSVPs (participant doc created).
- Organizer scans attendee QR → `QRScannerScreen.js:86` calls `checkInParticipant`.
- Check-in fails with `Unable to complete check-in` even though organizer owns the event.
Expected
Free-RSVP attendees can be checked in by the event owner/organizer.
Actual
Transaction denied by security rules; check-in always fails.
Suggested fix
Either allow the organizer (via `isEventOwner`) to update `checkInStatus`/checkedInAt\/checkedInBy\ on the participant doc, or route the participant status update through a Cloud Function (as is already done for volunteer logs).
Bug
checkInParticipant()inapp/src/lib/checkInService.jsruns a transaction that writes to the participant document:```js
transaction.set(
participantRef,
{ checkInStatus: "checked-in", checkedInAt, checkedInBy: organizerId },
{ merge: true },
);
```
But
firestore.rulesforevents/{eventId}/participants/{participantId}only allow a participant to update their own doc and only the keys `status`, `buddyPreference`, `updatedAt`:```text
allow update: if request.auth != null && request.auth.uid == participantId &&
validateAttendanceStatus(request.resource.data) &&
request.resource.data.diff(resource.data).affectedKeys().hasOnly([`status`, `buddyPreference`, `updatedAt`]);
```
The check-in runs as the organizer (not the participant), and writes `checkInStatus` / `checkedInAt` / `checkedInBy` — both conditions fail. Because Firestore transactions are atomic, this one denied write fails the whole transaction, so `checkInParticipant` always returns `Check-in failed`.
Reproduction
Expected
Free-RSVP attendees can be checked in by the event owner/organizer.
Actual
Transaction denied by security rules; check-in always fails.
Suggested fix
Either allow the organizer (via `isEventOwner`) to update `checkInStatus`/
checkedInAt\/checkedInBy\on the participant doc, or route the participant status update through a Cloud Function (as is already done for volunteer logs).