INTERNAL TOOLS // KB

KB ARTICLE BUILDER

DEMO MODE

Knowledge base for tl-kb-builder.html — covers architecture, all steps/panels, every config field, wiring status, documented limitations, proxy checklist, and troubleshooting.

$ ~/platform/kb/docs cat kb-dashboard-tl-kb-builder.html
What Is This Tool

The KB Article Builder is a 5-step wizard for creating structured Knowledge Base articles inside the MSP AI Platform. Techs fill in article info, symptoms, procedure steps, notes, and tags — the builder assembles them into a formatted article ready for copy-paste into a KB system, export as plain text, or (when proxy is live) direct persistence to a backend KB API.

The tool is a sub-page served inside the MSP AI Platform parent shell. It loads ../nav.js to inherit the parent nav. All article generation logic is client-side JavaScript with no external runtime dependencies.

Article Types Supported

TypeIconUse Case
Deployment Guide🚀Step-by-step install, onboarding, or setup of a tool or service
Break-Fix🔧Troubleshooting an error, failure, or incident with a known resolution
Policy / Config📋Standards, configuration references, compliance baselines, or policies
Integration Status
Action / FeatureStatusNotes
5-step wizard UILiveFully functional. Navigation, validation, preview all wired.
Article type selectionLiveDeploy / Break-Fix / Policy toggles update step 2 labels dynamically.
Symptom builderLiveDynamic add/remove, bound to symptoms[] array.
Step builder with CMD blocksLivePer-step toggle for CMD textarea. Rendered in preview and export.
Tag inputLiveEnter/comma to add, backspace to remove, suggestion pills.
Live preview (Step 5)LivebuildPreview() renders full formatted article from current state.
Copy to clipboardLivenavigator.clipboard.writeText — requires secure context (HTTPS or localhost).
Export plain text (.txt)LiveBlob download. Filename: kb-{slug}-YYYY-MM-DD.txt
Product / OS / Affected pills in exportFixedFIX 4: previously these fields were silently dropped from buildPlainText() and submitArticle(). Now included.
KB ID generationClient-sideKB-YYYYMMDD-XXXX — locally generated, not globally unique until persisted.
Article persistence (POST /kb/articles)Activates when proxy is liveCommented-out fetch() in submitArticle(). Wire to custom KB backend.
IT Glue exportActivates when proxy is livePOST /itglue/documents — requires IT Glue API key in proxy.
ConnectWise ticket attachActivates when proxy is livePOST /cw/service/tickets/{id}/notes — appends article to CW ticket.
nav.js parent injectionVia parent shellFIX 6: script tag added. Loads ../nav.js deferred. Works when served from parent directory.
loadDashboard() / startAutoRefresh() / refreshAll()Wired — demo modeFIX 7: suite-standard proxy pattern added. No-op in demo. Activates when KB API endpoint is live.
Architecture

The KB Builder is a single-file, self-contained HTML application. All state is held in six JavaScript variables. There is no framework, no bundler, and no server-side rendering. The wizard flow is driven by goTo(step) which validates the current step before advancing.

State Variables

VariableTypeHolds
currentStepintActive wizard step (1–5)
selectedTypestring'deploy' | 'fix' | 'policy'
selectedDiffstring'low' | 'med' | 'high'
selectedImpactstring'low' | 'med' | 'high'
selectedCalloutstring'note' | 'tip' | 'warn' | 'danger' | 'none'
tags[]string[]All current tags
steps[]object[]{ id, text, cmd, showCmd } per step
symptoms[]string[]All current symptom/overview entries

Proxy-Ready Wiring Pattern

// loadDashboard() — called on DOMContentLoaded async function loadDashboard() { if (isLive) { // REAL FETCH — uncomment when proxy is live: // const res = await fetch(PROXY.base + '/kb/articles/count'); // const data = await res.json(); setStatus('live'); } else { setStatus('demo'); // demo fallback — UI initialises normally } } // refreshAll() — called every 30s by startAutoRefresh async function refreshAll() { if (isLive) { await loadDashboard(); } // DEMO: no-op — builder state is local, no data to drift } // startAutoRefresh(30000) — suite-standard scheduler function startAutoRefresh(intervalMs = 30000) { _refreshTimer = setInterval(refreshAll, intervalMs); }

