decisions
Docs move into a database
A frozen record of a decision at the time. Superseded by a new record rather than edited.
Written by the build · 2 September 2026
Frozen. A record of a decision at a point in time, not living documentation. Do not update it — supersede it with a new record instead.
Docs move into a database
What we decided
Documentation content moves out of markdown files in this repo and into a store, so that people who do not use git can edit it. CI keeps writing the generated pages; an AI proposes updates to written ones; a person always approves.
Why
PMs and POs own the customer-facing notes. They are not going to open a pull request, and asking them to is how the changelog stops being written.
Engineers also want to fix a wrong line in a runbook in ten seconds, not in a branch.
Where it lives: the backend's Mongo, behind the admin API
Not a new database owned by the docs app.
The backend already has the whole of what this needs: Mongo, admin accounts with roles and email-OTP two-factor, a permission catalogue, an audit log, and CI that knows when the code changed. Standing up a second auth system next to that would be a mistake we would spend a year regretting.
The docs app becomes a client of that API, exactly as bundul-admin already is.
The rule that makes it safe: every document has an origin
Putting all 41 documents into one editable store would break the thing that makes the generated ones worth reading.
| Origin | Count | Written by | Editable in the app |
|---|---|---|---|
generated |
11 | CI, from the code | No. The screen says it comes from the code |
written |
12 | People | Yes |
frozen |
18 | Nobody, ever | No. They record what was true then |
If an admin could edit cron-jobs.md, one of two things happens on the next
merge: CI overwrites their work, or CI does not and the page now lies about what
the system does. The second is worse than having no page.
What we are giving up, and what replaces it
Review. A pull request is how a doc change gets read by someone else. Losing that entirely would be careless, so: a person's edit goes live immediately, and anything the AI wrote waits for one approval. A typo fix is instant. A machine rewrite of the payments documentation gets read first.
History. Git gave this away for free. The store keeps every revision, not just the current one, with who changed it and when. Cheap now, painful to retrofit.
Phases
| Phase | What | Delivers |
|---|---|---|
| 1 | Doc model, admin API, CI pushes generated pages in |
One source of truth; an honest "last updated" |
| 2 | Editing screen + revision history | PMs edit release notes; engineers fix runbooks |
| 3 | Pending revisions and a review queue | The approval step the AI needs |
| 4 | AI updates written docs after a code change | The Passport → Stripe case |
| 5 | AI drafts the customer note | First draft written for you |
Each phase is useful on its own. Nothing later is required for something earlier to be worth having.
What this replaces
tools/sync-internal-docs.mjs copies markdown into the docs app at build time.
That stays until phase 1 ships, then goes. Markdown files remain the authoring
format for frozen and for anything an engineer prefers to write next to the
code — CI pushes those into the store rather than the store replacing them.
This is a record of a decision at the time. It is not edited — write a new record that supersedes it.