Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

40 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

TRQR Logo

Restaurant Management System with Digital QR Menus

Menu management, table tracking, payments, and analytics — all in one dashboard.

Status Stack i18n License


Live Demo · Features · Tech Stack · Architecture · Plans · Screenshots


Overview

TRQR is a full-stack SaaS platform for restaurant management. At its core is a QR-based digital menu system — guests scan the table QR code, browse the menu instantly on their phone, and place orders with no app download required.

But TRQR goes well beyond menus. Restaurant owners get a complete operational dashboard: manage tables and live orders, track payments with split-bill support, monitor revenue and traffic analytics, design and print branded QR tabletop cards, and configure the entire system in Turkish or English — all in real time from a single interface.

Built with a strong emphasis on production security, plan-based access control, and a clean, fast user experience.


Features

For Restaurant Owners

Feature Description
Menu Builder Drag-and-drop category and item editor. Add names, prices, descriptions, and photos. The price field accepts both Turkish and English number formats (decimal comma or dot, thousands grouping) and echoes the parsed amount back live, so "2.500" is never silently stored as ₺2.50. Toggle a single item — or a whole category — to "out of stock" ("86") instantly; unavailable items are greyed out on the public menu and blocked from new orders.
AI Menu Import (Starter and above) Getting a menu into the system is the biggest friction at signup, so it can be done from a photo. Upload up to 10 photos of a printed menu — or a single PDF — and a vision model returns a structured draft: categories, item names, descriptions and prices. Nothing is written until the owner reviews it. The provider is behind an adapter (AI_PROVIDER / AI_MODEL are env vars, no SDK dependency), and the model's answer is never trusted: every response is validated against a Zod schema server-side, with one automatic repair retry that feeds the concrete validation errors back to the model. Turkish price formats are the hard part and are handled explicitly — 1.250,00 TL becomes 1250, never 1.25. Rows the model cannot read are skipped and reported, never guessed, and the review step leads with that list. Spend is capped by plan gate, per-actor rate limit, and a per-restaurant daily quota on the Istanbul business day; failed attempts are refunded. Uploaded images are analysis input only and are never stored.
Guest Menu Experience The customer-facing menu is built for someone standing at a table with a phone. Search appears on menus past 12 items and folds Turkish letters both ways — a guest typing "cig kofte" finds "Çiğ Köfte", and "ispanak" matches an item written "ISPANAK" — matching on name, description, English translation or category, in any word order. Dietary badges (vegan, vegetarian, gluten-free, lactose-free, contains-nuts, three spice levels) render on the row and in a tap-to-open item detail sheet with the full photo, description and price. A TR/EN switch appears once any item has an English translation and is remembered per restaurant on that phone. All of it works on every plan, Free included, and across all six templates.
Menu Design Dedicated Menu Designer page with live preview (separate from Restaurant Settings). Six professionally designed templates, each with a matching QR tabletop card design. Template access gated by plan tier.
QR Code & Tabletop Designer Unique QR code per restaurant with a built-in tabletop card designer. Preview all templates live, customise the card message, and export as PDF in A5, A6, or Square format. When a custom menu URL is set, the QR code encodes the slug URL; falling back to the UUID-based public URL otherwise.
Custom Menu URL Pro and Enterprise restaurants can define a short, memorable slug for their public menu (e.g., trqr.net/menu/yildiz-restoran). Real-time availability checking with debounce. Slug is revoked automatically if the restaurant's plan falls below Pro after the grace period.
Print Menu Export the full restaurant menu as a print-ready PDF. Choose template and paper size; preview renders live in the browser before export.
PDF Menu (Pro and Enterprise) Upload a PDF and serve it on the public menu link instead of the interactive templates — ideal for restaurants that already have a professionally designed menu. Guests get a mobile-friendly viewer that renders the PDF page-by-page to a canvas as they scroll (so a long menu never freezes a low-RAM phone and the first page shows immediately), with a "page N / total" indicator and an open-in-new-tab escape hatch. Switching between interactive and PDF mode is an explicit save, and the public view automatically falls back to the interactive menu if the plan drops below Pro.
Table Management Configure table count, assign custom names (e.g., "Garden", "VIP 1"), track per-table orders, merge tables, transfer a whole table or move individual items between tables, and close bills in one tap. Order state survives a merge/transfer (a pending item never silently becomes "served").
Staff & Kitchen System Owner-managed staff accounts with 6-digit PIN login (waiter / kitchen / cashier / manager roles, plus per-user permission overrides). A mobile waiter app for taking orders and collecting payment at the table, and a live Kitchen Display System (KDS) with thermal ticket printing. Available from the Starter plan; staff seat count scales with the tier.
Payment Tracking Record full payments, equal splits, or per-item payments. Apply percentage discounts at checkout; all transactions stored with full line-item detail. Payments are atomic — the sale record and the table update commit in a single transaction, totals are recomputed server-side (the client total is never trusted), and each pay action carries an idempotency key so a dropped network response can't double-charge. Receipts are numbered uniquely per restaurant per day.
Order from the Table (QR) (Pro and Enterprise) Guests scan their table's own QR and order from the menu; payment stays at the register. Off by default; an approve mode (default) holds every guest order for one-tap waiter approval — it reaches neither the kitchen nor the bill until accepted — while auto mode sends straight to the kitchen. Table QRs are signed credentials (HMAC over table id + a reprint counter): reprinting from the dashboard instantly kills every previously printed code. Prices are always resolved server-side through the same campaign-aware engine as waiter orders; the guest payload carries no prices at all. Includes a per-table on/off switch, an A4 print sheet of all table QRs, layered rate limits, and a once-a-minute "call the waiter" bell that alerts the waiter app.
Campaigns & Happy Hour (Pro and Enterprise) Scheduled, scoped discounts that apply themselves. Define a percentage off, a fixed amount off, or a flat price; scope it to the whole menu, selected categories or selected items; schedule it by weekday and time window (overnight windows like 22:00–02:00 wrap correctly and belong to the day they started); optionally bound it by calendar dates. The public menu shows a "-%20" discount badge and the live discounted price (kuruş-exact) next to the struck-through base price — and the menu editor shows the same live price on each item row — while the order path bills it automatically — with a session lock: a table that opens during happy hour keeps its discount for the whole sitting, even after the window closes. At most one campaign applies per line (the most advantageous price wins — a campaign can never make an item more expensive), the discounted price flows into the receipt with its campaign provenance, and day-end reporting shows exactly how much each day's campaigns gave away, separate from manual discounts.
Menu Header Carousel (Pro and Enterprise) A swipeable strip of photos at the very top of the public menu — campaign posters, the room, the dish of the day — working across all six templates, each passing its own accent so the controls look native. It advances on its own but pauses on hover, while the guest drags, and whenever the tab is hidden, and honours prefers-reduced-motion by dropping the motion while keeping arrows and dots usable. A single photo becomes a fixed banner; with none uploaded every template renders exactly as before. Owners upload, reorder and remove from the Menu Designer. Photos are validated by their actual bytes, capped per plan, and the internal storage path is never exposed on the public menu.
Portion-Priced Items One menu item can carry several priced portions — Yarım/Tam, Küçük/Orta/Büyük — instead of needing a separate item per size, which duplicated the photo and description and burned the per-category item limit twice for one dish. The menu shows a "from" price and the guest picks a portion when they order; waiters and the dashboard pick the same way. A portion can sell out on its own while its siblings keep selling, campaigns discount each portion on its own price, and the receipt records which portion was sold. Ordering a portioned item always requires naming a portion: the server refuses rather than defaulting, because putting the wrong size on a bill is silent. Available on every plan.
Extras & Options Choices a guest adds to a line — "+extra cheese ₺15", "no onions", "extra sauce" — grouped, each with its own price difference, and each able to sell out on its own. A guest picks them in the same sheet as the portion, with the line total updating as they choose; waiters and the dashboard pick from chips. Ordering an extra the menu can't honour is refused rather than dropped, because dropping one under-charges while the kitchen still makes it. A campaign discounts the dish by default and reaches the extras only when that campaign says so — halving a ₺15 cheese the kitchen still buys is a margin loss nobody agreed to. Available on every plan.
Comp & Void Take an individual line — even an already-served dish — off the bill as a comp (complimentary, e.g. a quality complaint) or a void/return (wrong item), quantity-aware and with a mandatory reason. Removed lines stay visible on the bill (struck through) for transparency but are never charged. Gated by the discount permission; a non-manager needs a manager's PIN (a manager taps in, or an owner-set restaurant override PIN) to go past the restaurant's configurable approval threshold (default 5%) — no flat ceiling, and the PIN itself is brute-force-locked. Every adjustment is idempotent and lands in an append-only ledger that records who approved it.
Receipt History Every completed payment stored as a numbered receipt (YYYYMMDD-NNNN). Filter by date/payment method, view itemised details, export individual receipts as PDF.
Day Summary Report Aggregate report for any calendar date: orders, revenue, cash/card split, avg order value, discounts, comps / voids / food-waste totals, top items, and top adjustments by value. Exportable as PDF.
Day-End Report Email (Pro and Enterprise) Opt-in daily email of the day-end summary — revenue, receipts, cash/card, comps/voids, top 5 products — sent automatically after each Istanbul business day closes, at an owner-chosen hour. A self-healing hourly job derives the target day and "already sent?" from state (so a missed run is caught next tick, and double-ticks never double-send); days with no sales are skipped, so inactive accounts aren't mailed. Shares one aggregation service with the on-screen Day Summary, so the numbers match exactly.
Analytics Dashboard Daily views, revenue trends, top-selling items, and hourly traffic distribution — all with date range filtering (Today / This Week / This Month / Custom).
Subscription Management In-dashboard plan management with live plan status, trial countdown, grace period warnings, and a direct upgrade path.
Onboarding Wizard Step-by-step setup checklist for new restaurants: name, first item, menu preview, QR download. Dismissible once complete.
Multi-Currency Set the display currency (TRY ₺, USD $, EUR €, GBP £) from Restaurant Settings. Currency symbol updates everywhere: table management, payment steps, receipts, analytics, print export, and the live public menu.
Bilingual UI Full Turkish and English support throughout the entire dashboard, public menu, and email flows.