Article Output Pipeline

The same state is consumed by three output paths. All three were audited for completeness — the product/OS/affected/time fields were previously missing from the export and summary paths (fixed in FIX 4).

PathFunctionOutput
Live previewbuildPreview()Formatted HTML rendered into #previewCard on Step 5
Summary screensubmitArticle()Populates #summaryWrap cards and sum-* elements
Plain text exportbuildPlainText()Structured .txt file with all fields, exported via Blob
Audit Log — All Fixes Applied
FIX 1 — KTC Home Bar Removed

The original file contained <header class="topbar"> with a .tb-brand div containing the KTC logo and all associated CSS blocks (.topbar, .tb-brand, .tb-logo, .tb-name, .tb-right, .tb-btn, .tb-tag). These were removed. The page now uses the IVR-pattern topbar with the layer-badge and Orbitron h1, inheriting nav from the parent shell.

FIX 2 — Theme Aligned to IVR Ground Truth

The original used JetBrains Mono / Exo 2 / Inter font stack, a #020406 background, and CSS tokens like --surface, --bdr, --txt2. All replaced with IVR ground-truth tokens: Orbitron / Share Tech Mono / Rajdhani, #0a0a0f bg, and the exact --panel / --border / --text / --cyan etc. variable set. Grid and scanline overlays match the IVR console exactly.

FIX 3 — goTo() Back-Navigation Bug

Original code always executed node${currentStep}.classList.add('done') regardless of direction. Navigating backward (e.g. step 3 → step 1) marked node3 as "done" even though the user was going back, leaving incorrect green "completed" markers on nodes the user went back past.

Fix: wrapped the done-add in a forward-only guard. When going backward, all nodes from the destination index onward have their "done" class removed.

FIX 4 — Product / OS / Affected / Time Missing from Export + Summary

Four pill groups captured state that was only used in buildPreview() but silently dropped from both buildPlainText() and submitArticle(): product/platform, OS scope, affected users, and time estimate. All four are now included in the plain-text export (added as labelled lines after Tags) and in a new "Product / OS / Affected" summary card plus "Est. Time" summary card. A helper function getPillVals(id) is used consistently across all three output paths.

FIX 5 — resetBuilder() Missing Callout-Opt Clear

The reset function used querySelectorAll('.toggle-opt, .prio-card, .pill') which missed .callout-opt buttons. After a reset, any previously selected callout type (Note / Tip / Warning / Critical) remained visually selected. Fixed by adding .callout-opt to the selector.

FIX 6 — nav.js Script Tag Added

The file is a sub-page of the MSP AI Platform parent shell. The original file had no <script src="../nav.js" defer></script> tag. Added without touching any other functionality. Will silently 404 if opened standalone — expected behavior.

FIX 7 — Proxy-Ready Wiring Added

The original had no loadDashboard(), startAutoRefresh(30000), or refreshAll() — inconsistent with the rest of the console suite. All three added. isLive flag defaults false. Commented-out real fetch() call placed in submitArticle() for KB persistence. Demo banner added matching the IVR console pattern. Status dot shows DEMO MODE (yellow) / KB API ONLINE (green).

Step 1 — Article Info
FieldRequiredDescription
Article TitleFree-text. Becomes article header. Validated non-empty on Next.
Author / Tech NameFree-text. Validated non-empty. Appears in preview meta and export.
Client / AccountOptional. Leave blank for general articles. Displayed in preview meta.
Article TypeToggle: Deploy / Break-Fix / Policy. Drives step 2 label changes. Validated on Next.
CategorySelect: Backups, Networking, Security, Endpoints, Email, Identity, Cloud, Servers, Printing, Hardware, Other.
DifficultyCard: Basic / Intermediate / Advanced. Stored in selectedDiff. Included in export.
Affected Product / PlatformMulti-select pill group (13 options). Now included in export and summary (FIX 4).
OS / Environment ScopeMulti-select pill group (9 options). Now included in export and summary (FIX 4).
Step 2 — Symptoms / Overview

