Articles in the Knowledge Base move through three statuses. Editors transition them via the buttons in The Editor; the status is also visible as a coloured badge on every row of the admin landing.
Primary status values
The kb_article.status column stores one of three string values, enforced by a CHECK constraint at the schema level.
| Status | Badge colour | Where visible | Set by |
|---|---|---|---|
DRAFT | Grey | Admin only. | Default state for new articles. Set automatically by **Create draft** on `/admin/new`, or by the agent API import endpoint when `publish: false`. |
PUBLISHED | Green | Public reader, chat-widget, admin. | Set by clicking **Publish** in the editor, or by the agent API when `publish: true`. Triggers `revalidatePath` on `/`, `/a/[slug]`, and `/admin`. |
ARCHIVED | Amber | Admin only. | Set by clicking **Archive** in the editor (only available when status is currently PUBLISHED) or by `POST /api/kb/admin/articles/[id]/archive`. |
The pending-draft chip
A separate state lives alongside status: an article can have a draft stashed in the kb_article_draft table even while its public status remains PUBLISHED. This happens whenever an author edits a published article and clicks Save Draft without clicking Publish.
| Indicator | Where | Meaning |
|---|---|---|
| Amber draft pending chip | Next to the status badge in the editor header. | The article has both a live published version AND an unpublished draft. The next time you click Publish, the draft replaces the public version. |
| (no chip) | ā | No pending draft. The editor body matches the public version exactly. |
The pending draft body sits in kb_article_draft.body_json. Publish deletes the draft row in the same transaction as the status update ā that's how the chip clears immediately after publishing.
Status transitions
| From | Action | To | Side effects |
|---|---|---|---|
| (no row) | Create draft / agent import with publish: false | DRAFT | kb_article row created, no publication. |
DRAFT | Publish | PUBLISHED | Body sanitised on write, draft row deleted, paths revalidated. |
PUBLISHED | Save Draft (after edits) | PUBLISHED + draft pending | kb_article_draft row written; the public body unchanged. |
PUBLISHED + draft pending | Publish | PUBLISHED (chip cleared) | Draft body replaces the public body; draft row deleted. |
PUBLISHED | Archive | ARCHIVED | Public reader returns 404 for /a/<slug>; chat-widget hides the article. |
ARCHIVED | Re-import via agent API with publish: true | PUBLISHED | Article re-appears for readers. |
There is no in-UI button to un-archive an article today. The cleanest path is the agent API: import with the same slug and publish: true. Slug is preserved on upsert, so old links keep working.
Visibility matrix
Which status reaches which reader surface.
| Surface | DRAFT | PUBLISHED | ARCHIVED |
|---|---|---|---|
Public reader (/, /a/<slug>, /f/<slug>) | Hidden | Visible | Hidden |
| Chat-widget Help tab (folder tree, search, article view) | Hidden | Visible | Hidden |
Admin landing (/admin) | Visible (with badge) | Visible (with badge) | Visible (with badge) |
Search API (/api/kb/search) | Excluded | Included | Excluded |
Public folder tree API (/api/kb/folders) | Excluded | Included | Excluded |
| Related articles panel | Excluded (never as source or target) | Included | Excluded |
The asymmetry is deliberate: archives are almost the same as deletes from a reader's perspective, but the article stays in the database, the slug remains reserved (so a future publish under the same slug works), and managers can audit the historical content.
Related
- Manage articles and folders ā where status badges appear and how to trigger transitions.
- The Editor ā the buttons that change status.
- The Knowledge Base ā the reader surfaces affected by status.