Summary#
use Osysharp.KnowledgeBase@1; gives an app a knowledge base and a public help centre. Say who does what, and where people
go to ask a person:
policy ReadsTeamKnowledge => IsStaff; // reads the articles only the team may read
policy WritesKnowledge => IsStaff; // writes drafts, sends them for review
policy ReviewsKnowledge => IsEditor; // publishes, sends back, archives
policy ManagesKnowledge => IsAdmin; // categories, sections, settings
app.Knowledge = new KnowledgeSetup { Name = "Lumen Docs", ContactPath = "/contact" };The help centre is at /help-centre, the team's desk at /knowledge, the settings at /settings/knowledge.
Signature#
use Osysharp.KnowledgeBase@1; // with Osysharp.Identity@0, Osysharp.Markdown@1, Osysharp.MarkdownEditor@1,
// Osysharp.Seo@0, Osysharp.Memory, Osysharp.Workflow and Osysharp.Ui
app.Knowledge = new KnowledgeSetup {
Name = "", // the help centre's name — "Help centre" when empty
Path = "/help-centre", DeskPath = "/knowledge", // where its pages are, when an app moves them
ContactPath = "", // where "Still need help?" goes — "" offers no way to ask
ContactLabel = "Contact us",
};
// what happens to articles — raised by the kit, heard by any [On] handler after the commit, as the app:
// ArticleSentForReview { Revision } · ArticlePublished { Revision } · ArticleSentBack { Revision, Step }
// ArticleArchived { Article } · ArticleRestored { Article }
// each says itself ("Sent back: …"), so telling somebody needs no words: Notify(author, e)
[On] void Heard(ArticleSentForReview e);
// writing
KnowledgeRevision NewKnowledgeArticle(KnowledgeSection section, string title, string language = "",
KnowledgeAudience audience = KnowledgeAudience.Everyone, string slug = "")
KnowledgeRevision KnowledgeDraft(KnowledgeArticle article, string language = "") // the draft being written, or a new one
KnowledgeRevision KnowledgeDraftFrom(KnowledgeRevision earlier) // put back what an earlier version said
void DiscardKnowledgeDraft(KnowledgeRevision draft) // a draft never sent
// steps — each recorded, applied after the commit
KnowledgeStep SendKnowledgeForReview(KnowledgeRevision draft, string note = "")
KnowledgeStep TakeKnowledgeBack(KnowledgeRevision version)
KnowledgeStep PublishKnowledge(KnowledgeRevision version, string note = "")
KnowledgeStep SendKnowledgeBack(KnowledgeRevision version, string note)
KnowledgeStep ArchiveKnowledge(KnowledgeArticle article, string note = "")
KnowledgeStep RestoreKnowledge(KnowledgeArticle article)
// reading — every one the reader's own, in the reader's language
KnowledgeArticleView KnowledgeArticleView(string slug)
List<KnowledgeShelf> KnowledgeShelves(bool includeTeam = false)
KnowledgeResults SearchKnowledge(string query, bool includeTeam = false, int take = 20)
KnowledgeResults KnowledgeByMeaning(string query, bool includeTeam = false, int take = 5) // by what it is about
List<KnowledgeHit> SuggestKnowledge(string text, int take = 0) // 0: as many as the settings say
// components
KnowledgeSuggestingField(string label, Binding<string> value, …) // a field that offers articles as a person types
KnowledgeQuickSearch(int take = 4, …) // a search for a chat panel or a sidebar
HelpCentreFrame() // design it to put the help centre in your site
// pages: /help-centre, /help-centre/c/{slug}, /help-centre/a/{slug}, /help-centre/search/{query},
// /knowledge, /knowledge/a/{id}, /knowledge/a/{id}/{language}, /knowledge/review, /knowledge/categories
// served: /help-centre/sitemap.xmlDescription#
Who reads what#
A category and an article are for everyone or for the team only (KnowledgeAudience.Team). An article in a
team category is the team's whatever its own audience says. A person outside the team reads an article only while a
version of it is published, it is not archived, and both it and its category are for everyone — and that is a RULE on
the rows, so it holds for every read: the help centre, a search, a suggestion, a query the app writes itself. An
address that names a team article answers "not here", exactly as an address that names nothing does.
SearchKnowledge and the help centre's pages take includeTeam for a reader who is on the team: the team sees its own
articles in the help centre, marked. The help centre's search, SuggestKnowledge and KnowledgeQuickSearch always
leave them out, whoever is typing.
How does a draft become what readers read?#
What an article says is in its VERSIONS, one language each and numbered 1, 2, 3. A draft is the only version whose words change — the title, a line about it, and a markdown body written in the markdown editor. Sending it for review, publishing it, sending it back and archiving are STEPS: each is a row made by the person taking it, under the step's rule (writers send and take back; reviewers publish, send back and archive), and applied after the commit by the kit's own run, which checks it again. A version is never published by editing it. While Review before publishing is on (the default), a reviewer publishes only a version somebody else wrote; with it off, a reviewer may publish a draft of their own. Publishing a version makes the one it replaces an earlier version, kept and readable by the team; "Start a draft from it" puts back what an earlier one said.
Which language does a reader get?#
Each language the app speaks has its own versions of an article, written, reviewed and published on their own. A new language's draft starts as a copy of the original's words, to translate. A reader reads the version in their language (Which language a reader gets — and switching it); with none, the original — and the page says so. Category and section names are [Translatable] — an entity's own words in every language: the team types them in each language on the desk. An article in a right-to-left language reads right to left inside a left-to-right page, and the other way round.
How does a reader find an article?#
Every published version's words are kept as plain text and searched in full text (field search (Matches / TextScore / Similarity)) — every word first, and when no article has them all, any of them, saying so. A search finds an article in any of its languages and shows it in the reader's.
Inflected words find each other. Each version also keeps its words in their base form, stemmed in ITS language (The stemming kit — an inflected word finds its other forms), and a query is stemmed in the reader's: a Swedish reader asking about "betalningen" finds the article that says "betalningar", and an Arabic reader's "بالبطاقة" finds "البطاقات". English, Swedish, Danish, Norwegian and Arabic have stemmers; any other language matches word for word.
By meaning, too. The current version of every published article is indexed by meaning ([Searchable(Memory)]), so
KnowledgeByMeaning(query) finds an article that answers a question in other words — or in another language. It is
for an app with an embedder: without one, the results say so in Unavailable and hold nothing, and word search goes on
working. Both searches apply the same rule — an article for the team only is never in a customer's results, however it
was found. KnowledgeSuggestingField asks once a person pauses and shows nothing until something matches; an article
it offers opens over the form, so what they wrote is still there.
The help centre in your site#
The front page, a category, an article and the search are PARTS (HelpCentreFront, HelpCentreCategory,
HelpCentreArticle, HelpCentreSearch), so a look (Looks — a site's whole design, picked per version) or the app can design them. HelpCentreFrame is the
frame around every help-centre page — nothing by default; design it once to put the help centre in your site's header
and footer. The kit's pages write a head for search engines (head): an article's title, line and canonical
address, a TechArticle and its breadcrumb (Osysharp.Seo), every language's address, and noindex on a team article
and on "not here". /help-centre/sitemap.xml lists every public category and article.
Where does the team write and review?#
/knowledge lists every article with how each of its languages stands; an article's page has its draft in the editor,
what can be done next, where it sits and who reads it, its versions and its steps. /knowledge/review is the queue,
longest-waiting first; /knowledge/categories arranges the shelves. They stand in your app's own shell
([Layout(WorkspaceFrame)] — design WorkspaceShell once, WorkspaceShell, WorkspaceFrame and [Nav] — a kit's pages in your app's shell and navigation) and the knowledge base lists itself
in your navigation ([Nav], Nav.Pages()); take a page over by name to change it.
What personal data does it keep?#
Who wrote and who reviewed an article, and what a reviewer wrote back, are classified (Personal.Identity,
Personal.Content). With Osysharp.Privacy, Osysharp.Privacy.KnowledgeBase arrives by itself (Bridges — a package that arrives when an app uses the two it completes): a person's articles, versions and
steps are in their copy, their review notes are kept out of use on request, and an erasure takes their name off
everything and their notes with it — the articles stay. Whoever answers privacy requests must be able to read the
knowledge base (a writer, reviewer or manager of it).
What is not here#
AI drafts and AI translation of an article — add-ons on this core. Article voting ("was this helpful?") — the SatisfactionSurveys kit's question, asked about an article, when an app wants it.
Examples#
A photo editor documents its features#
app LumenDocs {
use Osysharp.Identity@0;
use Osysharp.KnowledgeBase@1;
use Osysharp.MarkdownEditor@1;
use Osysharp.Seo@0;
use Osysharp.Memory;
use Osysharp.Workflow;
use Osysharp.Ui;
model "model/**/*.osy";
}
using Osysharp.Identity;
using Osysharp.KnowledgeBase;
[Role] enum DocsRole { Authenticator, Writer, Editor }
policy IsWriter => RoleGrant.Any(g => g.Member == user && (g.Role == DocsRole.Writer || g.Role == DocsRole.Editor));
policy IsEditor => RoleGrant.Any(g => g.Member == user && g.Role == DocsRole.Editor);
policy ReadsTeamKnowledge => IsWriter;
policy WritesKnowledge => IsWriter;
policy ReviewsKnowledge => IsEditor;
policy ManagesKnowledge => IsEditor;
app.Knowledge = new KnowledgeSetup { Name = "Lumen Docs", ContactPath = "/contact", ContactLabel = "Ask the Lumen team" };
/// Where "Still need help?" goes — a subject that offers articles as it is typed.
[Route("/contact")] [AllowAnonymous] [Render(CSR)]
component ContactPage() {
string subject = "";
render {
Stack(gap: 4, p: 6) {
KnowledgeSuggestingField("What is it about?", value: subject, placeholder: "One line about it");
}
}
}See also#
- Markdown — what an article's body is; The markdown editor kit — a rich editor you opt into — where it is written
- field search (Matches / TextScore / Similarity) — the full-text search under
SearchKnowledge - Looks — a site's whole design, picked per version — designing the help centre's parts and frame
- head — what a search engine reads on each page
- The Conversations kit — one timeline per conversation, across every channel —
KnowledgeQuickSearch()in the chat'shelpslot - [Settings] and [Setting]: a settings section declared on its row, each field drawn by its type — the settings page the kit declares
- The Privacy kit — erasure that keeps only what the company must or may — a writer's articles and notes in their privacy requests