Labels and heading adapt based on article type selected in Step 1. "Deploy" shows "Use Case / Overview". "Break-Fix" shows "Symptoms / Triggers". "Policy" shows "Scope / Overview".

FieldRequiredDescription
Symptoms / Use-Case listDynamic add/remove rows. At least one non-empty entry required. Stored in symptoms[].
Error Codes / Event IDsFree text. Rendered as "Error Codes:" line in export if populated.
Who is AffectedMulti-select pills (6 options). Now included in export and summary (FIX 4).
Business Impact / UrgencyCard: Low / Medium / High. Stored in selectedImpact. Included in export.
Step 3 — Procedure
FieldRequiredDescription
Steps (list)Dynamic add/remove. Each step has a text area and optional CMD toggle. At least one non-empty step required. Stored in steps[].
CMD block (per step)Optional per-step. Toggle button shows/hides a green-tinted mono textarea. Rendered in preview and export as "CMD: ..." line.
Expected OutcomeFree text. Renders as bordered "Expected outcome:" line in preview and export.
Estimated TimeSingle-select pill (6 options). Now included in export and summary (FIX 4).
Step 4 — Notes & Tags
FieldRequiredDescription
Callout TypeNote / Tip / Warning / Critical / No callout. Stored in selectedCallout. Controls border/bg color in preview. Reset now correctly clears this (FIX 5).
Callout TextFree text. Only rendered if callout type is not "none" and text is non-empty.
Related ArticlesFree text. Rendered as "Related:" line in export if populated.
Known Limitations / GotchasFree text. Rendered as "Gotchas:" line in export if populated.
TagsType + Enter or comma to add. Backspace removes last tag. At least one required. 12 suggestion pills available.
Step 5 — Review

buildPreview() fires when goTo(5) is called. Renders a live preview card showing exactly how the article will appear. All fields including product/OS/affected/time are rendered in the preview meta bar. Submitting calls submitArticle().

Preview fidelity The preview reads from the same state arrays (symptoms[], steps[], tags[]) and DOM inputs as the export. What you see in preview is what you get in the exported .txt file.
Summary Screen

Shown after submitArticle() fires. The form and progress rail are hidden. Summary cards display all collected fields. Three action buttons are available.

ButtonFunctionStatus
Export Plain TextexportArticle()Live — Blob .txt download
Copy to ClipboardcopyArticle()Live — navigator.clipboard (HTTPS required)
Build Another ArticleresetBuilder()Live — Full state reset, re-init
API Endpoints
All actions are client-side only in the current build No external network calls are made. All output is generated in-browser. The proxy seam is present in submitArticle() — uncomment the apiFetch() call to activate persistence.
ActionEndpointMethodStatus
Submit article (persist)/kb/articlesPOSTActivates when proxy is live
Export .txtBlob download — no endpointN/ALive
Copy to clipboardnavigator.clipboard APIN/ALive — HTTPS required
IT Glue push/itglue/documentsPOSTActivates when proxy is live
CW Manage attach/cw/service/tickets/{id}/notesPOSTActivates when proxy is live
KB article count/kb/articles/countGETloadDashboard() seam — proxy live only
nav.js../nav.js (parent directory)Script tagVia parent shell
Google Fontsfonts.googleapis.comGETExternal CDN
Documented Limitations
No KB Persistence Backend

Articles generate a local KB ID (KB-YYYYMMDD-XXXX) using Date + Math.random(). IDs are not globally unique across sessions and are not stored anywhere. Articles exist only in memory until exported or copied. Wire POST /kb/articles in submitArticle() when a KB backend is available.

No ConnectWise / IT Glue Integration

