npm run devβ start Next.js dev servernpm run build/npm run previewβ build and previewnpm run db:pushβ reset database (danger: deletes data)npm run lint:check-fixβAdded prettier and eslint config to format code.- Use can Bun as well.
- You can download if it is not supported
I built a full-stack Digital Menu Management System using the T3 stack (Next.js, tRPC, Prisma, Tailwind, shadcn/ui), Resend (email) with the goal of creating a complete, production-ready menu management workflow:
- Email OTP authentication (Resend integration)
- Restaurant, Category, and Dish management
- Dynamic menu UI with categories, dish previews, spice-level indicators, veg/non-veg markers
- Dialog-based dish creation & editing using use state form + Zod
- QR/slug-based public menu viewer
- Mobile-responsive menu layout with sticky category headers
- Static image selection + reusable components
-
Start with database modelling I carefully designed the Prisma schema using normalized relationships:
Restaurant,Category,Dish,DishCategory,User
-
Build APIs using tRPC
- CRUD for restaurants, categories, dishes
- Server-side validation using zod
- Proper relational creation using Prisma (Dish β Category many-to-many).
-
Frontend development using shadcn/ui
- Created forms using
Zod validations and react local states - Used reusable input components
- Ensured full mobile responsiveness
- Created forms using
-
Menu Viewer
- Smooth category scrolling
- Sticky title
- Dialog pop-up on item click
- Recommended items section based on user interaction
-
Polish & UX
- Error pages (404, error.tsx) with polished UI
- Loading states, skeletons, toasts
- Simple, clean UI with shadcn components
-
VS Code Extensions used:
- Prisma
- Tailwind CSS IntelliSense
- ESLint + Prettier
- TypeScript tooling
- OpenAI ChatGPT (GPT-5.1) (Free Version)
- Cursor (minor autocomplete) (Free version). With paid subscription my productivity will increase
- To speed up UI polishing
- To refine TypeScript validation logic
- To generate reusable components
- To help with Zod schema transformations
I always manually reviewed and corrected all generated output.
Some of the main prompts I used during development:
- βImprove this Next.js error page design using shadcn UI.β
- βWrite a Dialog form using zod + shadcn UI.β
- βCreate reusable components with validation states.β
- βFix TypeScript error: unknown row type in table renderer.β
- βFormat date using a custom fDateTime util and render safely.β
- βBuild a country dropdown using countries-list package.β
I used ChatGPT primarily for architecture and code refinement, not for generating full files blindly.
- Creating clean UI code quickly
- Suggesting Zod patterns (string β number transforms)
- Fixing TypeScript narrowings =* Reusable component patterns
- Debugging some Prisma errors
- Some Zod schemas were wrong (string/number mismatch) β fixed manually
- Gave non-responsive layouts β I optimized for mobile
- Incorrect TypeScript narrowing for unknown β I fixed using
row as { createdAt: ... } - Gave React components without proper key handling β corrected manually
AI was helpful but needed manual supervision, especially around:
- tRPC typing
- Prisma relations
- Shadcn UI component usage patterns
- Show resend email
- Show which email the code was sent to
- Prevent resend when email is missing
- Disabled UI while sending code
- Error toast when API fails
-
Price accepts both string/number β validated β transformed into number
-
isVeg allows:
- true (Veg)
- false (Non-Veg)
- null (Unspecified)
-
Spice level validated + converted from string β number
-
Empty image allowed
-
Category validation (cannot assign categories from another restaurant)
- Ensure restaurant exists
- Ensure categories belong to restaurant
- Prevent duplicate dish-category assignments
- No categories available β show message
- No dishes available β show message
- Menu viewer with empty categories β hide sections gracefully
- Sticky header logic when scrolling between categories
- Handle dish images of varying aspect ratios
- Full responsive fallback pages
- Working back/home navigation
Would add:
- Cloud storage (S3 / Supabase / UploadThing)
- Cropping
- Compression
- Fallback images
To avoid:
- Abuse
- Spam triggers
- API blocks (403 from Resend)
Only owners should:
- Edit restaurants
- Modify dishes
- Delete categories
Useful for restaurants with poor connectivity.
- Dish views
- Category popularity
- Customer behavior insights
- User registration and login via email verification code (OTP)
- Users can create and manage multiple restaurants
- Manage menu categories and dishes (dishes can belong to multiple categories)
- Customers access menus via QR code or shared links
The project uses the following technologies (T3-style stack + additions):
- T3 Stack (Next.js, tRPC, TypeScript, Tailwind CSS)
- Prisma as the ORM
- PostgreSQL (production-ready hosting recommended: Neon β https://neon.com)
- shadcn/ui (component primitives and shadcn-based UI)
- Vercel for hosting
- Resend for transactional email delivery (OTP)
These steps will get the project running locally on Linux / macOS. For Windows, use WSL or adapt commands.
- Clone the repo and install dependencies
git clone https://github.com/Hareesh108/digital-menu-management-system.git
cd digital-menu-management-system
npm install- Create a
.envfile in the project root. Example:
# Postgres database used by Prisma (change the password/port/name as needed)
DATABASE_URL="postgres://postgres:password@localhost:5432/digital_menu_dev"
# JWT secret for session tokens
JWT_SECRET="replace_with_a_long_random_secret"
# Optional - Resend API key for sending real emails (dev falls back to console logging)
# RESEND_API_KEY="re_xxx"
NODE_ENV="development"
- Start a local Postgres database (recommended: Docker)
If you have Docker or Podman installed, run the helper script which reads DATABASE_URL from .env:
./start-database.shAlternatively, run Postgres locally and ensure DATABASE_URL points to it.
- Generate Prisma client and apply schema
# generate the Prisma client
npm run db:generate
# apply schema (choose one)
npm run db:push # push schema without migrations
# or
npm run db:migrate # run migrations (preferred for tracked changes)- Start the development server
npm run devVisit http://localhost:3000
- Verification emails: When
RESEND_API_KEYis present the app will send OTPs via Resend. In development (no API key) the verification code is logged to the server console for convenience. - Sessions: The app uses JWT tokens stored in an httpOnly cookie named
session-token. KeepJWT_SECRETstable across runs. - If you change Prisma schema, run
npm run db:generateand eitherdb:pushordb:migratedepending on workflow.
# Introspect DB into schema.prisma (Optional, depend on the data sync)
npx prisma db pull
# Create the SQL that builds the current schema from an empty DB and write it into a migration folder
mkdir -p prisma/migrations/000000_baseline
npx prisma migrate diff --from-empty --to-schema-datamodel prisma/schema.prisma --script > prisma/migrations/000000_baseline/migration.sql
# Mark this migration as already applied in Prismaβs migration table
npx prisma migrate resolve --applied "000000_baseline"
# Verify status
npx prisma migrate status
# Generate client
npx prisma generate
# Example folder structure after this
/prisma
schema.prisma
migrations/
000000_baseline/
migration.sql
# Any new script change
npm run db:generate
# OR
# Name of the file (add-post-status)
npx prisma migrate dev --name add-post-status
# New migration folder
prisma/
migrations/
20251128134705_add-post-status/
migration.sql
000000_baseline/ (if you used baseline workflow)
migration.sql
schema.prisma
# Verify status
npx prisma migrate status
- Database connection issues: ensure
DATABASE_URLis correct and Postgres is running. Usenpm run db:studioto inspect. - Email not received: set
RESEND_API_KEYor use the console-logged code in dev. - Session problems: ensure
JWT_SECRETis set and consistent.
The app deploys well on Vercel. On Vercel set the DATABASE_URL, JWT_SECRET, and RESEND_API_KEY (if used) in Project Environment Variables.