Skip to content

Latest commit

 

History

920 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Click (KMP) — Mobile app

Anti-doomscrolling · Stop scrolling, start living.
Click is built as a people-first social utility: fewer infinite feeds, more real-world presence. We optimize for intentional connection—not passive consumption—so moments in the room matter more than minutes on the timeline.

Click — The seamless offline-to-online connection app.
This repository is the Kotlin Multiplatform mobile client: Compose Multiplatform UI with Android and iOS targets. Backend pieces (Postgres, Edge Functions, companion HTTP APIs) live in sibling services; the app integrates via Supabase and a configurable web base URL for QR and chat APIs.


Core concept

Click is a digital handshake: it turns brief, in-person encounters into lasting connections using a multi-modal proximity mesh—not a single hardware sandbox. Phones agree they shared the same physical context through corroborating signals, then open a lightweight path to chat and memory—without treating the OS as the source of truth for “who was really there.”

The Tri-Factor Handshake

New connections use a simultaneous blend of:

  • Bluetooth Low Energy (BLE) advertising — local presence and session framing in the room.
  • 18.5 kHz ultrasonic audio chirps — inaudible to most listeners, detectable on the ultrasonic-capable microphone path for tight co-location.
  • Progressive high-accuracy GPS — refined over the handshake window so devices can assert they occupy the same space, not merely the same building.

Together, these factors mathematically verify that two (or more) phones were in the exact same room, reducing reliance on legacy OS-imposed proximity restrictions.

Verified Group Cliques (Multi-Tap)

When three or more people connect at the same time (Multi-Tap), the app coordinates a verified group clique: the backend performs O(1) validation so the cohort forms a fully connected subgraph (everyone mutually verified with everyone else). On success, participants drop into a private group chat—a real clique, not a loose list of pairwise guesses. The current chat threat model is documented in composeApp/src/commonMain/kotlin/compose/project/click/click/crypto/CRYPTO_README.md; product copy must not overstate it.

Memory Capsules

Memory Capsules pair objective signals with subjective story:

  • Hardware-backed contextBarometricHeightMonitor captures elevation trends; AmbientNoiseMonitor reads exact decibel levels from the same stream used for ultrasonic detection, grounding “how loud / how high” the moment felt in data.
  • Polymorphic subjective tagging — users layer meaning (“met at open mic,” “after class”) in a flexible schema; tagged payloads participate in data fan-out so capsules stay rich without collapsing into one rigid field.

Lifecycle: 48-Hour Auto-Archive Sweep

There is no “hard lock” or forced expiry that deletes relationships by timer alone. Instead, Click runs a 48-Hour Auto-Archive Sweep: connections that are not acted on within 48 hours move to archive, keeping the active surface calm and intentional. Archived items remain recoverable according to product policy—this is about UI hygiene and focus, not punishing users with arbitrary countdowns.


Source sets and entry points

Location Purpose
composeApp/src/commonMain/kotlin/ Shared UI (Compose), ViewModels, repositories, Supabase client, chat, connections, maps, most business logic
composeApp/src/androidMain/kotlin/ Android actual implementations: FCM service, TokenStorage, crypto, location
composeApp/src/iosMain/kotlin/ iOS actual implementations: TokenStorage, push helpers, permission requesters, stubs/bridges to Swift where needed
iosApp/iosApp/ Xcode app: Swift for UserNotifications, Google Sign-In, app lifecycle and Kotlin entry
composeApp/build.gradle.kts Multiplatform targets, dependencies (e.g. Supabase KMP, Ktor)

Guideline: add new features in commonMain first; use expect/actual (or small platform facades) only when you must touch BLE / audio / GPS pipelines, Keychain, EncryptedSharedPreferences, or platform location.


