PlayTennisMarin
Mar. 2026 - Present
An iOS app for a Marin County tennis league. Players enroll, pay, and report match scores. Built with AI coding tools.
Overview
PlayTennisMarin is an iOS app for a recreational tennis league in Marin County. Players enroll in a season, pay with Apple Pay or Venmo, and report their match scores. My mom runs the league and was doing all of it by hand over email.
I built it using AI coding tools.
What I Did
- Worked with my mom to understand how she actually runs the league and where here process can be improved (and where it cannot). I then built around that instead of around what seemed technically cleanest. She handles payments by hand, so the app writes new enrollments to a simple spreadsheet.
- Designed the app. I have always been interested in graphic design so this part was very fun. I used one main green color, one accent color, Montserrat throughout, and a fixed set of design "atoms" that are reused across the app. This way the app feels consistent and changes are easy to make. There are no default iOS components anywhere in the app which makes the app feel custom and cohesive.
- Made decisions based on who uses it. Most players are older adults enrolling once or twice a year on their phone. That's why there are tooltips on the confusing fields, plain explanations of skill levels, and support for large text sizes without the layout breaking.
- Tested it with real people. I sent TestFlight builds to my mom and her friends and fixed what they got stuck on.
- Created a premium feel by adding a loading screen with a bouncing tennis ball and a score submission screen that shows a gold scorecard that shifts as you tilt the phone.
- Made sure the security basics were covered: input validation on the server, verified payment webhooks, rate limiting, escaping user input in emails, no personal data sent to error reporting, and a published privacy policy.
- Set up the parts outside the app itself. A backend server, domain and DNS, email authentication records so confirmation emails don't land in spam, separate staging and production environments, Apple Pay configuration, and App Store submission.
- Kept the codebase readable. Shared logic lives in one place, constants have one source of truth, and I documented why certain things are the way they are so nothing gets undone by accident later.
How It Works
A React Native app sends and receives data to and from an Express backend. There's no database. Session info is sent to Airtable, which my mom edits directly, and completed enrollments get written back there for her to work from.
Apple Pay enrollments finish on the server rather than on the phone. The app requests a payment intent, and a Stripe webhook completes the enrollment after the charge goes through, so someone who loses signal partway still ends up enrolled with a confirmation email. If the app can't reach live data it falls back to the last good response, and then to a baseline shipped with the backend, so it never just fails to load.
Tech Stack
- App
- React Native / Expo SDK 54, JavaScript, iOS only
- Backend
- Node.js / Express on Railway
- Payments
- Stripe, plus a Venmo/Zelle option
- Data
- Airtable, editable by the league admin
- Resend, with SPF / DKIM / DMARC set up
- Error Monitoring
- Sentry
- Distribution
- EAS Build, TestFlight, App Store
- AI tools
- Claude for planning, Claude Code for the implementation
What I Learned
Most of my time went to things that weren't code but rather design-based like whether a confirmation email asking for a Venmo payment reads as a scam or if the app is clear and easy to use for an older user base.
Could I code an app from scratch by myself? Absolutely no way. This project mostly taught me how to use an agentic coding tool efficiently and effectively. I learned how to manage context windows, choose the appropriate model, and oversee multiple agents.
I also ended up learning a lot about DNS records, email deliverability, API rate limits, and staging environments.
Some Concepts and Terms I Learned
- Webhook
- A webhook is triggered by a specific action in an application which will send the event details in a packet to an "endpoint" which is provided by the receiving app. The receiving app processes the information however it sees fit, and then sends back an acknowledgement.
- API Keys and Secrets
- An API key is a sequence of characters you send with a request that proves you are who you claim to be.
- SPF / DKIM / DMARC
- SPF is a list of servers allowed to send email on your domain. DKIM attaches a signature to the email which the receiver verifies with a public key. DMARC verifies that SPF or DKIM passed and that the domain that passed matches the one in the From address, then enforces a policy on what happens when it doesn't.