opendesk
PublikKNOWLEDGE_BASE.md
Agents write articles in the desk at /opendesk/kb. Customers and guests read them in the portal at /help. This file follows an article from the database to both apps. For how the portal itself is built, read README.md.
Data
| DocType | Folder under opendesk/opendesk/doctype/ | Holds |
|---|---|---|
OD Article | od_article | title, category, content, excerpt, author, status, visibility, title_slug, views |
OD Article Category | od_article_category | name, description, icon, pinned, pinned_order |
OD Article Feedback | od_article_feedback | one vote per user or guest visitor: 0 none, 1 like, 2 dislike |
OD Settings holds the site-wide switches on its knowledge base tab:
public_knowledge_base: guests can read the KB. If it is off, guests must sign in.prefer_knowledge_base: the customer home is the KB (/help), not the ticket list (/help/my-tickets).allow_anonymous_article_voting: guests can vote.banner_image,banner_preset: the banner on the KB home.
Who can read what
Only Published articles are readable outside the desk. visibility then decides who sees an article:
| Visibility | Guest | Customer | Agent |
|---|---|---|---|
Public | yes, if public_knowledge_base is on | yes | yes |
Customers | no | yes | yes |
Private | no | no | yes |
Agents see every article, in every status. A signed-in user without a customer role sees only Public.
The rules live in od_article/od_article.py:
make_article_filters()builds the filters that every list query uses.can_view_article()checks one article.permission_queryandhas_permissionapply the same rules to Frappe permissions.opendesk/hooks.pyregisters them.
A category has no visibility field. get_category_visibility() in od_article_category.py reads it from the category's articles. An article that joins a category can only get stricter visibility, never wider (get_stricter_visibility()).
The General category is reserved. It cannot be renamed or deleted.
APIs
opendesk/api/knowledge_base.py has the KB endpoints.
- Reads (guests allowed,
GET):get_categories,get_articles,get_kb_sidebar,get_article,get_article_markdown,search_articles. - Guest writes (
POST, rate limited):vote_on_article,increment_views. A guest voter is known by theod_visitorcookie. - Agent only:
create_category,delete_articles,move_to_category,merge_category,get_category_visibility,set_category_visibility,get_general_category.
Every guest endpoint calls validate_public_access() first. Keep that call in any new guest endpoint.
Other files:
opendesk/api/article.py:get_related(articles for a ticket),get_article_statsand search helpers.opendesk/search.py: the RediSearch index for articles.after_migrateand a scheduled job build it.opendesk/api/config.py:get_configgives the portal its KB flags, banner and KB form scripts.
Desk: authoring
| What | Where |
|---|---|
| Article and category list | desk/src/pages/knowledge-base/KnowledgeBaseAgent.vue (/opendesk/kb) |
| Read and edit an article | desk/src/pages/knowledge-base/Article.vue (/opendesk/kb/articles/:articleId) |
| New article | desk/src/pages/knowledge-base/NewArticle.vue |
| Category, access, move and merge dialogs | desk/src/components/knowledge-base/ |
| Desk KB state | desk/src/stores/knowledgeBase.ts |
| KB settings tab | desk/src/components/Settings/KnowledgeBase/KnowledgeBase.vue |
The desk links to the portal copy of an article with CUSTOMER_PORTAL_ROOT + ROUTES.article(...) from @opendesk/shared.
Portal: reading
| Page | URL | Data |
|---|---|---|
public_kb | /help | get_categories, get_articles (popular or recent) |
categories | /help/categories | get_categories |
category | /help/category/:category | get_articles for one category |
article | /help/articles/:name-slug | get_article, increment_views, vote_on_article, get_article_markdown |
All four pages allow guests and use useKnowledgeBaseHeader and the kb_settings Studio Component. The sidebar, the article cache and hover prefetch are in studio/opendesk/stores/knowledgeBase.ts. The article parts (body, contents, feedback, sidebar, "copy for LLM") are in studio/opendesk/components/knowledge_base/.
Search (PortalArticleSearch) and the article suggestions on the new ticket form both use useArticleSearch, which calls search_articles.
Settings shared by both apps
The KB look and feel (banner, pinned categories, header links) has one form, shared/src/settings/KnowledgeBaseForm.vue. The desk Settings tab and the portal Settings dialog both render it.
shared/src/settings/knowledgeBaseDraft.ts holds the unsaved draft. It writes OD Settings, the category pins and the header links. Header links are stored in an OD Form Script with apply_to_knowledge_base set.
?preview=1 on the KB home shows the unsaved draft (shared/src/knowledgeBasePreview.ts).
Old URLs
website_redirects in opendesk/hooks.py keeps the URLs of the old portal working:
| Old | New |
|---|---|
/opendesk/kb-public | /help |
/opendesk/kb-public/articles/<name> | /help/articles/<name> |
/opendesk/kb-public/<category> | /help/category/<category> |
Tests
- Backend:
opendesk/tests/api/test_knowledge_base.py(public reads, customer-only articles, permissions, category access, search),opendesk/tests/api/test_article.py,opendesk/tests/test_search.py, and the DocType tests inod_articleandod_article_category. - End to end:
e2e/tests/knowledge-base/has the portal walkthrough and the agent spec.e2e/helpers/portal.tsmakes categories and articles over REST.
When you add a guest endpoint, add a test that a guest is refused while public_knowledge_base is off.