For Guests

  • Instant menu access by scanning the table QR code — no app install
  • Clean, responsive menu display on any device
  • Category-based navigation with item photos, prices, and descriptions
  • Template-matched visual design consistent with the restaurant's brand
  • "Powered by TRQR" watermark shown on menus from Free and Starter plans; automatically removed for Pro and Enterprise restaurants

For Staff (Waiters & Kitchen)

  • PIN login at /staff/login — staff sign in with the restaurant's menu slug (or ID) + username + 6-digit PIN, independently of the owner account, on shared phones and tablets
  • Waiter app (mobile-first) — table grid with live occupancy and an "awaiting payment" state, take orders with quantity steppers and per-item notes, send to kitchen, mark items served, and collect payment (full / equal split / per-item, with discounts)
  • Comp / Void at the table — pull an individual line (including a served dish) off the bill as a comp or a void/return with a reason, right from the table detail screen; gated by permission, and anything past the restaurant's approval threshold (default 5%) prompts for a manager PIN inline
  • Kitchen Display System (KDS) (tablet) — live order tickets grouped by table with elapsed timers, mark a whole ticket ready in one tap, and auto-print to a WebUSB thermal printer. The print queue survives a yanked cable (offline queue in localStorage) and recovers from a bad ticket: one that repeatedly fails at the USB level is set aside so it can't wedge the tickets behind it, with a "couldn't print" warning to reprint by hand
  • Offline-aware — a persistent banner appears across the waiter and kitchen apps the moment the connection drops, so staff know it's the network, not the app; a failed request surfaces a clear "connection lost" message instead of failing silently
  • Open Orders view — preparing and ready items grouped by table, with a buzz + toast the moment the kitchen marks something ready
  • Day-end report — managers and cashiers can pull a shift/day summary (orders, revenue, cash/card split) from the staff app, scoped to their restaurant and computed on the Istanbul business day
  • Role- and permission-based — every action gated by the staff member's effective permissions; assigned-table mode scopes a waiter to their own tables
  • Bilingual — Turkish / English switch right in the staff login, waiter, and kitchen app bars

