Key points
- Each restaurant's data is separated inside the database itself, not only in the app.
- Passwords are hashed with scrypt; repeated failures lock the account for 15 minutes.
- Sessions rotate on every refresh, and a reused session ends the whole sign-in chain.
- Orders, cash, points and audit records are append-only.
Every restaurant in its own space
All restaurants run on one platform, but the database enforces the separation. Every restaurant table has row-level security switched on and forced, and every request runs in a transaction that is set to one restaurant. The account the application uses cannot bypass those rules.
Two internal roles are allowed past them for narrow jobs: the background workers, which may only list which restaurants are active before doing their work restaurant by restaurant, and the SCALE team's control center, which has no access to customer addresses, order locations, password hashes or restaurants' own audit logs.
Sign-in and passwords
- Passwords are 8 to 128 characters and are stored as scrypt hashes with a random salt; they are compared in constant time.
- Five wrong passwords lock the account for 15 minutes. Signing in to an account that does not exist takes the same time, so it does not reveal which accounts exist.
- Sign-in attempts are also limited per address over 15 minutes: 10 for staff, 60 for customers, 5 new customer registrations. The counts are shared by every server.
- Verification codes are 6 digits, expire after 10 minutes and allow a limited number of tries.
- Cloudflare bot protection can be switched on for sign-in and for placing orders.
Sessions that cannot be replayed
A sign-in gives a short-lived access token (15 minutes by default) and a refresh token. Every refresh replaces the refresh token with a new one. If an old one is ever used again, the whole chain of sessions is ended, which stops a stolen token from being used for long.
Each request also checks that the session is still active, so removing a staff member, changing their password or reducing their role signs them out everywhere at once. Console cookies cannot be read by page scripts and are not sent by other sites.
Least-privilege roles
Access is built from 29 permissions, from reading orders to confirming cash or managing staff. The owner can create roles with any mix of them, and staff can be limited to one branch. Nobody can grant a permission they do not hold themselves, built-in roles cannot be edited, and the last active owner cannot be removed.
The console hides what a role cannot use, but that is only for clarity: the server checks the permission, the branch and the membership on every action.
Records that cannot be rewritten
Order status changes, the points ledger, stock movements, price history and the audit log are append-only. The database rejects any update or deletion, so corrections are made by adding a new, visible entry.
Respecting customers' data
- Order locations are taken only while the app is open, with consent, and are deleted after 180 days.
- Customers can delete their account from the website or app. Their addresses, locations, devices, notifications and password are removed, and their profile is anonymised.
- To stop the same person from claiming new-customer offers again, only protected fingerprints of their phone and email are kept.