menu-MENAmenu-MENA
HomePricingBlogContact UsGet Started
The Team page in the admin panel mid-load, showing the sidebar (Menu Editor, Modifier groups, Review queue, Import Menu, Orders, Analytics, Reservations), a branch picker reading Test Restaurant, and a Publish button, with the team table still rendering as gray skeleton placeholders

Who Can Edit What: Owner and Manager Permissions

Multi-Branch & Team

By menu-MENA Team

Published on August 29, 2026


Two roles, no permissions matrix

Open /admin/team as anything other than the account owner and the page bounces you straight back to the dashboard. That redirect is the whole story of how permissions work here: there isn't a settings screen with a grid of checkboxes for "can edit menu," "can view orders," "can manage billing." There's owner, and there's manager, and the type that backs both of them in the codebase is exactly two strings: 'owner' | 'manager'. Owner is whoever's Firebase uid matches the tenant's ownerId field. Manager is anyone the owner invited, full stop, no self-signup path exists for joining someone else's account.

What stays owner-only

A handful of pages and actions check for owner specifically, not just "someone with access." Team management itself. Billing and the subscription plan. The public API key. The custom domain setting. The audit log. Adding or deleting a branch. Copying a menu from one branch to another, or pushing a menu update out to multiple branches at once. And the aggregate analytics view that adds up scans and views across every branch in one chart. None of that opens up no matter how a manager's access is scoped, because the server checks the role directly on those requests, not the branch.

What a manager can actually do

Everything else on the branch they're scoped to: the menu editor, item prices, sold-out toggles, modifier groups, orders, reservations, coupons, theme and template settings for that branch's public page. The mechanism is one shared function, resolveEditableTenantFromCookie, that every write endpoint in the admin API calls before doing anything. It resolves who's asking and what tenant they're asking about, and returns either owner-with-no-restrictions or manager-with-a-branch-scope. A route that needs to be owner-only adds one line on top of that: if the resolved role isn't 'owner', reject with a 403. Everything else just runs against whatever branch scope came back.

One branch, or all of them

That branch scope is set once, at invite time, and it's either null (all branches under the account) or a specific branch's id. A manager scoped to null sees every branch in their branch switcher and can move between them freely, same as managing several locations under one owner. A manager scoped to one branch sees only that branch in the switcher, full stop, and even if they somehow got hold of another branch's tenant id, the server checks the requested branch against their stored scope on every single request and rejects anything that doesn't match. The branch picker also hides the "add a branch" and "manage branches" controls for anyone who isn't the owner, so a manager never sees an invitation to do something they can't actually do.

Sending an invite

The Team page has one button: Invite a member. It opens a dialog with an email field (optional, more on that below) and a branch scope picker that defaults to All branches. Submit it and the server generates a random 24-byte token, stores it in an invites collection with a 7-day expiry, and the link (/invite/{token}) gets copied to your clipboard immediately. If you did fill in an email, menu-MENA also sends it as a real email in the background, but that send is best-effort: if it fails, you've still got the link in your clipboard and nothing blocks on it.

Accepting, revoking, and removing

Whoever opens the invite link sees the restaurant's name and logo before they sign in, then claiming it is a single transaction: it checks the invite hasn't already been used or expired, checks the person isn't already a member, and only then creates their membership and marks the invite claimed. Two people can't race the same link into two memberships. From the owner's side, a pending invite can be revoked, resent (which quietly kills the old token and issues a fresh one), or copied again if the original clipboard copy got lost. An already-accepted invite can't be revoked, since there's nothing left to revoke, at that point removing the person happens from the members table instead, with an undo toast in case it was a misclick.

Every one of those actions, inviting, revoking, claiming, removing, writes an entry to the audit log with who did it and what changed. The raw invite token never gets stored there, only a fingerprint of it, because the token itself is a bearer credential and the log doesn't expire.

Frequently Asked Questions

Two: owner and manager. There's no staff or read-only role today. Owner is whoever created the account (the uid that matches the tenant's ownerId). Manager is anyone the owner invites, and every invited person gets the same manager role, the only thing that varies per person is which branch they're scoped to.

Yes. Leave the email field blank in the invite dialog and menu-MENA still generates a working invite link, it just skips sending an email and the pending-invites list shows it as link-only. That's useful if you want to hand someone a link over WhatsApp instead of waiting on an email to land.

Team management, billing and the subscription plan, the public API key, the audit log, and the custom domain setting are owner-only regardless of scope. So is adding or deleting a branch, copying a menu from one branch to another, pushing a menu update across branches, and the aggregate analytics view that compares all branches at once. A manager scoped to a branch can edit that branch's menu, prices, availability, orders, reservations and coupons.

Yes. When you send the invite, the branch scope field defaults to All branches but you can pick one specific branch from the dropdown instead. A manager scoped that way only sees that one branch in their branch switcher, and the server rejects any request to edit a different branch even if they somehow get a tenant id for it.

Seven days from the moment you create it. After that it shows an Expired chip in the pending invites list and can't be claimed. You can generate a fresh one any time with the resend button, which revokes the old link and issues a new one in the same action.

No. Removing someone from your team deletes their membership record for your tenant, nothing about their personal login. They can't get back into your admin panel, but their email and password (or Google sign-in) still work everywhere else, including if a different restaurant invites them later.