Tree and paths

The doc_pages table is an adjacency list. Each row points at its parent through parent_id and stores its own materialised path, so the sidebar and routing read one column without walking the tree.

Columns

Column Type Notes
parent_id foreign doc_pages, nullable cascadeOnDelete — removing a doc drops its subtree
user_id foreign users author; restrictOnDelete
slug string URL fragment, unique within the parent
path string, unique full route segment, rebuilt on save
position unsigned int sibling order, defaults to 0
body longText Markdown content
published_at timestamp, nullable null or future = draft

Path building

Doc::buildPath returns parent->path . '/' . slug when a parent exists, otherwise just the slug. The saving hook writes that result into path on every write, so the column is never stale.

When path, slug, or parent_id changed during a save, the saved hook re-saves each child. Each child save re-fires savingbuildPathsaved, so the rebuild cascades down the subtree in one pass. The same hook calls DocOutline::flushCache() so the public sidebar picks up the new paths immediately.

Position and nesting

Siblings are ordered by position then id (see Doc::children and DocOutline::fetchDocs). DocOutline::nest($doc) reparents a doc under its previous sibling and parks it at the end of that sibling's children; unnest($doc) lifts it back to its parent's level, slotted one position after the parent. moveUp / moveDown swap positions with the previous or next sibling without touching parent_id.

Outline query

DocOutline::tree() loads the whole outline in a single query that selects only id, parent_id, title, slug, path, position, published_atbody is excluded because it is the large column. The published set is cached under filament-docs:outline:v2 and busted by every create, save, delete, and restore event on Doc. The cache is opt-in (DOCS_OUTLINE_CACHE env) and off by default on Magic Containers.

Example

A root guide with a child install and a grandchild requirements:

  • guidepath = guide
  • installpath = guide/install
  • requirementspath = guide/install/requirements
graph LR
    A["guide<br/>path: guide"] --> B["install<br/>path: guide/install"]
    B --> C["requirements<br/>path: guide/install/requirements"]
    S["Doc saved<br/>(path/slug/parent changed)"] --> R["buildPath rewrites path"]
    R --> K["saved hook re-saves children"]
    K --> F["DocOutline::flushCache"]

See also

Built by Qcentic