For Platform Admins

  • Full restaurant and user management
  • Per-restaurant plan overrides and feature flag control
  • Immutable audit log with actor, IP, HTTP context, and before/after diff
  • Platform-wide analytics overview

Screenshots

Dashboard

Menu Builder Analytics
Menu Builder Analytics
QR Code & Tabletop Table Management
QR Code Tables
Print Menu Restaurant Settings
Print Menu Restaurant Settings
Menu Designer
Menu Designer

Public Menu — 6 Templates

Classic Minimal Modern
Classic Minimal Modern
Rustic Elegant Aurora
Rustic Elegant Neon

Mobile

Mobile Menu Mobile Dashboard
Mobile Menu Mobile Dashboard

Marketing Pages

Landing Page Pricing
Landing Page Pricing

Staff & Kitchen App

Staff PIN Login Waiter Tables
Staff Login Waiter Tables
Open Orders (grouped by table) Kitchen Display (KDS)
Open Orders Kitchen Display
Collect Payment
Collect Payment

Authentication

Login & Sign Up
Login

Tech Stack

Frontend

Layer Technology
Framework React 19 + TypeScript 5.8
Build Tool Vite 6
UI Components Material UI (MUI) 7
Styling Emotion (CSS-in-JS)
Routing React Router 7
Animations Framer Motion 12
Drag & Drop dnd-kit
i18n i18next + react-i18next
PDF Export jsPDF + html2canvas
SEO React Helmet Async
CAPTCHA Cloudflare Turnstile
HTTP Client Axios
Testing Vitest + Testing Library

