Security
What protects your staff records, control by control
A rota holds names, addresses, dates of birth and what people are paid. Everything below is built and running today, and each one says what it covers and where it stops. The last section is the list of things we do not claim.
Last updated 19 September 2026
One business cannot reach another’s data
Every business has its own address on the site, and every database query made while you are inside it is rewritten to carry that business before it runs. Your membership is the access check itself: asking for a record belonging to a business you are not a member of returns nothing found, from the same query that would have fetched it. There is no second permission layer that somebody could forget to call, because there is no query that can be written without the first one.
What keeps that true as the product grows is a test that reads the database schema directly rather than a list somebody maintains. It fails the build if a newly added table has not been classified, if any operation on a tenant-scoped table could run without the business on it, or if a conflicting business could be written over the real one rather than refused. The single deliberate way around the rewrite is a differently named database client, used in a handful of places that each carry a written reason, and a lint rule that fails the deploy when it appears anywhere else.
Deleting something hides it, and you can bring it back
A deleted shift, a deleted note, an archived member of staff and a closed business are all marked as gone rather than removed. A deleted shift appears in a log you can restore it from, and restoring re-checks it against the rota as it stands now rather than as it stood when it was deleted. Clearing a whole week uses that same mechanism, so a week cleared by mistake is recoverable shift by shift.
The risk in that design is the opposite of the obvious one: not that data is lost, but that a query somewhere forgets to exclude the hidden rows and shows a deleted shift back to somebody. A scan of every query in the codebase runs in the test suite and fails on one that neither decides the question nor appears on a written exemption list with a reason attached.
An activity log that says what it does not record
Owners and administrators have an activity log in settings. It is deliberately not open to managers: a trail of who decided what about whom is itself sensitive, and a manager already sees the decisions they are party to on the screens that own them. It records, among other things:
- people joining the business on an invitation, and the role they joined as;
- downloads of the people list, the leave register and a full copy of the account — including how many rows went and whether pay columns were in them;
- leave entered, approved, denied and cancelled, and any shift changed to clear a clash with it;
- timesheet lines approved, and hours or clocked times corrected;
- role changes, and which sites and teams a manager covers;
- pay rates on a job role, and sites, teams and job roles added, renamed, archived or restored.
The page itself publishes what it does not record, on the page, rather than leaving a reader to infer completeness. Today that is: shifts created, edited or published; clocking in and out; site-level clock-in restrictions; people’s own details and pay rates set on a person; settings outside sites, teams and job roles; sign-ins; and the downloads that are assembled in your browser from a page you are already looking at, which leave no request for us to record.
You can see and end every session on your account
Your account lists everywhere you are signed in — the device, the browser, roughly where it was last used and when — and lets you end any of them, or all the others at once. The one you are reading on is marked so you cannot sign yourself out by accident.
Nobody can list or end anybody else’s sessions, and that is structural rather than a check we remembered to write: no function on that surface accepts a user identifier at all, so there is no parameter a request could carry to name somebody else. The session you choose is matched against your own list before anything is ended, and an identifier belonging to another account simply is not in it.
Everything you have entered, back out in one file
Organisation settings carry a control that hands back the whole account — people, rotas, leave, allowances and timesheet entries — as a single file, formatted so a person can open and read it rather than only a program. It needs no request, no waiting period and no conversation with us, and it works for as long as the account is open.
Because it is the largest single disclosure the product can make, taking it writes an audit row first — the dataset, the number of records, and whether pay was among them. If that record cannot be written the download does not happen, which is the right way round: once the file exists the disclosure has already been made, and failing afterwards would only lose the evidence of it.
Two different things called deleting an account
Deleting your own sign-in is a control under Your account and it is yours to press. It removes your sign-in, your name and email address, and your membership of every business here. It deliberately leaves your employment record and the rota history attached to it with your employer, and cuts the link between the two — those records are the business’s, held under its own obligations, and a processor destroying a controller’s wage records on somebody else’s instruction would be the wrong thing to build. The one person who cannot do it is the sole owner of a business, because it would leave that business with nobody able to run or close it.
Closing a business is a separate control, available to an owner and guarded by typing the business name. Everybody loses access and the address stops resolving; the records themselves are kept, because a rota is the record of who worked when and the timesheets behind it are what people were paid from. Permanent erasure is done by hand on request, so that nobody destroys a wage record with a mis-click, and for thirty days after a closure a copy is still available.
What a browser is allowed to run
Rotaaa sends a strict Content-Security-Policy that enforces rather than warns. Each page is served with a one-time token and only scripts carrying it will run, so an injected script tag does nothing even if one were ever to reach a page. A policy nobody can observe is one you only find out about from a customer, so violations are reported back to an endpoint of ours, rate limited and logged as the directive and what it refused — never stored, never shown to anybody, and never rendered anywhere.
Passwords are never seen by us at all. Sign-in, verification and any second factor are handled by Clerk, our authentication provider, and Rotaaa holds none of it.
Who else touches any of it
Four parties, and they are named on one page rather than kept in a register somewhere you would have to ask for: Clerk for authentication, Resend for the emails Rotaaa sends, a small relay that tells us a support message has arrived or that the server has thrown, and the provider of the machine the application and its database run on. What each one receives, and what happens when that list changes, is set out in the privacy policy.
There is no analytics provider, no advertising network, no session recorder, no chat widget, no payment processor and no third-party error monitoring. That is a statement about what is wired into the product rather than an intention.
What we do not claim
Everything above is checkable, which is exactly why the gaps have to be here too. An unstated gap on a page like this one reads as a covered one.
- Backups are our database provider’s, and a restore has not been rehearsed. So no recovery point and no recovery time are promised, and neither will be until one has been tested end to end. It is an honest reason to keep your own copy of anything you could not reconstruct — see the service level agreement.
- There has been no external penetration test and no certification. No ISO 27001, no SOC 2, no third-party audit of any of the above. What there is instead is the test suite that fails the build, and a codebase one person can hold in their head.
- Our own support console writes no audit rows yet. It exists so that a support thread is tied to a business and answered by somebody identifiable, and it can read across accounts to do that. “Did anybody at Rotaaa look at this?” is therefore not answerable from your activity log today. It is an open piece of work rather than a decision, and this page will say so until it is done.
Reporting something
A report that somebody can see data they should not is the most urgent thing there is, and it is the same-working-day case in our service level agreement. Email [email protected], or message us from inside Rotaaa if you can sign in. Tell us what you did and what you saw; that is usually enough to reproduce it. The other routes, and what to expect back, are on support.