Overview
The Docs CMS plugin is a first-party panel plugin that stores documentation pages as a tree and gives editors a drag-handle sidebar outline editor. It owns the data model, the admin CRUD, and the outline cache; the public /docs/{path} route is wired by the clone, not by the plugin.
Storage
Pages live in the doc_pages table — an adjacency list with a cached denormalised path.
| Column | Purpose |
|---|---|
id |
Primary key |
parent_id |
Self-FK, cascade-on-delete (subtree goes with the parent) |
slug |
URL segment for this node |
path |
Full materialised path, unique (e.g. plugins/docs-cms/overview) |
position |
Sibling order, 1-based after applyTree |
body |
Markdown (longText) |
published_at |
null or past = published; future = scheduled |
user_id |
Author FK, restrict-on-delete |
seo_meta |
Polymorphic SEO via filament-seo (HasSeo) |
Doc::booted() builds path on save (buildPath()), re-saves children when path/slug/parent_id change, and busts the outline cache on save/delete/restore.
Components
FilamentDocsPlugin::make()— the panel plugin;register()mountsDocResourceand theArrangeDocspage.Docmodel (Mamenein\FilamentDocs\Models\Doc, tabledoc_pages) — tree, publish scope,publicPath(), media collectionbodyon thes3disk.DocResource— Create / Edit / List pages; form has parent select, title, slug,MediaMarkdownEditorbody,PublishStatus,SeoFields.ArrangeDocspage (Docs sidebar) — renders thefilament-docs::sidebar-editorview;reorder()authorises every moved doc then runsDocOutline::applyTree()inside a transaction.DocOutline—tree(),flatten(),moveUp/Down,nest/unnest,applyTree(),idsInTree().
Outline cache
DocOutline::tree(publishedOnly: true) selects only id, parent_id, title, slug, path, position, published_at — body is excluded — in one query. When DOCS_OUTLINE_CACHE=true the published set is cached as plain attribute arrays (binary-safe for libSQL cache stores) and hydrated back into Doc models. Saving or deleting any doc calls DocOutline::flushCache(). The editor view always fetches live (publishedOnly: false).
Public rendering
The plugin does not register /docs/{path}. The clone wires the route and the Blade view; it calls Doc::publicPath() (/docs/{path}) for links and the resource preview action.
flowchart LR
A["Arrange Docs (drag)"] --> B["DocOutline::applyTree"]
B --> C["doc_pages\nparent_id / position / path"]
C --> D["DocOutline::tree\n(cached, body excluded)"]
D --> E["clone route\n/docs/{path}"]
C -. save/delete .-> F["flushCache"]
F --> D