Backend

Layer Technology
Runtime Node.js 22
Framework Express 5
Database PostgreSQL 16
ORM Sequelize 6
Caching / Token Blacklist Redis (ioredis)
Authentication JWT + HTTP-only refresh tokens
Validation Zod 4
File Uploads Multer 2
Logging Pino (structured JSON logs)
Scheduled Jobs node-cron
Password Hashing bcryptjs
Testing Jest 30 + Supertest

Infrastructure

Layer Technology
Containerization Docker + Docker Compose
Reverse Proxy Nginx
CDN / DDoS Protection Cloudflare
Deployment VPS with Nginx + SSL
Environment Config .env file per environment

Architecture

graph TD
    A[Internet] --> B["Cloudflare\nCDN · DDoS Protection · Turnstile"]
    B --> C["Nginx\nReverse Proxy · TLS Termination"]
    C --> D["React SPA\nVite · TypeScript · MUI"]
    C --> E["Express API\nNode.js 22 · JWT · Zod · Pino"]
    E --> F[("PostgreSQL 16\nSequelize ORM")]
    E --> G[("Redis\ncache · token blacklist")]
    E --> H["File Storage\nmenu item images"]
Loading

See docs/architecture.md for detailed component descriptions.


Menu Templates

TRQR includes six professionally designed menu templates. Each template has a matching QR tabletop card design for print export.

Template Tier Style
Classic Free Warm serif typography, cream/tan tones
Minimal Free Clean sans-serif, monochromatic
Modern Starter Bold gradient, vibrant accent color
Rustic Starter Earthy tones, dashed borders, handcrafted feel
Elegant Pro Dark luxury design, gold accents
Aurora Pro Deep indigo-violet gradient, frosted-glass cards

Subscription Plans

Every new account starts on the Starter plan — free for the first 5 days. No credit card required. After the trial, accounts automatically move to the Free plan unless upgraded. A 3-day grace period follows expiry before any data is trimmed.

Free Starter Pro Enterprise
Price ₺0 ₺1,999 ₺999 / mo ₺2,999 ₺1,499 / mo Custom
Trial 5 days free
Tables 5 15 40 100
Categories 5 15 30 50
Items per Category 15 30 50 100
Items with Photos 12 60 200 1,000
Templates Classic, Minimal + Modern, Rustic + Elegant, Aurora All
Analytics Basic Standard Advanced Premium
Payment Tracking
Staff Accounts 3 10 50
Waiter App + Kitchen Display (KDS)
Data Export
Remove Branding
Priority Support
Custom Menu URL
Menu Search, Dietary Badges, TR/EN Menu
AI Menu Import
Campaigns & Happy Hour
Menu Header Carousel 8 photos 12 photos
Portion-Priced Items
Extras & Options
Order-from-Table via QR
PDF Menu
Day-End Report Email
Custom Domain

