Click is a privacy-first social connection app. The repo contains:
| Component | Location | Tech |
|---|---|---|
| KMP mobile app | composeApp/ |
Kotlin Multiplatform + Compose Multiplatform (Android/iOS) |
| Supabase Edge Functions | supabase/functions/ |
Deno/TypeScript (mobile-owned + mirrored shared) |
| DB migrations (mirror) | supabase/migrations/ |
Subset mirrored from click-web (source of truth) |
| Legacy SQL notes | database/ |
PostgreSQL SQL files / historical notes |
Backend HTTP APIs live in the sibling click-web Next.js app (CLICK_WEB_BASE_URL). The old Flask server/ tree has been removed — do not recreate it.
See README.md for architecture details and AI.md for coding guidelines.
No local Flask/API server is required. Point CLICK_WEB_BASE_URL in composeApp/src/commonMain/kotlin/QRModels.kt at deployed click-web (https://joinclick.co) or a local Next.js instance (http://localhost:3000 for simulator).
Android build:
./gradlew :composeApp:assembleDebug
Requires local.properties with sdk.dir=/opt/android-sdk and MAPS_API_KEY=<key> (placeholder value works for builds). If local.properties is missing, Gradle falls back to checked-in local.defaults.properties so iOS framework embed and IDE sync still configure. The google-services.json is optional; the build gracefully skips the Google Services plugin when it is absent.
- Kotlin unit tests (Android JVM):
./gradlew :composeApp:testDebugUnitTest - Kotlin / Compose UI tests (iOS Simulator):
./gradlew :composeApp:iosSimulatorArm64Test(macOS + Xcode required) - All Kotlin tests:
./gradlew :composeApp:allTests - Maestro E2E (device/simulator + CLI):
bash scripts/maestro-smoke-android.sh(assembleDebug, uninstall snapshot APK, install, thenmaestro test .maestro --include-tags smoke). Do not run Maestro against an emulator that already has an old Click install. Smoke flows:launch_login,login_signup_toggle. Auth (onboarded user with avatar):maestro test .maestro/auth --include-tags auth -e TEST_EMAIL=... -e TEST_PASSWORD=...(tabs.yamlasserts noonboarding-avatarand map chrome). Do not add Maestro Cloud to PR CI. - Supabase drift (when
../click-webis present):bash scripts/check-supabase-drift.sh - Shared prefs/personality migration lives in click-web (
20260813180000_notification_prefs_personality.sql) and is mirrored here.
CI: Android job runs on Linux (testDebugUnitTest + assembleDebug); iOS job runs on macos-26 + Xcode 26 (iosSimulatorArm64Test).
- The
google-secretsGradle plugin readsMAPS_API_KEYfromlocal.properties, withlocal.defaults.propertiesas a checked-in fallback for CI/Xcode when the gitignored file is absent. A placeholder value is sufficient for compilation but Google Maps features won't work at runtime without a real key. - iOS builds require Xcode (macOS only) and are not runnable in Cloud Agent VMs.
- The
click-webNext.js companion app (QR flows, chat gatekeeper) is a separate repository. Prefer checking it out as a sibling../click-web. click-web/supabaseis the source of truth for shared migrations andbind-proximity-connection. Sync mirrors withbash scripts/sync-supabase-from-click-web.sh. Mobile-only functions (send-push-notification,expire-*,verify-hub-proximity) stay in this repo.- Supabase Edge Functions require the Supabase CLI to deploy/serve locally; they are not needed for basic mobile build testing.
local.propertiesis gitignored. Recreate it on each fresh checkout (or rely onlocal.defaults.propertiesfor Gradle configure-only steps such as iOS framework embedding).
The liquid-glass tab bar and navigation bar are real UIKit views added to ComposeUIViewController.view (BottomBar.ios.kt, NativeCollapsingScaffold.ios.kt). They are not Compose UIKitView / UIKitViewController overlays.
- Pin
UITabBarto the host bottom andUINavigationBarto the host top. Height is intrinsic / constrained to the bar — neverfillMaxSize(). - On iOS 26, do not apply
UITabBarAppearance/UINavigationBarAppearance(that opts out of Liquid Glass). - Do not restore Compose
LiquidGlassPageHeader/ opaque-Box headers as iOS tab-root chrome. - No merge to
mainwithout device/simulator screenshots or a recording of every tab (Home, Add Click, Clicks, Map, Settings, nested screens) attached to the PR. CI passing is not visual proof. - Re-attempts of a SwiftUI
TabView/NavigationStackshell stay on a branch until that visual checklist is complete.