Benny.mk — Benefits Beyond the Office

7/11/2026

Benny.mk — Benefits Beyond the Office

Screenshots below are from the real product running against a seeded demo dataset — every company, merchant, employee, discount and transaction shown is generated demo data.

Overview

Benny is an employee-benefits and discounts platform built for North Macedonia — "Benefits Beyond the Office. Scan. Save. Enjoy." Companies take out a single subscription and invite their team; employees use the Benny app to unlock everyday discounts (always at least 10%) at partner restaurants, cafés, bars, bakeries, dessert shops, fast-food spots and pubs across Skopje. Merchant staff complete each discount with a quick QR scan at the table, and the Benny team runs the whole marketplace from a separate admin console.

It's a complete, production-shaped product spanning five surfaces on one API, fully bilingual (English + Macedonian), with money in MKD and every time-based rule computed in Europe/Skopje.

The benny.mk landing page — "Benefits Beyond the Office"

The product at a glance

Benny is a monorepo of four apps talking to one backend and one database:

benny.mk            Public marketing site + company & merchant dashboards   (React + Vite)
admin.benny.mk      Internal operations console                             (React + Vite)
mk.benny.app        Employee + merchant-staff mobile app, role-aware        (Expo / React Native)
api                 REST API, JWT auth, 8-role RBAC, billing & QR engine    (Express 5 + MongoDB)

Everything is invite-only — there is no public sign-up. A company admin invites employees by email or a single-use 48-hour link; a merchant owner invites their managers and waiters the same way. One users collection, one login endpoint, and role-based routing decide which of the five experiences a person actually sees.

The employee app

The heart of the product is the phone in the employee's pocket. After a bilingual onboarding, employees land on a home feed personalised to their company, browse and search partner venues, open a venue to see its live discounts on a map, and — the payoff — generate a one-time discount code to show the waiter.

Employee home feed with personalised deals Search and filter partner venues Venue detail with active discounts and map

The home feed leads with the employee's running savings total and their company badge, then a banner carousel, "Best deals", and "New on Benny". Search offers a list/map toggle with category and service-type filters. Each venue page shows its scheduled and fixed discounts, opening the exact time windows (e.g. Happy Hour −25%, Mon–Fri 17:00–19:00), a description in both languages, and a live Google Map pin.

Every redemption lands in the employee's Activity history — original price, discount applied, amount saved, and the running total — so the value of the benefit is always visible.

Bilingual onboarding carousel Savings history with per-visit breakdown Account menu with company and profile

The signature move — the QR discount flow

Benny's core interaction is a two-sided QR handshake designed so a customer can never fake a discount and a waiter never has to do math. All tokens are minted server-side and every discount is calculated on the server — the client only ever displays what it's told.