Plan limits are enforced server-side — no client-side bypassing.


Security Highlights

TRQR is built with a production security mindset throughout.

  • No account enumeration — Login returns a single generic error for both an unknown identifier and a wrong password (the miss path burns a cost-matched bcrypt so response time doesn't leak account existence either), and resend-verification answers an unknown address exactly like a real one. The full reason still lands in the audit log for investigation.
  • Progressive CAPTCHA, outage-safe — Cloudflare Turnstile is triggered after repeated failed login attempts (hard block past the threshold); verification fails safe on a provider outage — a 5 s timeout returns 503 with Retry-After rather than hanging the request or wrongly rejecting a human.
  • Rotating refresh tokens with reuse detection — Short-lived access tokens; HTTP-only cookie refresh tokens that rotate on every use. A replayed (already-consumed) refresh token is treated as a stolen-cookie signal and force-logs-out the account, with a short grace window so a benign multi-tab/reload race doesn't trip it. Password change/reset invalidate every other live session. The legacy plaintext refresh column has been dropped — the JWT signature plus Redis revocation are the sole source of truth.
  • Single-use SSE stream tickets — The realtime (Server-Sent Events) channel is authenticated with a short-lived, single-use ticket instead of the access token, so the token never lands in a URL, proxy log, or browser history.
  • Manager-PIN approval, brute-force locked — Over-threshold discounts/comps/voids require a manager PIN (or an owner-set override PIN); the check is rate-limited and locks out after repeated failures. A manager can set a dedicated approval PIN distinct from their login PIN, so the code entered in front of other staff to approve an adjustment never doubles as a login credential.
  • Thermal-printer command hardening — Kitchen-ticket text (item names, notes, table/waiter labels) is stripped of control bytes before it reaches the ESC/POS encoder, so a crafted order note can't smuggle printer commands (drawer-kick, cutter) into the byte stream.
  • Zod Validation — All incoming API data validated against strict schemas before reaching business logic; JSONB row payloads are whitelisted (no passthrough) so client junk can't accumulate in the database.
  • XSS Sanitization — Recursive sanitization on every request body, query, and params
  • Helmet + Nginx headers — Full HTTP security header set (CSP, HSTS, X-Frame-Options, nosniff, referrer policy), with the edge headers centralised so a per-location cache rule can't silently drop them.
  • Rate Limiting, per-actor — Tiered limiters per endpoint category (auth, uploads, global). Authenticated traffic is keyed by verified actor id rather than IP, so a whole restaurant behind one NAT isn't throttled as a single client; guest menu views get their own wider bucket.
  • HPP Protection — HTTP Parameter Pollution prevention
  • Request Correlation — Every request gets a UUID at ingress; propagated to audit logs
  • Immutable Audit Log — Every meaningful server action is logged with actor, IP, HTTP context, resource, and before/after diff; retained on a rolling window by a scheduled cleanup job
  • Plan Enforcement — Server-side middleware validates feature access and resource limits on every mutation
  • Dependency hygiene — Both the client and server dependency trees audit clean (0 known vulnerabilities), kept current as part of routine maintenance.

Internationalization

Full bilingual support in Turkish and English — including dashboard, error messages, email flows, and the public menu page.

Language is configurable per restaurant and switchable in the dashboard at any time.


Demo

🌐 Live Product: https://trqr.net


Source Code

This repository is a public showcase only. The application source code is private.

TRQR is a commercial product. The source code — including the frontend, backend, database migrations, infrastructure configuration, and all business logic — is maintained in a private repository and is not available for public access or contribution.

This showcase exists to document the product's architecture, features, and technical decisions for portfolio and reference purposes.

For licensing inquiries, collaboration, or white-label arrangements, please reach out via the contact section below.


About

Built and maintained by Salih Yıldız.


TRQR — Bringing restaurant menus into the digital era.

About

TRQR — Full-stack restaurant management SaaS. Digital QR menus, table & order tracking, payment splits, analytics, and print export. React 19 + Node.js + PostgreSQL. Public showcase, source is private.

Topics

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors