CODEX // oaoisme wiki

§ Codex — the learning wiki · Architecture — one container, three faces

The data model

updated 2026-06-01

Two tables. That's the whole schema.

sections

A top-level area — one per project. Columns that matter: slug (unique, used in URLs), title, blurb (one-line description shown on cards), accent (one of six colour names that re-skins the section), and sort.

pages

Everything you read. Key columns:

  • section_id → which section it belongs to (cascade-deletes with the section).
  • parent_idself-referential foreign key to another row in pages. This is the entire nesting mechanism: a page with parent_id = NULL is a top-level page; a page that points at another page is a subpage. One level deep by convention.
  • UNIQUE(section_id, slug) → a slug only has to be unique within its section, so two projects can both have an "overview" page.

How the tree is built

The database stores a flat list of rows with parent pointers. The tree() function in db.js does the assembly in memory: load all pages for a section, build a Map from id → node, then walk the list and push each node into its parent's children array (or into roots if it has no parent). That's an adjacency-list → nested-object transform — cheap, and it avoids recursive SQL.

const byId = new Map(pages.map(p => [p.id, { ...p, children: [] }]));
const roots = [];
for (const p of pages)
  (p.parent_id ? byId.get(p.parent_id).children : roots).push(byId.get(p.id));

Gotcha: because nesting is just a nullable parent_id, nothing in the schema stops you nesting three levels deep. The one-level convention is enforced by discipline (and the MCP tool descriptions), not a constraint. Keep it shallow on purpose.