Joining groups (code, QR, link)

You can belong to multiple groups. Join is not limited to “first time” users.

From the app

Welcome screen (no groups yet)

If you are not in any group, Home shows:

  • Join a Group (Link/Code/QR)
  • Create a New Group

Profile (already in one or more groups)

Profile → scroll to Join another group (above Create a New Group):

  • Join a Group (Code / QR / Link) opens the same join flow.

Join methods

Method What you do
6-character code Admin shares code (e.g. A3K9XZ). Enter it on Join group.
QR in the app On Join group, open the in-app camera scanner (allow camera). Scan the invite QR. Home ⋮ menu has Join a Group.
Nearby (BLE) An admin can enable Broadcast to Nearby Users on Invite / Onboarding (advertises the group name). Members open ⋮ → Join a Group → BLE Scan to discover and join.
Link / system camera Open https://swapsanity.com/join/CODE (or scan that QR with the phone camera). If the app is installed and deep links work, SwapSanity opens; if you are signed out you sign in first, then join continues.
NFC / BLE Optional paths on the same Join screen when offered.

After a successful join request, group admins must approve (unless your email is pre-approved on the roster). You will not see the group’s shifts until approved.

Pending approval notification

  • In the app: Home shows an amber banner: “Your group join request is pending admin approval.” Tap it for details. The banner stays until an admin approves or rejects.
  • After you submit: You also get an in-app notification (“Join request pending”).
  • When decided: Push (FCM) + in-app notification if approved or declined.
  • Admins: Get a push when someone requests to join (if they have notifications enabled).

How invite codes work

  1. A group admin opens Admin → Invite Members (or CLI create-invite).
  2. The screen shows a QR, the 6-character code, and the invite link, with Copy code, Copy link, and Share.
  3. Server stores group_invites/{CODE} with groupId and 24-hour expiry.
  4. Public URL: https://swapsanity.com/join/CODE (sandbox: https://sandbox.swapsanity.com/join/CODE).
  5. The recipient opens the link or Join a Group and enters the code. A pending request is created in group_requests until an admin approves.

App download

Scanning a join QR does not install the app by itself. Users need SwapSanity from the store (or web). Deep links open the app if already installed and universal links are configured.

Multi-group shared events

Event admins (Organizers) manage cross-group events (races, ski hills, etc.). Host-group members see the event on their group calendar without automatically becoming admins or participants. The event site can be an existing group location or only for this event (not added to the group’s place list).

Ways to get involved

Path What it means
Open join link / code Join as racer, spectator, patrol, or staff (participation only — not Event admin). Choosing spectator joins without a team. You still help the mesh and place nearby tags with your GPS. You can turn off Show my position on the map if you do not want a dot. Organizers can include spectator GPS on the event plan. The name you enter at join (or the organizer name when you create the event) is what appears on the live map — not your Google account name.
Invite to participate Named invite from an Event admin; accept or decline
Invite as Event admin / Safety Privilege role; accept or decline (separate from participate)
Assign duty (tradable) Calendar duty on the host group that you can trade — not admin powers

Join / invite methods:

Method URL / action
Link / QR https://swapsanity.com/join-event/CODE
Landing page Opens the app when installed; otherwise shows the code + Continue in web app
In app Activity Hub → Join multi-group event → enter code

Invite codes are created with the event (or refreshed via generateSharedEventInvite) and expire (default 72 hours).

Who can manage the event?

Only Event admins (Organizers) can change event details, boundaries, and roles — not every host-group lead. The person who created the event is an Event admin; they can invite others as Event admin or Safety. Being a group admin of the host team does not by itself grant event edit.

How to know if deep linking works

Quick device checks

  1. Install the production or sandbox build (package com.swapsanity.app or .sandbox).
  2. Create an invite: https://swapsanity.com/join/TESTCODE (or real code from admin).
  3. Phone: Messages/Notes/Chrome → open the link without opening the app first.
    • Success: SwapSanity opens (or asks to open) and lands on Join with that code.
    • Fail: Only the website/browser opens and never offers the app.
  4. Cold start: Force-stop the app, then open the link again (tests install-time / cold deep link).
  5. Signed out: Sign out, open link → should open app → login → then continue join (pending URI is stored).

Android verification (developer)

# Association file must be HTTPS + application/json (no redirect)
curl -sI https://swapsanity.com/.well-known/assetlinks.json
curl -s https://swapsanity.com/.well-known/assetlinks.json

# Should list package + cert fingerprint matching your signing key
adb shell pm get-app-links com.swapsanity.app
# Look for swapsanity.com → verified
# If not verified:
adb shell pm verify-app-links --re-verify com.swapsanity.app

iOS

  • apple-app-site-association must be served at
    https://swapsanity.com/.well-known/apple-app-site-association
    (no .json suffix required; correct Content-Type).
  • Team ID in that file must match Apple Developer (not placeholder YOUR_TEAM_ID).
  • Device: Settings → Developer → Associated Domains Diagnostics (if available), or open the link from Notes.

Common failures

Issue Effect
apple-app-site-association still has YOUR_TEAM_ID iOS universal links never verify
Wrong SHA-256 in assetlinks.json Android App Links stay unverified
Hosting not serving .well-known Verification fails
Only custom scheme, not https Camera may open browser only

Repo files: swapsanity.com/.well-known/assetlinks.json,
swapsanity.com/.well-known/apple-app-site-association,
Android autoVerify intent-filters, iOS Runner.entitlements applinks.

Not the same as field ID QRs

Join invite QR Static ID / check-in QR (batch export)
Join request for a group Identify a person on field day
Path like /join/CODE Personal token payload
Join group screen Activity hub / identity scanners

Admin: approve requests

In the app: group onboarding / pending join requests UI.

CLI (as group admin):

swapsanity_cli --env sandbox list-join-requests --group-id GID
swapsanity_cli --env sandbox approve-join --request-id GID_USERUID
swapsanity_cli --env sandbox reject-join --request-id GID_USERUID

Create invite:

swapsanity_cli --env sandbox create-invite --group-id GID
# → code + https://swapsanity.com/join/CODE

Join with code:

swapsanity_cli --env sandbox join-group --code A3K9XZ