Features (app scope)

  • Tri-Factor proximity mesh + QR — In-person discovery and connection via BLE + ultrasonic + progressive GPS; QR remains a fallback path that uses HTTP against the configured web base URL (see QRModels.kt / QrCodeView.kt). Connection metadata can record connectionMethod (e.g. "qr", "tri_factor").
  • Multi-Tap verified cliques — Simultaneous 3+ person handshakes validated server-side; client-side encrypted group chat on success.
  • Real-time chat — Supabase Realtime channels, SupabaseChatRepository / ChatViewModel, typing and presence-oriented state, push hooks for background delivery (Edge Function + FCM/APNs). - Presence — Realtime subscriptions in home/chat/map-related ViewModels for online status and activity signals.
  • Maps — Map screens and Realtime channels (e.g. connection discovery) backed by Supabase-backed repositories.
  • Memory Capsules (opt-in)rememberAmbientNoiseMonitor, rememberBarometricHeightMonitor, and subjective tagging flows when the user opts in (settings + connection sheets).
  • Prior Connections — Optional, skippable onboarding step. Contacts are hashed on-device (SHA-256 of E.164 / email) and matched via POST /api/contacts/discover. Self-reported edges use source=prior and never mint connection_encounters or handshake vanity metrics.

Tech stack (mobile)

  • Kotlin Multiplatform + Compose Multiplatform
  • Android: Gradle, Jetpack lifecycle/viewmodel where used, FCM (google-services.json in composeApp/)
  • iOS: Xcode project, APNs (via backend)
  • Supabase KMP: Auth (with SettingsSessionManager + app TokenStorage sync in SupabaseConfig), Postgrest, Realtime
  • Ktor client for companion HTTP APIs (QR, waitlist)

Configuration (this app)

Supabase

Edit composeApp/src/commonMain/kotlin/compose/project/click/click/data/SupabaseConfig.kt:

  • SUPABASE_URL, SUPABASE_ANON_KEY
  • Auth redirect scheme/host (click / login) must match Supabase Auth and the iOS/Android URL handlers.

SupabaseConfig.startSessionSync(tokenStorage) keeps the SDK session aligned with TokenStorage (Keychain on iOS / encrypted prefs on Android). iOS migrates the previous plaintext session once into Keychain and purges it after the secure write succeeds. Cold boot imports TokenStorage when the SDK session is empty or expired. Access-token wall-clock headroom is not enough to skip GoTrue refresh: TestFlight updates and dual-store drift otherwise keep a JWT that click-web rejects as 401 Unauthorized until the user signs out. Boot, 45-minute ticker, foreground resume, and HTTP 401/403 retries call refreshSession(forceRefresh = true) (which always hits /token unless another refresh is already in-flight), then drop/reconnect the Realtime socket so hub subscribe and sends use the new bearer. connect() is a no-op on an open socket — rebindRealtimeSocket() disconnects first.

Web base URL (QR, waitlist)

composeApp/src/commonMain/kotlin/QRModels.kt defines CLICK_WEB_BASE_URL. Point it at your deployed or local companion app that exposes /api/qr, etc. (typically the click-web project next to this repo).

Android push (FCM)

Place google-services.json in composeApp/ (package compose.project.click.click). The Supabase Edge Function uses a Firebase service account for server-side FCM.

iOS capabilities

Enable Push Notifications, Background Modes (Remote notifications), and associated entitlements.


Build and run

Android

From this directory:

./gradlew :composeApp:assembleDebug

Use Android Studio’s composeApp run configuration, or install the debug APK from composeApp/build/outputs/.

Create local.properties at the repo root with sdk.dir and MAPS_API_KEY (see AGENTS.md). If the file is missing, Gradle uses checked-in local.defaults.properties so the project still configures (required for Xcode’s Kotlin framework step).

iOS

  1. Open iosApp/iosApp.xcodeproj in Xcode.
  2. Resolve Swift packages (GoogleSignIn).
  3. Select the iosApp scheme, set signing team, build and run.

Xcode’s Compile Kotlin Framework phase runs ./gradlew :composeApp:embedAndSignAppleFrameworkForXcode. That Gradle configure step needs MAPS_API_KEY via local.properties or the checked-in local.defaults.properties fallback (Xcode Cloud writes local.properties in iosApp/ci_scripts/ci_pre_xcodebuild.sh).

