[Admin] Digital membership cards (Apple Wallet + Google Pay)
Every active member can add their membership to Apple Wallet (iOS) or Google Pay (Android). The wallet pass shows their status, tier, expiry, and a QR code for check-in — members can flash their phone at the front desk without unlocking it.
Member experience:
- Member sees "Add to Wallet" buttons on their dashboard (club page / studio member portal)
- One tap → pass downloads + installs in the native wallet app
- Pass updates dynamically when their tier, status, or expiry changes (via Apple's web service — push notifications)
QR payload schema:
`whosin://checkin/{productType}/{orgId}/{memberCode}` — deterministic, HMAC-derived 6-digit code per member. Our admin QR scanner recognises this format.
Operational setup (Apple Wallet):
Production Apple Wallet passes require a signed certificate from Apple's Developer Program:
- Register for an Apple Developer account ($99/year)
- Create a Pass Type ID identifier (e.g. `pass.app.whosin.membership`)
- Generate a signing certificate + download the .p12 file
- Upload to our platform via `firebase functions:secrets:set PASSKIT_P12` and `PASSKIT_P12_PASSWORD`
Until the cert is uploaded, the generator falls back to a demo mode — members see a friendly "Coming soon" message instead of a broken pass.
Operational setup (Google Pay):
Google Wallet uses a service account. Same `firebase functions:secrets:set GOOGLE_WALLET_ISSUER_ID` + `GOOGLE_WALLET_SERVICE_ACCOUNT_KEY`.
Security:
- Passes are member-scoped — a member can only generate passes for their own memberships
- QR codes are HMAC-signed so they can't be forged; even a copied screenshot requires the active backend check
- Lost phone: member regenerates the pass from their dashboard; old pass is invalidated on next scan attempt
Troubleshooting:
- "Pass won't install" → check that the Pass Type ID matches your cert
- "Pass shows 'Expired'" → our backend updates via Apple's push service every few minutes; wait or re-download
- "QR won't scan" → brightness up, damaged QR fallback: tap "Manual entry" in the scanner