Skip to main content

Who does what

GreatBook does not have an elaborate permission matrix. It has one rule, applied consistently, and the roles fall out of it.
The document-intake rule: three distinct, authenticated people stand behind every document-originated posted journal entry. Whoever submitted the document, whoever approved it into the queue, and whoever approved the posting must be three different named users.
Native subledger records, approved workpapers, reversals and system-origin events do not acquire invented submitter or intake-approver identities. They follow their canonical service controls and reach the same single ledger writer. The document-gate responsibilities below are a consequence of that rule.

The seven roles

Submitter

Files a document into the queue, by composing it in the Typewriter or dropping it into chat. Anyone signed in can be a submitter. A submitter can never approve their own document at either gate.

Designated document approver

Signs a composed Typewriter document before it may be handed to the Clerk. Designated per document type. Cannot approve a document they composed.

Intake approver

Stands at gate 1 and answers “is this document real and correctly extracted?”. Approving launches the Bookkeeper and moves no money. May not be the submitter.

Posting checker

Stands at gate 2 and answers “is this journal entry right?”. This releases a document-originated proposal; the ledger service remains the only component that writes. May not be anyone who submitted, drafted, edited or approved that document.

Accountant

Runs the period close, reads the checklist, and proposes adjusting entries. Proposes only. An adjustment follows its stable-source approval path and reaches the single writer through the Bookkeeper gate.

Auditor

Asks the Auditor agent for independent assurance and reads its findings. Nothing in this role can change a book, because the agent has no write path at all.

Developer

Operates the system: connector health, migrations, deploys. Being able to deploy the system does not confer the ability to approve a posting in it.

Who may do what in the document workflow

The posting gate does not grey itself out for makers. The rule is printed under the buttons and names you if you are one of the makers, but the button still looks clickable, and the server refuses it with a 409. Nothing can go wrong, but you get an error rather than a disabled control. Read the line under the buttons before you click.

Agents are not people

Five identities are agents, never people: the Clerk, the Bookkeeper, the Accountant, the Auditor and the Typewriter. The document gate records who approved its journal entry, and “an agent approved it” is not an answer that provenance may carry. So agent identities are refused at both gates, as are placeholder identities: unknown, anonymous, none, n/a, user, someone, test, and the bare string submitter. That last one has a history worth knowing, because it explains why the rule is written the way it is.
The separation-of-duties check used to compare identities as raw strings. In the deployed path the maker set contained no real human identity except the intake approver:So checker != submitter compared a real email address against the word “submitter”, and passed every time. The person who uploaded a document could approve their own document. The advertised “maker is not checker” meant “two humans touch the money”, not “the uploader cannot approve”.The fix had two halves, and only both together are worth anything. The rule now compares three named identities, and the submitter is now a real identity: the UI’s passthrough injects it from the validated session and strips any the browser sent. A rule comparing authenticated identities is only worth writing once the identities are authenticated.

How two spellings of one person are handled

The three identities do not all arrive in the same format, so they are compared on a canonical key: casefolded, trimmed, and reduced to the local part of an email address. Thai, thai and thai@vinmake.com are therefore one person. That choice leans deliberately in one direction. It can merge two different people who share a local part across domains, which refuses a posting that should have been allowed. The opposite error, treating one person’s two spellings as two people, would admit a self-approval. A refused posting is a phone call. An admitted self-approval is a fraudulent entry in an immutable ledger.

Where the rule is enforced

Three places, deliberately, because each covers what the others cannot.
1

At the intake gate

So a document cannot even enter the active queue in a state where it could never be posted. Fail at the gate the human is standing at, not two gates later.
2

At the API boundary of the posting gate

So the reviewer gets a clean 409 with a readable reason rather than a failed run.
3

Inside the Bookkeeper, immediately before the writer

Against the record the graph re-read itself, so the rule holds even if the graph is driven another way.
A rejection is subject to only half the rule. Refusing a document writes nothing to the ledger, so it is not gated on three distinct people, only on the refusal itself being attributable to a named user. Applying the full rule to rejections used to strand documents: a row whose submitter was still a placeholder could not be posted, could not be rejected, and could not be resubmitted. It sat active forever and showed up in the Auditor’s reconciliation as a document with no journal entry.