Schema Overview
The map — every stored table, what it holds, and which page owns its detail
Every stored table is defined in one file, convex/schema.ts, which governs.
This page is the map — what each table is for and where its detail is written
down. It is deliberately short: the shapes live on the pages it points at, and a
count or a column list repeated here would only drift.
In plain terms: the index at the front of the filing system. It tells you which drawer holds what, and which page describes the cards in that drawer.
Content — the Folio tables
Two recursive tables plus pins hold every authored thing. Their detail, the write invariants and the read layer are all in Folios Schema, which governs.
| Table | Holds |
|---|---|
folios | One row per folio, versionless — the card in the drawer. Keys, pointers and lineage; its kind is the sole kind discriminator. |
folioVersions | One save point of one folio's own content. Every edit lands on the open draft; minting a version is a user act. |
folioPins | A save point's schedule — which children, at which edition, that save point comprises. Pins point down; children never point up. |
tags | The shared vocabulary a folio's About card draws its tags from. |
listOrders | One person's own order for one list of cards — a Workspace's Projects, a Project's Documents, or their Libraries (listKey is the container's folio key, or libraries). Keyed by the signed-in account, else the browser's user. Only a sort hint: a key absent from order is new and draws on top; a Library's own Documents are never stored here (The Goldie Card). |
There are no separate document, module and block tables. The three-tier
schema and its three version tables were deleted on 2026-09-03; a card's tier is
a word on the card. A page describing documents or moduleVersions as storage
is out of date, and bun run preflight will not catch it — prose about a table
is not a path — so say so rather than building against it.
Goldie — conversation binding
Threads and messages themselves belong to the Convex Agent component, in its own namespace. The app stores only the binding.
| Table | Holds |
|---|---|
folioAgentThreads | One Builder conversation, bound to the folio its card shows and the session that opened it — so a tool call resolves whose authority it acts under from the thread alone (One Goldie Per Folio). |
folioListThreads | A list-screen row's conversation, bound to the browser client rather than a document session (Goldie on the List Screens). |
proposals | One filed, not-yet-applied change to one Working Document — Proposals Schema. |
A proposal is its own row, never a folio version and never a column on the row it targets. Versions record what happened, and a declined suggestion did not happen, so a rejected proposal leaves no trace in version lineage.
Identity and access
| Table | Holds |
|---|---|
authSessions | Who this browser claims to be, and which Document it is bound to — Auth Sessions. Only an authorized session opens a Document. |
users | Authenticated platform accounts — Users. Separate from party facts, which are document content. |
authEvents | The append-only audit trail of authentication attempts — Auth Flow. |
folioVisits | Which folios this browser opened and when, per kind, so Recent can be listed without a session. |
Ships empty
Three tables exist with typed validators and no product writer. They are not a gap to fill opportunistically — each waits on a feature.
| Table | Waits on |
|---|---|
libraries | The library feature: the public singleton is minted at launch, a personal library on a user's first save-to-library (A Library Is a Shelf). |
libraryPins | The same. A pin names an exact sealed edition; listing mints no version. |
documentGenerations | Export and payment — Document Generations. |
Rules that hold across every table
- Business identity is a prefixed
keystring, not Convex's_id._idstays internal; a key is what crosses the wire and appears in a route. - Never duplicate
_creationTime. There is nocreatedAt, noproposedAt. A folio version's created date derives from its row's_creationTime; a proposal's filing time is the same. - The version row is the render boundary. Re-rendering or exporting reads a
named
folioVersionsrow and the editions its pins schedule — never the mutable state of another version. - A field is not a row. It is an ordered entry owned by one data block's version, with its own minted identity, and it freezes with that version.
- Parties are not a schema concept. Party facts — willmaker, executors,
family — are ordinary data on a
data_poolmodule, so cross-document reuse is the same mechanism as any otherdata_poolreference. data_poolis a convention, not a type. Modules have no type discriminator. A module whose data blocks own document-wide facts is usually handleddata_pool, and nothing in the schema grants it special status for that. Write authority belongs to the data block owning each field.- An identity challenge is access metadata, declared
access.challenge: identity— not anauthmodule type.
The other schema pages
- Status Axes — the four independent status axes, and why they are never one overloaded enum.
- Flow Schema —
flow.conditionand the reference grammar a condition may use. - YAML and JSON Mapping — how authored YAML becomes stored JSON, and back.
- Threads and Messages — what the Agent component owns rather than this schema.