Skip to content

Contacts & QR Share

Purpose

Contacts helps a user manage trusted people they can call. QR share lets a user safely share a temporary contact link without exposing private keys or long-lived identity data.

The flow is intentionally simple:

Discover person -> send request -> accept/decline -> sync contact list -> warm trust data for future calls

Main Concepts

Concept Meaning
Contact A person already connected to the current user.
Friend request A pending relationship request between two users.
Share token An opaque server-issued value embedded in a QR/link.
Trust warm-up Background verification of peer device keys after a request is sent or accepted.
Numeric fallback Direct add flow from call history when the app already has a participant identifier.

Friend Request Lifecycle

User chooses a person
        -> app sends request by known ID or share token
        -> server creates pending request
        -> receiver gets notified
        -> receiver accepts, declines, or sender cancels
        -> contact lists and badges refresh

Important behavior:

  • Sending by ID is used when the app already knows the target from call history or an internal record.
  • Sending by token is used for QR/universal-link sharing.
  • Accepting a request creates the contact relationship.
  • Declining or canceling removes pending relationship state and clears related local trust cache.
  • Successful send/accept can return peer key hashes; the app verifies and caches those in the background so future calls start faster and with fewer warnings.

QR Share Lifecycle

User opens own QR
        -> app asks server for an opaque token
        -> app builds a share link from that token
        -> app renders the link as QR
        -> another user scans/taps/imports the link
        -> app resolves the token
        -> app shows the resolved display name
        -> user confirms Add Friend

The client treats token lifetime, usage count, and rate limits as server policy. The client only displays the expiration hint returned by the server, with a local fallback when the server omits that hint.

Accepted Input Sources

Source Behavior
Camera scan Reads QR payload, resolves token if it is a contact link.
Photo import Detects QR payload from the selected image, then follows the same scan path.
Universal link Opens the Add Friend sheet and resolves the embedded token.
App deep link Same as universal link, but through the app URL scheme.
Call history action Uses the known participant identifier directly when no share token is involved.

Error Handling

The UI does not hardcode token-specific branches. It displays the localized server error when available, otherwise a generic validation or network message.

Common user-facing states:

  • invalid QR/link
  • token cannot be resolved
  • request already sent or no longer valid
  • network/session failure
  • duplicate send prevented while a request is already in progress

State & Concurrency Intent

The Contacts and QR screens keep UI state on the main actor and push network work into asynchronous service calls. Loading flags prevent duplicate user actions while a request is in flight.

Design intent:

  • one visible source of truth for contact list and request badge
  • no business logic inside visual rows/buttons
  • no client-side token generation or token signing
  • no sensitive data in QR payload beyond the opaque token
  • predictable recovery: refresh lists after send/accept/decline/cancel