The hard part: points that are always right
The point-of-sale vendor's public REST API didn't expose the identity and loyalty fields the app needed. Polling it harder wouldn't fix that.
So I designed a two-speed integration and got the vendor to approve it:
GraphQL bulk sync
Builds the login index: who each member is and how to find them, synced in bulk.
Live REST
Reads spendable points at the moment a member looks, so the balance is always current.
Built to grow without re-shipping
Tiers, milestones, and order-ahead are built but dark behind feature flags, ready to switch on when the business is. Marketing push is consent-gated from the start, over APNs and FCM.
Through both app stores
Both apps passed Apple and Google review. Google Play initially rejected the Android build: R8 obfuscation had renamed serialized fields. I tracked it down, fixed it, and shipped.
Handed off properly
The engagement ended with a full operational handoff packet, so the people running the platform have everything they need to operate it.
Scale
PostgreSQL across 21 tables, holding about 126,000 member records and about 20,000 menu rows, behind a Node and Express API served with nginx and PM2, with a React admin dashboard for staff.