One database. Many companies. No overlap.

Every business that runs on Ledgerly shares infrastructure and shares nothing else. That is worth being specific about, because “we take security seriously” is not a mechanism.

Four layers, not one

The query cannot be unscoped

Application code never talks to the database directly. It goes through a client that adds the company filter to every read, stamps it onto every write, and is driven by the schema itself — so a table added next year is protected the day it is added, not the day somebody remembers. A request for a record id belonging to another company comes back empty, exactly as if it did not exist.

The database enforces it too

Every reference between records carries the company alongside the id. That closes the gap a filter alone leaves open: a document that belongs to you but points at another company’s customer. The database rejects the reference rather than storing it, so the case where a detail page would render somebody else’s name simply cannot arise.

A missing filter fails loudly

The company column defaults to a value no company can have, behind that foreign key. Any write that somehow escaped the scoped client would be rejected on the spot instead of landing somewhere quiet where nobody looks for months.

It is checked, not asserted

Two automated suites run on every change. One signs up two companies and attacks one from the other — stolen record ids, totals, bulk updates, payments applied to the wrong invoice. The other reads the source code itself and fails the build if any file reaches for the unscoped client without being on a short, justified list.

Any one of these could have a bug. The point of having four is that a bug in one of them is not enough.

The rest of the basics

Passwords
Hashed with scrypt and a per-user salt, verified in constant time. Nobody at any company can read them, including us.
Sessions
A random token in an httpOnly cookie. Only its hash is stored, so a database dump cannot be replayed as a live session.
Roles
Seven roles with write access gated per module, so the person who raises a purchase order need not be the person who records paying it.
Audit trail
Every confirmation, posting, payment and settings change records who did it and when.
Period locking
Close a period and nothing can post into it — not a correction, not an import, not an administrator.
Your data on exit
An account that lapses becomes read-only. Everything stays visible and nothing is deleted.

What we do not claim

There is no payment processing in this product, so no card data ever reaches it. We are not going to list compliance badges we have not earned. And if you find a way across the wall between two companies, that is the most valuable bug report we can receive — it will be treated that way.

Start free