MyMise began as a four-person CDU capstone project, which I led, with a simple observation: cafes run the same menu in three places, the counter board, the QR ordering app and Uber Eats, and the three drift apart. Prices get updated in one and not the others. A size disappears. An add-on is free in-store and $1.50 online. Nobody notices until a customer does.
The core engine does two things. First, it matches items across menus. Names are never identical, so matching uses RapidFuzz fuzzy string matching with thresholds tuned against real menus. Second, it runs nine rules over each matched group: price gaps, size gaps, missing add-ons, description mismatches and so on. In the pilot cafe it found all 13 problems the owner already knew about, plus the reassurance that there were no others.
The backend is FastAPI on PostgreSQL 16. The decision I am most glad about is using PostgreSQL row-level security for tenant isolation. Every business’s data is walled off at the database layer, not just in application code, and there is a test that fails if one business can see another’s rows. That test was written before most of the features.
Sign-in supports email codes, Google, Microsoft and passkeys through OpenID Connect and WebAuthn, with invites for owner, manager, staff and viewer roles. One Expo and React Native codebase covers phone, tablet and web, which matters when the user is standing behind a counter with whatever device is nearest.
It runs on Azure in Australia, on Container Apps, PostgreSQL Flexible Server and Blob Storage, for about US$30 a month. Every push goes through GitHub Actions: 100 or more tests against a real PostgreSQL database, type checks and linting. If it is not green it does not ship.
The capstone finished. MyMise did not: it now runs as a live product at mymise.com.au, and the nine rules are still growing.
