Orderly
QR ordering, payments, and POS — for restaurants, retail, and any business with a counter or a table.
Project spec · 6 fields+
Overview
Orderly is a contactless ordering and POS platform for restaurants, retail, and any business serving customers in person. Customers scan a QR code at a table or counter, browse a digital menu or product catalog, and place orders directly — no app download, no account, no waiting for staff to take the order.
On the operations side, every order flows into a real-time queue — a Kitchen Display System for kitchens, a fulfillment view for retail counters — and staff handle table status, pickup, and payments through a single dashboard.
The brief
The post-pandemic shift toward contactless ordering created demand that most merchants couldn't meet with off-the-shelf POS add-ons. Existing solutions were either expensive enterprise systems or consumer apps that put the merchant's brand and data behind a third-party wall.
The brief was a merchant-first platform: the customer experience needed to feel like the merchant's own product, while the operational tooling needed to be simple enough for a cafe owner or shop manager to configure themselves and hand to staff on day one. One stack, multiple verticals, no per-vertical compromises.
Build
The stack is Nuxt 4 + Prisma over PostgreSQL with Redis for rate-limit and cache state, deployed on Fly.io. The auth, organization, and billing foundation isn't bespoke — Orderly ships on top of `@xyz/nuxt-auth-layer`, our own reusable Nuxt package with OAuth, MFA (TOTP + QR), password policies, RBAC, audit logs, and per-route rate limiting baked in. Building Orderly meant adding the domain layer on a foundation that already handled identity correctly.
The data graph models the full merchant operation: `Organization → Venue → Table → MenuCategory → MenuItem` (with variants, modifier groups, and likes), plus `GuestSession → Order → OrderItem → Payment` for the customer side. F&B venues use `Table` as the seating unit; retail venues map it to a counter or pickup point. Inventory is real, not nominal: `RecipeComponent` ties menu items to `InventoryItem`s for kitchens, and `StockMovement` records auto-deduct as orders fire. Multi-tenant by construction — one platform, many merchants under separate `Organization`s with their own venues, tables, and menus.
The product runs as five distinct app surfaces sharing one backend: `/guest` (customer, no auth), `/kitchen` (KDS), `/staff`, `/manager` (merchant owner), and `/admin` (platform-wide). Each surface has its own SSR/CSR strategy in `routeRules`: kitchen and manager need SSR for first-paint correctness; guest cart and checkout are client-only because they're personal stateful flows.
The no-signup constraint is solved with `GuestSession` as a first-class model — separate from `User`, with no email, no password, no recovery flow. Scanning a QR mints a guest session bound to a `Table`; that session carries cart state, order history, and payment intents through to checkout. No account wall, no friction, but every byte of state is still traceable for the operator.
Production hardening is in the codebase, not aspirational: Tap Payments for checkout with cryptographic webhook verification (via our own `@xyz/webhook-verifier` package), Pino structured logging, Vitest unit + integration suites including a dedicated `security-regressions.test.ts`, full `AuditLog` model, RBAC via `Role`/`UserRole`, and per-endpoint rate limits tuned to actual traffic shapes (guest order: 5/min/IP; guest payment status check: 30/min/IP, because the callback page polls every 5s while a payment is pending). Sentry runs server-side via a manual plugin — the `@sentry/nuxt` module triggered a Vite transform-stage hang on this codebase, so we documented the workaround rather than chase the root cause through a launch.
Outcome
Orderly is live at orderly.now. The customer-facing flow ships entirely on the web — no app store, no install, no account — and the operations side ships as a real-time order queue (Kitchen Display System for kitchens, fulfillment view for retail) plus role-based dashboards for staff, managers, and platform admins, all on the same codebase.
The choice we'd defend hardest in v1 is the no-signup constraint. It made bill splitting, tipping, and order recovery harder to implement, but it's the single decision the product hangs on: every byte of friction removed was downstream of refusing to put a signup wall between a customer and the order they're trying to place.
Have a project
in mind?
Tell us what you're building. We respond within 24 hours.