2.8 KiB
| id | title | description | tags | lang | ||
|---|---|---|---|---|---|---|
| principles | Principles | The four rules that shape f451's design, and why they exist. |
|
en |
Principles
Four rules recur throughout the codebase. They are not style preferences — each one closes off a class of bugs or design mistakes that the project has already made once.
Git is the source of truth, Postgres is only an index
Every space is a Git repository; every page is a Markdown file with frontmatter. Postgres holds the rendered content, the search vector, the knowledge-graph edges, sessions and encrypted provider tokens — nothing that can be derived from Git is allowed to live only in the database.
Important
Losing
pg-datais recoverable:POST /admin/reindexor the drift job rebuilds the index from Git. Losingforgejo-datais not — that is the one thing backups exist for. If you find yourself adding a column that holds information not derivable from the Git content, stop and ask whether it belongs in Git instead.
Permissions come from the Git provider
f451 has no role system of its own. Whether someone can see a space or write to it is decided by their permissions on the underlying repository. Writers always write with their own provider token — the API never commits under a service account. Without a linked provider account, every write attempt fails with 403; that is a precondition, not a bug.
This also shapes how "not found" behaves: a 404 deliberately means
"doesn't exist, or you don't have access" — never distinguish the two.
Doing so would let an unauthorized caller learn that a page exists, which
is exactly the kind of existence oracle this design avoids.
Writing always goes through the review workflow
There is no route that writes directly to the published version — not for people, not for agents. The path is always: create a draft (a branch) → write → open a review (a pull request) → approve (merge) → reindex.
Draft routes carry a SHA contract: whoever writes names the baseSha of
the version they started from. If the content has changed underneath them,
they get a 409 back with the current state instead of a silent
overwrite. See api for the routes that implement this.
Diagrams carry their own source
.drawio.svg and .excalidraw.svg files under <page folder>/_media/ are
plain SVGs that also carry the diagram's source XML in a content
attribute. One file is both the picture people see and the thing the
diagram editor reopens. The SVG sanitizer keeps that attribute and the
wrapping text elements deliberately — stripping either would make the
diagram unreadable or unopenable.
Tip
These four rules are the first thing to check when a design choice looks surprising: it is very likely a direct consequence of one of them, not an arbitrary decision.