Cross-platform mobile app

GameLynx

A skill-based matchmaking app that pairs golfers with compatible playing partners nearby, then gets the round on the calendar.

Overview

GameLynx treats compatibility as the product rather than as a filter bolted onto a booking tool.

Golf is a four-hour commitment with a stranger, so a bad pairing costs a whole afternoon. Existing tools help you book a tee time but not find someone worth playing it with — you either golf alone, get paired at random by the pro shop, or spend the round waiting on someone forty strokes away from your game.

The app closes that loop end to end. A weighted model turns handicap, pace, cart preference, and availability into a ranked match. A discovery map shows who is nearby. Messaging carries structured tee-time invitations rather than a conversation someone has to convert into a plan. Trip planning finds locals before you travel.

What makes it useful as evidence is not the feature list — it is what went wrong. A crash on opening a profile, a keyboard that closed the instant it opened, and a production build with a blank map are all documented above with the specific cause and the specific fix.

Status
In development — store listings in progress
Built for
Golfers looking for compatible playing partners, plus moderators reviewing reports
Role
Solo full-stack developer: mobile app, REST API, admin console, native debugging, release engineering
Timeline
Aug 2025 – Present
Platforms
iOS, Android, Web admin console
Categories
Mobile Apps, Location & Maps
The GameLynx app shown on a phone, displaying its member discovery map

What was built

Responsibilities and core features

Responsibilities

  • React Native app for iOS and Android from one Expo codebase
  • Flask and PostgreSQL API with JWT authentication and rate limiting
  • React moderation console for reports, appeals, and audit logs
  • Native memory profiling and crash diagnosis
  • Release engineering through EAS Build with environment-scoped configuration

Core features

  • Passwordless sign-in via Twilio Verify, with email and password kept available
  • Live Mapbox discovery map with Supercluster marker clustering
  • Server-side location randomisation so exact coordinates never leave their owner
  • Outdoor and indoor toggle separating course players from simulator players
  • Weighted Quick Match scoring across handicap, average score, pace, cart, simulator and music preferences
  • Direct messaging carrying structured tee-time invitations accepted or declined inline
  • Mapbox Search course picker filtered to golf points of interest
  • Long-press message reporting into a moderation queue
  • Travel planning that re-centres discovery on a destination and date range
  • Handicap trend chart drawn as hand-built SVG with a nice-number axis algorithm
  • RevenueCat ad-removal purchase with restore, plus Google AdMob

Engineering

Problems that came up, and what fixed them

The specifics matter more than the feature list. This is what the work actually consisted of.

  1. A crash that looked like a logic bug and was a memory bug

    Opening a player profile hard-crashed the app. Instrumenting the running app showed a second live Mapbox instance — the profile's map thumbnail, while the discovery map stayed mounted underneath in the navigation stack — pushing native heap from about 185 MB past 390 MB and stalling garbage collection for 24 seconds, which Android resolves by killing the process. Replacing non-interactive maps with Static Images API renders, and guaranteeing only one live map is ever mounted, settled memory at a stable 217 MB across repeated navigation.

  2. A New Architecture rendering bug that closed the keyboard

    Tapping any text field opened the keyboard and immediately closed it. The cause was a focus style that toggled elevation and shadow on the focused input's wrapper. On React Native's Fabric renderer that recreates the underlying native view, which drops IME focus. Keeping focus styling to colour-only changes fixed it.

  3. Authorization derived from the token, not the request

    Every user-scoped endpoint was audited so the acting user is derived exclusively from the JWT rather than from a client-supplied identifier in the URL, query string, or body — closing a class of bugs where any caller could read or modify another account by changing an ID. Writes are strictly self-scoped, and exact GPS coordinates are returned only to their owner. A dedicated test module asserts 401 without a token, 403 when acting as another user, that a forged sender ID in a body is ignored in favour of the token, and that location privacy holds for non-owners.

  4. Abuse and cost controls on billable endpoints

    Rate limiting sits on the authentication and SMS endpoints, because every verification request is a billable Twilio message. Shared storage for the limiter is configurable so limits hold across multiple server workers instead of being silently multiplied by the worker count.

  5. An API migration that did not require a synchronised release

    Mobile releases roll out gradually, so the client was written to work against both the pre-auth and post-auth versions of the API. App and server can deploy independently without breaking anyone mid-rollout.

  6. Configuration missing only in release builds

    Client configuration was absent from release builds, producing a blank map in production while everything worked locally. Configuration moved to managed EAS environment variables, and a missing map token now degrades to a placeholder instead of crashing the app.

Technical architecture

  • React Native 0.81 on Expo SDK 54 with React 19, TypeScript, React Navigation 7, and the New Architecture (Fabric) enabled
  • Flask and SQLAlchemy over PostgreSQL with Alembic migrations, Flask-JWT-Extended, Flask-Limiter, and Gunicorn
  • Mapbox for live maps, marker clustering, static thumbnails, and golf-course search; Twilio Verify for SMS; DigitalOcean Spaces for photo storage
  • Native integrations for location, notifications, and image picking, plus RevenueCat purchases and Google AdMob
  • A React 19, Vite, and TanStack Table admin console over 52 protected endpoints
  • EAS Build with environment-scoped configuration, shipping iOS, Android, and web from one codebase

Technology stack

  • React Native
  • Expo
  • TypeScript
  • React 19
  • Flask
  • PostgreSQL
  • Mapbox
  • Twilio Verify
  • Docker

What it adds up to

  • Runs as three independently deployable parts: mobile client, Flask API, and React moderation console
  • 22 screens, 99 API endpoints, and 14 data models across the system
  • 52 protected admin endpoints behind the moderation console
  • Backend covered by 18 pytest modules, including a dedicated authorization test suite
  • Memory profile stabilised at 217 MB after the native crash investigation

Related services

The work this project demonstrates

Custom Software

One system that matches your real process, instead of four tools and a spreadsheet holding the gaps together.

Mobile Apps

Cross-platform apps in React Native and Expo — including the background, permission, and store-review work that decides whether an app actually ships.

MVP Development

A first version scoped to answer the one question your idea actually depends on — built to ship, not to demo.

Keep reading

The MileageSync app shown on a phone, displaying its trip tracking home screen

Cross-platform mobile appMobile Apps

MileageSync

A hands-free mileage logger that detects drives in the background and turns them into IRS-ready deductions, with every GPS point kept on the device.

In development — store listings in progress

  • React Native
  • Expo
  • TypeScript
  • SQLite
  • +4 more
The FamilyPromise matching app shown across mobile screens

Full-stack civic mobile appMobile Apps

FamilyPromise Mobile Matching App

A role-based mobile app helping tenants, property owners, and case handlers coordinate Section 8 housing voucher matches in one workflow.

University team project, Fall 2024 — built with multiple contributors

  • React Native
  • Expo
  • TypeScript
  • Flask
  • +3 more

All case studies

Building something in this territory?

If any of this resembles the problem you are trying to solve, a discovery call is the fastest way to find out whether we can help.

Prefer email? Contact@DeviceBytes.com