Sealed
A working demonstration of approval routing and document sealing — a chain frozen at submission, signatures applied in-browser, and an artifact you can verify without trusting the system that produced it.
- Role
- Architect & sole engineer
The application
Screens, captured from the running app
Booted against its seeded database and walked route by route — these are the real pages, not mockups.





A demo, built to show the architecture behind a confidential client platform without exposing it. The firm, the people and the paperwork are invented. The routing, sealing and audit behaviour is the real thing.
Why it exists
The production version routes real memos and bank transfer instructions for an investment firm, and can't be shown. What's interesting about it isn't the interface — it's four decisions that are almost impossible to make convincing in prose, so here they are running.
Twenty-two documents across a month: thirteen sealed, four still waiting on a middle approver, four returned for changes, one rejected outright.
1. The chain is frozen at submission
When a document is submitted, the resolved approval chain is written to it as a snapshot — names, titles, and positions as they were at that moment.
Resolving it live at read time would be less code and quietly wrong. If someone is promoted next month, or leaves, or the signing threshold changes, the record of who was required to approve last month must not change with them. Every later view of the approval history reads the snapshot rather than re-running the rule.
2. Request-changes is its own state
Modelling "please fix this" as reject-then-resubmit is the obvious shortcut, and it destroys the thing people most often need to read later: the thread of the conversation. A returned document keeps its note, its author and its place in the chain.
In this seed that distinction is visible — four documents sitting in changes requested against one outright rejected, and the notes read very differently ("beneficiary bank details differ from the record on file" versus "outside the delegated authority for this category").
3. Hash both ends, not just the output
Sealing produces two digests:
- The original, at submission. Proves the document was not altered before the first signature.
- The sealed artifact, certificate page included. Proves it was not altered after the last one.
Hashing only the output is the common version and it leaves the first gap wide open. Both are shown on the document, so the artifact can be verified later without trusting the system that produced it.
4. CC never gates
The firm's existing paper convention was From / To / Through / CC, so the router reads exactly that. TO and THROUGH gate progress; CC recipients are notified and recorded in the audit trail, but a document never waits on them.
A chain that stalls on someone who was only ever copied is the classic way these systems quietly stop being used.
The audit trail
Append-only, and it records the views that changed nothing alongside the decisions that did — 141 events across the seed, each with actor, timestamp and source address. Signatures carry their own address rather than inheriting one from the session, because "who signed this, from where" is the question the trail exists to answer.
Stack
Next.js 16 App Router with React Server Components, Prisma over SQLite, five routes. In production this pairs with Puppeteer for HTML-to-PDF composition and pdf-lib for signature stamping and certificate appending; the demo models the resulting artifact rather than generating it, since the PDF pipeline is the part that is genuinely just plumbing.