Maestro (E2E UI)

Black-box flows live in .maestro/. Install the Maestro CLI (Java 17+) — do not vendor the Maestro source:

curl -fsSL "https://get.maestro.mobile.dev" | bash
# Rebuild, uninstall any snapshot APK, install this tree, then smoke.
# assembleDebug alone is not enough — AVDs keep the last installed Click app.
bash scripts/maestro-smoke-android.sh

Smoke flows (no secrets): smoke/launch_login.yaml, smoke/login_signup_toggle.yaml.

Email/password journeys (dedicated test user that has finished onboarding and has an avatar):

maestro test .maestro/auth --include-tags auth \
  -e TEST_EMAIL=you@example.com \
  -e TEST_PASSWORD=secret

auth/tabs.yaml also asserts onboarding-avatar is not visible and map chrome (map-screen) after nav-map.

Package id is compose.project.click.click on Android and iOS. Grant runtime permissions in flows via launchApp.permissions. Cloud uploads (optional) use .github/workflows/maestro-cloud.yml (workflow_dispatch, secrets MAESTRO_API_KEY + MAESTRO_PROJECT_ID).

Database and server-side setup

SQL migrations and ordering: database/. Full operator checklist (Edge Function secrets, APNs, FCM): EXTERNAL_SETUP.md.

Optional: quick_start_chat.sh for guided prompts around Supabase config.


Performance & scale

See docs/archive/PERFORMANCE.md (archived July 2026 notes) for hotspots, scale failure modes, and remediation (inbox RPC, RealtimeCoordinator, gated map prefetch).

Compile (Android + iOS):

./gradlew :composeApp:compileDebugKotlinAndroid :composeApp:compileKotlinIosSimulatorArm64

Notable modules (navigation)

Area Starting points
Auth & session data/SupabaseConfig.kt, viewmodel/AuthViewModel.kt, data/repository/AuthRepository.kt
Chat viewmodel/ChatViewModel.kt, data/repository/SupabaseChatRepository.kt
Connections / proximity / QR viewmodel/ConnectionViewModel.kt, ui/screens/ConnectionsScreen.kt, ui/components/QrCodeView.kt
Maps viewmodel/MapViewModel.kt
Push (Kotlin side) notifications/ChatPushNotifier.kt, data/repository/PushTokenRepository.kt

Monorepo note (click-web companion)

If your checkout includes click-web beside click/, run the Next.js app locally when developing QR, waitlist, or widget-vibe flows:

# Terminal 1 — click-web
cd click-web && npm run dev   # http://localhost:3000

# Terminal 2 — mobile
# Set CLICK_WEB_BASE_URL in QRModels.kt / build config to http://localhost:3000 (simulator)
# or your machine LAN IP for physical devices

The KMP app does not embed click-web—it calls it over HTTP with the user's Supabase JWT where required.

What mobile delegates to click-web

Flow Mobile entry Web route
QR token issue / redeem ApiClient, QrCodeView GET/POST /api/qr
Waitlist Marketing links POST /api/waitlist
Home widget vibe ApiClient.getWidgetVibe() GET /api/insights/widget-vibe
Home activity recap ApiClient.getActivityRecap() GET /api/me/recap?window=day|week

What mobile produces for B2B Click Insights

Mobile handshakes create connections and connection_encounters rows. When the user has Include in business insights enabled (AppDataManager.locationPreferences.includeInInsightsEnabled), rows carry include_in_business_insights: true and feed anonymized venue analytics on click-web /insights/*. Availability intents power Vibe Radar hexbins.

Mobile does not host the B2B insights dashboard—that is web-only (click-web/lib/insights/README.md).

Parity reference

  • Consumer dashboard parity: click-web/lib/dashboard/README.md
  • Connection / QR / proximity: click-web/lib/connections/README.md
  • Payload contracts (push, encrypted chat): click-web/AI.md §2, click-web/lib/chat/README.md
  • Insights testing playbook: click-web/lib/insights/README.md § Real-world testing

Ask DeepWiki

About

No description, website, or topics provided.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages