$ cd ../projects
LIVE IN PRODUCTIONFreelance client project · Aug 2024 – Present

Góly Esá

Everything a paying member touches — payment, video, chat, invoice — runs through code I wrote.

goly-esa.skApp StoreCode available on request
Steady
paying subscriber base, month after month
4
deliverables on one API — web, iOS, Android, admin
~34k
lines of code across 4 codebases
91
REST endpoints
1
developer, end to end

$ ls screenshots/

Goly Esa iOS app public listing on the Apple App Store with screenshots and 5.0 rating
Live on the App Store — the public iOS listing
Goly Esa app home feed with the community intro and express news posts
The member home feed — express news and community content
Goly Esa membership screen with an active premium subscription, profile settings and order history
Membership & account — Stripe-backed premium, activated

$ render architecture.svg

webReactiOSReact Native · ExpoAndroidReact Native · Expoone API contractSpring Boot 3 APIJava 17 · JWT auth · RESTPostgreSQLJPA entitiesFFmpeg → HLSvideo · podcasts · voiceWebSocket / STOMPchat · forumFCM/APNs · SMS · emailcampaigns & pushStripesubscriptions · one-time passessigned webhooks → entitlementsPREMIUM ENTITLEMENTS DRIVEN BY SIGNATURE-VERIFIED STRIPE WEBHOOKS

01 / One developer, four deliverables

Góly esá, s.r.o. is a Slovak football-analysis brand whose audience expects content where they live: on their phones. They didn't need a website — they needed a product. A premium membership with recurring payments, exclusive posts with video and podcasts, a direct line to the experts, and apps in the stores. As a solo freelancer, I took on the entire surface area: a Java 17 / Spring Boot 3 API on PostgreSQL, a React web app, and Expo / React Native apps for iOS and Android — plus the operations around them. The bet was that one developer with a tight, conventional stack could deliver and run all four surfaces, and that architecture choices would matter more than headcount. Twenty-one months of active development later, the platform is live, and a real business runs on it.

02 / The architecture: server-side authority, one contract

The backend is a layered Spring Boot 3 API: 91 REST endpoints across 19 controllers, 25 services, 18 JPA entities, JWT auth with refresh tokens and server-side revocation. One rule shaped everything: server-side authority for anything involving money or roles. The premium role is granted and revoked exclusively by verified Stripe webhooks — invoice paid, payment failed, subscription deleted — never by the client app. All four surfaces speak one API contract, and web and mobile share the Redux state shape, so a feature ships once and works everywhere. Payments run Stripe end to end: SetupIntents for off-session card setup, recurring subscriptions with 3D Secure handling, and one-time fixed-duration passes alongside them. Around the core: iText-generated Slovak VAT invoices, FCM and APNs push, SMS campaigns for new podcast episodes, transactional email, and an in-app admin area for content, users, and pricing. Boring, conventional framework usage everywhere else — by design.

03 / Money first: the duplicate-payment bug

A retried subscription after a failed payment could double-charge a returning user — a real production bug, with real money. The fix was making subscription creation defensive: before creating anything new, the system cancels past-due and unpaid leftovers, detects an existing active or trialing subscription, and returns it instead of creating a second one. The same caution applied when the business changed its pricing. I built an admin-triggered migration that moved every existing live subscription to the new Stripe price with proration explicitly disabled — no surprise invoices, no support tickets — while a new package structure of one-time day passes and multi-month passes went live alongside the recurring plans. Repricing a live subscriber base is the kind of change you only get one shot at, and it shipped cleanly.

04 / Video from phones is hostile

Members upload video from their phones, and phone video fights back. Rotation lives in metadata; a naive HLS transcode ignores it and everything arrives sideways. My pipeline — FFmpeg via JavaCV, running server-side — reads the rotation from the displaymatrix metadata and rotates frame-by-frame during transcode. Screen recordings are detected by codec and frame-rate profile and get their own encoder settings (CRF 23 at 3 Mbps, faster preset) so they don't waste bitrate that camera video (CRF 16, 8 Mbps, veryslow) actually needs. Oversized uploads are capped at 4K and downscaled, with a 200 MB limit. The output is H.264/AAC HLS with 10-second VOD segments, streamed to hls.js on the web and native players in the apps. The same pipeline transcodes podcast audio and chat voice notes to AAC HLS. Upload a video, and it just plays — everywhere.

05 / Realtime chat, push that actually arrives

Members talk to the experts through realtime chat — STOMP over SockJS WebSockets, with voice messages, image messages, and reactions — and to each other in a community forum with threads and reactions. Two WebSocket endpoints, topic broadcasts plus per-user queues, an admin-controlled messaging flag, all behaving identically on web and mobile. Then there's getting a notification to actually arrive. Reliable push across FCM and APNs — token lifecycles, Apple's delivery limits — took genuine iteration, and the commit history shows the scar tissue. Beyond push: an in-app notification center, comment notifications, and SMS campaigns through a Slovak gateway whenever a new podcast episode drops. The unglamorous parts got the same care — numbered Slovak VAT invoices your accountant accepts, order history, email campaigns — because a paying business runs on them every day.

06 / The outcome — honestly

The platform is live in production with a steady base of paying subscribers. The iOS app is on the App Store at v1.18.0, Android ships as a direct APK from the site, and the web app runs at goly-esa.sk. I continue to operate and evolve the system — the repricing, new package types, and feature work all shipped well after launch. I don't publish the client's other business figures. Two things I'd do differently, and I say so openly: I'd build an automated test suite around the payment paths first — validation was manual, which I compensated for with defensive server-side checks, but tests are the right answer — and I'd move media transcoding out of the request path into a worker queue before scale demands it. Knowing where the real debt is, and naming it, is part of operating a production system honestly.

07 / What this proves

Roughly 34,000 lines of code across 268 files: 8,827 lines of Java on the backend, 13,376 of TypeScript on the web, 11,705 in the mobile app — 130 commits over 21 months of active development. One person owning four codebases means every architectural decision comes back to you personally; that ownership is the real deliverable. If you need someone who can take a product from "we need an app" to a running business — payments that don't double-charge, video that just plays, chat that feels instant, invoices that pass the accountant — across web and both app stores, this is that project. Start to finish, one accountable developer. The client repo is private; a code walkthrough is available on request.

$ cat stack.txt

Java 17Spring Boot 3PostgreSQLReactTypeScriptReact Native / ExpoStripe SubscriptionsWebSockets / STOMPFFmpeg / HLSFCM / APNs

Need a product shipped across web and both app stores by one accountable developer? Code walkthrough available on request — get in touch.