Architecture
The Books You Can Defend
Caydem is built so that the answer to “how do you know these numbers haven’t changed?” is something structural — enforced by the database — rather than an assurance about how careful your team is.
The Question
Every Audit Arrives at the Same Question
How do you know the numbers you are showing me are the numbers you recorded?
The answer that rests on people
“We’re careful. Only two people have admin rights. We would catch it in review.”
That is a policy. Policies hold right up until the month someone is in a hurry, and they leave nothing behind to look at afterward.
The answer that rests on structure
“The ledger will not accept the edit.”
The refusal lives in a database trigger underneath the software — not in a screen that declines to show an Edit button. A correction has to be posted as a reversal, which leaves both entries standing.
What follows is the second answer, in 13 parts, laid out roughly in the order an auditor would ask for them. Each one leads with the plain statement; the mechanism sits underneath as the reason you should believe it. The ledger rules apply whether Caydem runs on one laptop or on a server your IT team owns, because they are not properties of the application — they are properties of the database it writes to. The access rules sit in the service layer above it, and where that distinction matters, it is printed with the claim.
Ledger Integrity
A Posted Entry Stays Posted
The general ledger is append-only. Corrections happen the way accountants have always made them — with a reversal that leaves both sides of the story visible.
- A posted entry can never be edited or deleted. Corrections are explicit reversals.
- This is enforced by database triggers, not by application code that a bug could route around — a deferred double-entry balance constraint checked at commit, a guard that rejects any edit to a stamped entry, and a guard that refuses to delete the lines of one. The only mutation left open is the posted-to-reversed flip, which is how a correction is supposed to happen. Triggers fire no matter which database role is connected.
- Every posted entry is a self-describing artifact.
- Each one carries a canonical JSON blob — account names, the user’s name, the company name, dimension values — snapshotted at the moment of posting, stored byte for byte, and hashed with SHA-256. Readable and re-hashable from the blob alone, without Caydem’s schema to interpret it.
- Posted journals are linked in a per-company hash chain.
- The sequence number and the previous entry’s hash live inside the hashed blob itself, so the link between entries is hash-protected along with the entry it points to. What that chain does and does not demonstrate is worth being precise about — see the limits at the end of this page.
- You can reconstruct the trial balance as of any historical date.
- As-of reporting reads only posted entries dated on or before the date you pick. Because posted entries never change, the report you run today for a date two years back is built from the same rows it would have been built from then.
- An entry cannot post unless it balances. There is no way to record a one-sided transaction.
Isolation
One Company Cannot See Another
Multi-company is not a filter applied to a shared table. Each company is a separate namespace in your database, with row-level policies underneath it.
- Every company lives in its own database schema, inside your own database.
- Company resolution sets the search_path for each transaction, so one company’s tables are a distinct namespace rather than rows sharing a table with everybody else’s. Separation is a property of the schema layout, not of a WHERE clause somebody has to remember to write.
- Row-level security policies scoped by company are defined on every domain and ledger table.
- Row-level security is enabled and forced on all of them, with policies that scope rows to a single company — so the constraint is declared on the table itself rather than assembled by the application on each query.
- Honest limit — These policies are the backstop for a least-privilege runtime connection that is still being rolled out — the desktop connection path cannot yet supply that credential. Today they are defense in depth behind the service-layer checks below, not the thing standing between you and an application bug. We are not going to tell you the database is currently refusing cross-company reads when the shipped default does not connect in a way that would make it do so.
Access Control
Every Action Has an Owner
Who may do what, under whose authority, is settled before the write happens — and recorded after it.
- Every mutating action checks a permission — enforced, not documented.
- Authorization is a single choke point in the service layer, one method to one permission code. A default-deny test walks the entire API surface, so a new route that ships without a permission fails the build.
- The person who created it can’t approve it.
- Segregation of duties is a rule engine wired into the approval path rather than a convention on a checklist. The approval check has no short-circuit for the company owner — the most senior role in the system is bound by the same rule as everyone else. Disabling a rule is an explicit act, not a quiet exception.
- Financial documents are audit-logged with the actor, the before and after values, and a reason.
- Journals, bills, sales invoices, vendor and customer payments, deposits, expenses, bank transfers, and approval requests each carry audit triggers. The log is written by the database as part of the same transaction as the change, so a write cannot succeed while its audit record quietly fails.
History & Recovery
Nothing You Referenced Ever Disappears
History has to keep pointing at something. Anything a posted transaction depends on is archived rather than deleted — and the whole company comes with you when you want it.
- Nothing referenced by history ever disappears.
- Any entity reachable from a posted transaction — vendors and customers, GL accounts, dimension values, tags, email templates — is archived, never hard-deleted. The row and its foreign keys stay exactly where they were; only the picker for future entries hides it. A vendor who went out of business in 2021 is still the payee on every 2021 invoice.
- Back up and restore a company from inside the app, with no DBA tools.
- The archive is per-table NDJSON with a checksum and a plaintext manifest you can read without special tools. A restore validates the schema version first and takes an automatic pre-restore backup as the undo.
- Honest limit — The archive is not encrypted — it is plain, checksummed data on disk, so treat the file with the same care as the books themselves. It is also sized for a small company’s dataset; if your books are large, plan on database-level backups instead.
- Your CPA gets a scoped workspace, not your file.
- An engagement model with a PBC list, a read-only auditor role, transaction sampling, and a period sign-off that records what was reviewed. It is an auditor workflow — a better way to run the request list and hand over scoped access — not a source of independent proof.
Honest Limits
What This Doesn’t Mean
A page like this is only worth reading if it also says where the guarantees stop. These are the four places we get asked about most.
It doesn’t mean we can prove to an outsider that nothing changed.
It is the triggers that stop a posted entry from being rewritten; the chain links entries to one another. Neither demonstrates anything to a third party who has no reason to trust whoever holds the database, and the chain has a known soft spot at its end — removing the most recent entries is the case that is hardest to see, and it is also the most natural way to dress up a close. Closing that gap takes a chain head recorded somewhere outside your own control, which is on our list and not in the product. So the claim we make is an immutable ledger, and we stop there.
It doesn’t mean the software is finished.
Caydem is in beta. Everything above is built and verified; plenty of other things on our list are neither. If a capability isn’t described on this page, assume we haven’t shipped it yet.
It doesn’t mean structure replaces judgment.
None of this decides whether an accrual was reasonable or a cutoff was honest. Structure makes your records hard to change quietly. It has no opinion on whether they were right when you posted them.
It doesn’t mean you can skip backups.
The in-app archive is a convenience for moving or restoring a company, not a disaster-recovery plan. If you self-host, the backup story for the database underneath is still yours to own.
Take It to Your Auditor
See how a CPA engagement runs inside Caydem, or look at where your data would live in each deployment.