Features

Live map

·         A single PostGIS spatial query loads everything in view, replacing 42+ separate calls.

·         Android uses GPU-clustered MapLibre and handles 100k+ markers at 60fps; iOS uses native Apple Maps with feature parity.

·         Promoted events appear larger and pulsing; ended activities are greyed out.

·         A join radius keeps events local; joining beyond 100 km uses one of 3 weekly exceptions.

Feed, stories and communities

·         One home feed merges community events, personal activities and posts in a single server call, with offline-first caching.

·         48-hour stories with per-viewer seen state and automatic cleanup.

·         Facebook-group-style communities with member-only feeds, optional approval for posts, events and joins, and an admin moderation queue. Admins are notified when an event is waiting for approval.

·         Recurring events (weekly, biweekly, monthly) share one chat across occurrences and appear as a single feed card.

Meeting people

·         Discover suggests people to follow, ranked by distance and shared interests.

·         Explorer is a swipe deck for meeting nearby people.

·         Follow requests (new): users can make their profile approval-only. Enforced on the server, so older app versions cannot bypass it.

·         A Vibe Score rewards hosting and engagement on a public leaderboard. Hosts reported by 3+ no-show attendees lose their score, and repeat offenders are banned automatically.

Messaging

·         Direct, group and event chats with photos, videos, emoji reactions, tappable links and online presence. Photos animate in and out of their thumbnails; videos play on both platforms with first-frame previews and disk caching.

·         Message requests for non-followers; blocking is enforced everywhere, including push notifications. A Blocked users screen (new) lists and unblocks people.

·         Database triggers add users to event chats when they join and remove them when they leave.

Payments (four flows)

·         Tickets: Stripe checkout (Apple Pay, Google Pay, card) issues a scannable QR ticket.

o   Door check-in (new): hosts scan guests' QR codes with the camera (Google code scanner on Android, AVFoundation on iOS) or type a 12-digit code, and get an instant result (admitted, already used, wrong event, not valid). The QR encoder is written in-house.

o   Automatic refunds (new): a Stripe refund marks the ticket refunded, removes the buyer from the event, updates the host's sales and notifies the buyer.

·         Tips: attendees tip hosts via Stripe Connect, with 100% going to the host.

·         Event boosts: hosts pay to promote events. Android uses Stripe, iOS uses an Apple in-app purchase; both end at the same server function.

·         Premium: Adapty subscriptions, granted only by a verified server-side webhook, with restore purchases and instant unlock after buying.

Other

·         English and Croatian (new): the whole app is localised, including correct Croatian plural forms, with an in-app language switch. Push notifications arrive in the user's chosen language.

·         Notifications (improved): pushes show while the app is open, and tapping one opens the exact screen it is about on both platforms.

·         After events, attendees are prompted to rate, tip or report no-shows.

·         Reminders 1 day and 1 hour before joined events.

·         Referral sharing (new): share your referral code through the native share sheet.

·         Deep links and Universal Links open shared events and posts in the app.

·         A remote switch handles maintenance mode and forced or optional updates per platform.

·         A web version runs the same Kotlin code via Kotlin/Wasm, with Google and Apple sign-in.


Engineering highlights

Performance

Batch operations and 5-minute local caching cut API traffic by about 90%; presence updates dropped from ~260 to 2–10 events per hour; the map loads its whole viewport in one query. In-memory caches are safe for concurrent access and all database work runs off the main thread.

Payment safety

Tickets are recorded atomically. iOS boost purchases are saved on-device and retried on every launch until the server accepts them, and the server ignores duplicate transactions. Every Apple transaction is re-verified with Adapty's server API rather than trusting the app. A refund revokes what was bought (ticket, boost or subscription), and a late or repeated webhook can never undo a refund.

Privacy & security audit (new)

In October 2026 I ran a full privacy and security review of the backend and fixed what it found. Private user data (email, location) can no longer reach other users' devices; location lives in a table only the server can read, and distances are rounded. Blocking and post visibility are enforced by the database itself, not just the app. Chat photos and videos moved to a private storage bucket served through 1-hour signed links. That switch was rolled out in a safe order: ship the new app builds, raise the minimum supported version, then flip the bucket.

Database security

Supabase grants public execute rights on new database functions by default. This had exposed several payment functions in production, including one that could mint free tickets. All of them are now server-only, and every migration verifies permissions afterwards. A database trigger also protects server-owned profile fields (premium status, Vibe Score, points), which previously could be changed by the user's own app.

QA & release discipline (new)

A written cross-platform test plan (Android emulator + iOS simulator) covers two devices on one account, time zones, HEIC photos, race conditions, interrupted uploads and clock skew. Release builds are test-launched before shipping, after one minified build was found to crash only in release.

Recurring events

A nightly job generates each occurrence as a regular event row, so the feed, map, tickets, reminders and Vibe Score needed no special handling.

Architecture

MVVM with repositories: 25 ViewModels and 36 repositories, with the chat ViewModel split into 13 focused controllers. Dependency injection with Koin, offline storage with SQLDelight.

Cross-platform

Most logic is shared. Maps, payments, sign-in, QR scanning and deep links sit behind thin expect/actual bridges, which is what made the web version possible.