A production-ready Next.js 15 + TypeScript application for restaurant group ordering. Staff can import menus, configure ordering events, collect customer orders, and monitor the kitchen dashboard with Supabase Realtime updates.
- Node.js 18+
- npm (or pnpm/yarn)
- Supabase project (Postgres + Realtime enabled)
- Optional: Resend account for transactional email
- Install dependencies:
npm install
- Copy environment variables:
cp .env.local.example .env.local
- Populate
.env.local:NEXT_PUBLIC_SUPABASE_URL= NEXT_PUBLIC_SUPABASE_ANON_KEY= SUPABASE_SERVICE_ROLE_KEY= ADMIN_PASSCODE=change-me RESEND_API_KEY= EMAIL_FROM=orders@example.com RESTAURANT_NOTIFICATION_EMAIL=team@example.com RESTAURANT_NAME="Example Kitchen" RESTAURANT_TZ="America/Chicago"RESEND_API_KEY,EMAIL_FROM, andRESTAURANT_NOTIFICATION_EMAILare optional; the app logs stubbed emails when they are not supplied. - Create the database schema in Supabase:
or paste the migration into the Supabase SQL editor.
psql "$SUPABASE_CONNECTION_STRING" -f supabase/migrations/0001_initial.sql - Seed the sample menu (optional but useful for local testing):
npm run seed
- Start the dev server:
Visit
npm run dev
http://localhost:3000for the customer flow,/admin/loginfor staff, and/kitchenafter authenticating.
Sample data lives in /data/menu.yaml and /data/menu.csv. Upload either file from /admin/menu-import to load categories, items, options, and option values. Imports compute a diff (created / updated / removed) and upsert records so incremental edits are safe. Re-run imports any time you tweak prices or modifiers.
CSV headers expected by the importer:
category,category_sort,item_id,item_name,item_desc,price,sku,item_sort,opt_group,opt_type,opt_required,opt_label,opt_price_delta
/events: Public calendar showing OPEN and UPCOMING events./menu: Customer menu with modifier dialogs, cart drawer, and checkout redirect when an event is open./checkout: Validates customer details and places the order via Supabase service role pricing./success: Lightweight confirmation page with pickup code./admin+/admin/events+/admin/menu: Staff tools for events and item visibility./admin/menu-import: YAML/CSV importer with diff summary./kitchen: Tablet-friendly dashboard with realtime updates and aggregate counts.
- Safe-area aware bottom bars for the menu cart and checkout submission flows.
- Responsive customer pages (
mx-auto max-w-screen-sm px-4) with single-column layouts that scale gracefully. - Bottom sheet + desktop modal pairing for menu customization, plus collapsible mobile cart drawer.
- Sticky segmented control on the kitchen dashboard (
Pending → Preparing → Ready → Picked up) with realtime highlights and audible chimes for new orders. - Inline Sonner toasts for add-to-cart, status changes, and checkout success/failure feedback.
- Skeleton
loading.tsxfiles for events, menu, and kitchen to eliminate perceived loading jank.
- Global design tokens live in
src/app/globals.css(--bg,--card,--primary,--ring,--radius,--shadow-*). Tweak these variables to restyle the app without editing components. - Utility classes (
.btn*,.input,.card,.safe-top,.safe-bottom, etc.) are also defined inglobals.cssunder@layer utilitiesfor reuse across pages. - UI primitives (Button, Card, Input, Dialog) live in
src/components/ui/—extend these components to add new variants or sizes instead of sprinkling bespoke Tailwind classes. - Customer flows should stay within
mx-auto max-w-screen-sm px-4containers; staff/kitchen views usemx-auto max-w-screen-lg px-4. - The responsive
Dialogcomponent supportsvariant="center"(modal),variant="bottom"(sheet), andvariant="sidebar"(drawer) for consistent overlay behavior.
- Lint:
npm run lint - Type check + build:
npm run build - Playwright end-to-end smoke tests:
npm run test:e2e- Requires the dev server running (
npm run dev), seeded data, andPLAYWRIGHT_E2E=truein the environment to opt-in. - Tests live in
tests/playwright; manual acceptance steps are documented intests/ACCEPTANCE.md.
- Requires the dev server running (
Order confirmations are sent to the customer and mirrored to RESTAURANT_NOTIFICATION_EMAIL when Resend credentials are available. Without credentials the app logs stub messages to the server console.
- Push to GitHub and connect the repository to Vercel.
- Set the following environment variables in Vercel (all “Production” and “Preview” scopes):
NEXT_PUBLIC_SUPABASE_URLNEXT_PUBLIC_SUPABASE_ANON_KEYSUPABASE_SERVICE_ROLE_KEYADMIN_PASSCODERESEND_API_KEY(optional)EMAIL_FROM(optional)RESTAURANT_NOTIFICATION_EMAIL(optional)RESTAURANT_NAMERESTAURANT_TZ
- Run
npm run buildduring the Vercel build step. - In Supabase, enable Realtime for
ordersandorder_items(already in the migration). - After deploying, run the menu seed once (via
npm run seedlocally or the admin importer) to populate baseline data.
src/lib/menu-import.ts– CSV/YAML parsing, diffing, and Supabase upserts.src/lib/orders-service.ts– Server-side pricing, order creation, summary utilities, and realtime broadcasting.src/components/menu/menu-client.tsx– Customer menu composer and cart drawer.src/app/(staff)/kitchen– Realtime kitchen dashboard with status controls and aggregates.scripts/seed-menu.ts– Optional CLI seed that importsdata/menu.yaml.
Manual smoke testing steps are captured in tests/ACCEPTANCE.md and cover menu imports, event creation, customer orders, kitchen updates, item visibility toggles, and menu refreshes.