There is no native KB article creation endpoint in the ConnectWise Manage REST API. CW Manage's closest option is POST /service/tickets/{id}/notes — attaching the article text as an internal note on a ticket. IT Glue has a Documents API (POST /documents) but requires an API key and auth headers managed by the proxy. Both require proxy activation.

No CSAT Endpoint in CW Manage

ConnectWise Manage has no CSAT satisfaction score in the public REST API. Not applicable to this tool type but documented for suite consistency. Use SmileBack or Nicereply integrations for CSAT data.

Copy to Clipboard Requires HTTPS

navigator.clipboard.writeText() is restricted to secure contexts (HTTPS or localhost). On plain HTTP the call will be rejected. The export (.txt download) path works regardless of protocol.

nav.js Requires Parent Shell

Opening tl-kb-builder.html standalone will produce a 404 on ../nav.js. This is expected — the nav is injected by the parent shell. The wizard functionality works fully without the nav.

Article State Is Not Persisted Between Sessions

There is no localStorage draft save. Closing or refreshing the browser tab discards all wizard progress. A draft auto-save could be added by serialising state to localStorage on each step transition — not yet implemented.

Proxy Activation Checklist
  • FIX 1: KTC home bar removed — sub-page pattern correct.
  • FIX 2: IVR ground-truth theme applied — fonts, tokens, grid/scanline match.
  • FIX 3: goTo() back-navigation bug fixed — no stale .done markers.
  • FIX 4: Product / OS / Affected / Time included in export and summary.
  • FIX 5: resetBuilder() .callout-opt clear added.
  • FIX 6: nav.js script tag added.
  • FIX 7: loadDashboard() / startAutoRefresh(30000) / refreshAll() wired. Demo banner active.
  • Build POST /kb/articles endpoint in proxy — accepts full article payload, returns persisted ID.
  • Set isLive = true in tl-kb-builder.html. Uncomment apiFetch() in submitArticle().
  • Verify demo banner hides and status dot turns green on live load.
  • If IT Glue push is needed: add API key to proxy, uncomment POST /itglue/documents call.
  • If CW Manage attach is needed: pass ticket ID into submitArticle(), uncomment POST /cw/service/tickets/{id}/notes call.
  • Draft auto-save: serialise steps[]/symptoms[]/tags[]/selectedType/etc. to localStorage on each goTo() call. Add "restore draft" prompt on load.
  • KB search: add GET /kb/articles?q= endpoint and wire a search input to the summary action row.
Troubleshooting

Nav bar not showing

Cause File opened standalone — ../nav.js 404s. Expected when not served from parent shell. Wizard works fully without nav.

Copy to Clipboard does nothing / throws

Cause HTTP (non-secure) context. navigator.clipboard requires HTTPS or localhost. Use Export Plain Text instead, or serve from HTTPS.

Callout type still shows selected after Build Another Article

Cause (historical — now fixed) FIX 5: .callout-opt was not in the resetBuilder() selector. Now cleared. Confirm you have the updated file.

Going back from Step 3 to Step 1 shows nodes 2 and 3 as "done"

Cause (historical — now fixed) FIX 3: goTo() always added .done regardless of direction. Now fixed — backward navigation clears .done from all nodes at or after the destination.

Product / OS / Time fields missing from exported .txt

Cause (historical — now fixed) FIX 4: buildPlainText() and submitArticle() did not read those pill groups. Now fixed — all four fields included in all three output paths.

Steps or symptoms don't update when I type

Cause The textarea oninput handler updates the array index when the DOM fires. If the textarea was added before the array entry existed (e.g. from a stale renderSteps() call), the index may be stale. Click "Remove" and re-add the step to resync. This is a low-probability edge case in the current build.

Article ID is duplicated across two submissions in the same session

Cause KB IDs use Math.random() with a 9000-value range. Collision probability in a single session is very low but possible. When proxy and KB backend are live, the backend should generate and return the canonical unique ID, replacing the client-side generated one.