Overview

PDF menus are awkward to update and often difficult to read on a phone. SmartMenu lets a restaurant upload a PDF or several menu images, then uses the OpenAI API to extract and structure the content. The owner can correct or customize the result, create QR codes for the tables, and manage the subscription from a dashboard.
Restaurant owners manage the content in the dashboard. Diners see the public menu after scanning a QR code. I designed the same system to work for a single coffee shop or a franchise with several locations.
Core Features

Subscriptions and payments
I implemented tiered subscriptions with Stripe. Each tier limits the number of active menus and controls access to premium features and OpenAI API usage. Webhooks synchronize payments and cancellations with the Supabase database. The active tier also determines whether a user can remove the "Powered by" watermark or open the advanced analytics.
Public menu pages
Diners often open the menu over a mobile connection, so the public pages (/m/[slug]) use Next.js Server Components. Most of the work happens on the server and the browser receives little JavaScript.
Restaurant Dashboard
The dashboard is where users edit menu items, categories, allergens, and the visual style. It also contains analytics and billing.

Database security
The application uses Supabase and PostgreSQL Row Level Security (RLS). Its policies restrict restaurant owners to their own data. Checks tied to the subscription, including permission to remove the watermark, also run in the database rather than relying on the frontend.
Technologies Used
- Frontend: Next.js 16, Tailwind CSS, Lucide Icons
- Backend: Supabase (PostgreSQL, Auth, Storage)
- APIs: OpenAI API for menu parsing and content generation
- Payments: Stripe (Checkout, Billing Portal, Webhooks)
- Deployment: Vercel
What I learned
This project gave me practical experience with user onboarding, usage limits, and recurring billing. It also showed me that subscription checks such as watermark validation are easier to secure and maintain when they live in the database rather than the frontend.