Scanner pointed at the venue's Benny QR code Manual venue-code entry fallback The employee's one-time discount QR with 5-minute countdown
  1. The venue displays a persistent printed QR (with a short code for anyone who can't scan).
  2. The employee scans it — or types the code — and the server computes the discount right now based on that venue's schedule, defaulting to its base rate outside any window, but never below 10%.
  3. Benny issues a temporary customer QR that lives for five minutes with a visible countdown, plus a SFV-3T7-style manual code.
  4. The waiter scans that customer code, enters the receipt total, and the server returns the final price. The completed transaction instantly flows into the employee's history, the merchant's analytics, the company's savings, and the admin ledger.

Because both codes are opaque server tokens and each state transition is an atomic conditional update, the flow is safe against replay, double-redemption, and client tampering.

The in-venue app — for merchant staff

The same binary is role-aware: a waiter or manager signs in and gets a stripped-down point-of-sale surface instead of the consumer feed. It opens straight to "Scan customer code", with a manual fallback, today's orders / discounts / revenue at a glance, and a running list of the day's transactions.

Merchant-staff home — scan customer code and today's totals

The company dashboard

Company admins and managers run their benefit from a web dashboard on benny.mk. The overview surfaces the numbers a people-ops or finance lead actually cares about: active employees, pending invites, the estimated monthly cost including 18% VAT, total transactions, and total savings delivered to the team — with a usage chart and a "where your team saves the most" leaderboard.

Company overview — active employees, monthly cost, savings and usage

Employees are invited by email or single-use link and can be enabled or disabled at any time — and only active employees are billable, which is the rule the whole billing model turns on. Analytics break down adoption and savings over time.

Company employees — invite, enable/disable, device reset

Billing is fully self-serve to inspect: the current plan, a live active-employee count, the next-invoice estimate, and a history of issued invoices — each one a proper bilingual document with line items, VAT, due dates, and payment status.

Company billing overview A single bilingual invoice with VAT and payment status

The merchant dashboard

Partner venues get their own dashboard to manage everything about their presence. The overview tracks today's and this month's redemptions and revenue; discounts can be a simple fixed percentage or a scheduled window (day-of-week + time range, always ≥10%).

Merchant overview — today and month to date Fixed and scheduled discounts

The QR code page renders the venue's printable code and short code (with a "print table tent" action), staff are invited and managed here, and the profile editor carries the bilingual description, business type, service tags, gallery, and a drag-the-pin Google Map location that powers the app's map search.

Printable venue QR and manual short code Merchant analytics — averages, weekday and hourly patterns

Business model & the venues

Benny is a B2B subscription: a company pays a flat 199 MKD per active employee per month (+18% VAT) on the Standard plan, and its whole team gets access to every partner discount. Merchants join to drive footfall and repeat visits from a captive, benefit-holding audience — they set their own discounts and pay nothing.

Partner venues are organised into the categories employees browse by — restaurants, cafés, bars, bakeries, dessert shops, fast food and pubs — each an admin-managed "business type" with its own search synonyms.

Restaurants Cafés Bars Bakeries Dessert shops Fast food

Billing & invoicing

The billing engine is a monthly cron job. On the 1st of each month it generates one invoice per company for the previous period: active-employee count × plan price, plus 18% VAT, with sequential numbers like BEN-2026-000042 and a 14-day due date. Invoices are rendered as bilingual PDFs, settled offline by bank transfer, and marked paid by an admin with a payment reference. The admin console tracks the whole lifecycle, including an "overdue" state.

Admin invoices — generate, track, mark paid A generated invoice with VAT and bank reference

The admin console

The Benny team operates the marketplace from admin.benny.mk. The overview is a live pulse of the platform — companies, active employees, merchants, transactions, platform-wide savings, pending/paid invoices and a revenue estimate — over a feed of the latest transactions across every venue.

Admin overview — the whole platform at a glance

From there, admins manage every company and merchant (including regenerating a venue's QR), inspect users and the full transaction ledger, run and reconcile billing, and configure plans, banners, business types and platform settings.

Admin merchants list Admin merchant detail

Roles, access & security

Benny runs on eight roles from a single users collection: SUPER_ADMIN and ADMIN (admin console); COMPANY_ADMIN and COMPANY_MANAGER (company dashboard); EMPLOYEE (mobile); and MERCHANT_OWNER, MERCHANT_MANAGER and MERCHANT_STAFF (merchant dashboard and/or the staff app). A single login endpoint routes each person to the right surface.

Access is deliberately tight: invite-only onboarding with single-use, 48-hour-expiring links; device-locked employee accounts (an X-Device-Id binding) to stop benefit-sharing; server-authoritative discount math; and non-enumerating password resets.

Architecture & tech

  • Backend — Node.js + Express 5, MongoDB/Mongoose, JWT auth, 8-role RBAC. Services for the scan state machine, discount calculation, billing, PDF invoices (pdfkit), analytics rollups, QR tokens and transactional email (Resend). Cron jobs generate invoices and expire invites.
  • Web & adminReact + Vite + Tailwind, react-i18next for full EN/MK bilingual UI, Google Maps for location pickers, same-origin API via a dev proxy.
  • MobileExpo / React Native with expo-router, a single role-aware binary, expo-camera QR scanning, react-native-maps, SecureStore-held JWT, and universal/app links (benny://, benny.mk) so an invite opens straight into the app.
  • Data model — Users, Companies, Merchants, Discounts, Invites, Invoices, ScanSessions, Transactions, SubscriptionPlans, Banners, BusinessTypes and daily analytics rollups, with a seed that builds an entire realistic demo world (companies, employees, ten real Skopje venues, discounts, ~120 transactions and two months of invoices).

What made it work

Benny's difficulty was never any single screen — it was coherence across five surfaces and eight roles without drift. Three decisions carried it: one API with strict role-based routing so every client is a thin view over the same truth; a server-authoritative QR engine so discounts can't be gamed and the two-sided scan "just works" at a busy table; and treating bilingual + MKD + Skopje-timezone as first-class from day one rather than a retrofit. The result is a benefits marketplace that feels effortless to the employee, trivial to the waiter, and fully accountable to the company and the operator.

Deliverables

  • Public marketing site (benny.mk) — bilingual EN/MK landing, perks, FAQ, legal, deep-link invite fallback
  • Company dashboard — employee invites, enable/disable, savings analytics, billing + PDF invoices
  • Merchant dashboard — fixed & scheduled discounts, printable venue QR, staff, transactions, analytics, map profile
  • Internal admin console — companies, merchants, users, transactions, invoicing, plans, banners, business types
  • Role-aware iOS/Android app (Expo/React Native) — employee discovery + QR redemption and merchant-staff checkout
  • QR discount engine — dual-token scan flow, server-side discount math (always ≥10%), Europe/Skopje scheduling
  • Monthly billing engine — per-active-employee invoicing + VAT, cron generation, bilingual PDF invoices
  • Node/Express/MongoDB API — 8-role RBAC, invite-only onboarding, device-locked anti-sharing

Links