Your artwork, your customer list, your invoice history.
A print shop's files are commercially sensitive, and handing them to somebody else's software is a real decision. This page is what we would want to read before making it.
Everything below describes a mechanism that exists in the software today, with the actual figure it uses. We have written it this way rather than as a list of adjectives because “enterprise-grade” and “bank-level” are not claims anyone can check, and the specific ones are.
Equally, there are things we do not claim. We hold no card details, because the platform issues invoices and does not take payments. Your customers have no accounts, because approving a proof never creates one. And we have not been through a formal external audit — if that is a requirement for you, say so early and we will tell you straight away whether we can meet it.
Signing in
Signing in from a new device sends a six-digit code to the address on the account. The code is stored hashed, never in plain text, and it is useless once used.
6 digits · expires in 10 minutes · 5 wrong triesConfirm a device once and it stops asking for a code on that browser. The token behind it is random, held server-side against one user, and expires on its own.
45 days · http-only cookieFailed sign-in attempts are counted against the identifier being tried, not the whole system, so someone hammering one account cannot lock everyone else out and cannot keep guessing either.
8 failed attempts per 15 minutesStored with bcrypt. When the standard moves on, an older hash is re-hashed the next time that person signs in successfully — nobody has to be told to reset anything.
bcrypt · rehash on next sign-inA reset link carries a token that is stored hashed and consumed the moment it sets a new password. Sending yourself a second link invalidates the first.
One use, then deadThe session identifier is regenerated at sign-in and again whenever an account's privileges change, so a session captured before a change cannot be replayed after one.
Regenerated on privilege changeKeeping shops apart
Every listing is scoped to the company asking for it in the SQL itself. A page is not fetching everything and then hiding the rows you should not see — the rows never leave the database.
Enforced at the query layerA login has a scope (shared team, named staff, or a client), a role within it, and separate switches for the print and social sides of the platform. A print-only staffer does not get a social page rendered and gets refused on a direct call to a social endpoint.
Scope · role · per-track accessStaff scoped to particular clients see those clients and nothing else. If someone has no assignments recorded, that means no access — not, as the easier implementation would have it, access to everything.
No assignment means no accessActions are written to an activity log, with owner-only and internal-only entries kept separate so a client login cannot read your staff's trail or your commercial notes.
Owner-only and internal-only entriesThe link your customer opens
Your customer approving a proof never creates a login. That is deliberate: an account we do not create is a password we cannot leak, and it removes the single most common reason a proof sits unapproved for a week.
No password to loseEach approval link carries a token of sixteen random bytes. There is no sequence to walk and no list to enumerate — a wrong token matches nothing at all.
16 random bytes · 128 bitsThe endpoint behind an approval link returns only the fields needed to render the one proof the token names. It never returns a list, another customer's job, or anything about your shop beyond the branding on the page.
Never a listThe approval page, the client portal, the sign-in page and the proof endpoint all tell crawlers not to index them, and they are left crawlable so that instruction is actually read rather than blocked at the door.
noindex on every client-facing pageFiles, secrets and time
Every folder that receives an upload carries a rule denying execution of anything script-shaped. The rule is re-written on every single request, not just at install — so a folder that loses it gets it straight back rather than sitting exposed until someone notices.
Re-asserted on every request · 9 foldersThe five prepress tools on this site have no upload endpoint in the code at all. Your artwork is read by your own browser and discarded when the tab closes. That is a fact about how they are built, not a promise about how we behave.
No endpoint existsWhen you connect a Facebook or Instagram account, the access token is encrypted before it is stored, each with its own initialisation vector.
Encrypted, per-record IVThe database is pinned to UTC and every time is converted in the viewer's own browser. An approval timestamped at sign-off reads correctly whether it is being checked from Islamabad, Dubai or Manchester — which matters when the timestamp is the evidence.
UTC stored · converted per viewerSomething here you need to dig into before you can commit?
Ask. We would rather answer it now than have it come up after you have moved your jobs across.