MSP PLATFORM // KNOWLEDGE BASE
FIELD INTEL CONSOLE
A field resolution knowledge base for MSP engineering teams. Engineers log real incident resolutions — exact symptoms, root cause, and the fix that worked — so the next engineer hitting the same P1 can find a pattern match in seconds rather than starting from zero.
File
field-intel-console.html
Backend
SharePoint REST (Phase 1)
Refresh
On-demand
Demo Seed
20 entries pre-loaded
Status
Demo — SP list not connected
Overview
What Is This Tool

The Field Intel Console is not a knowledge base in the traditional sense. It does not contain how-to articles, vendor documentation, or step-by-step guides for known procedures. What it contains are field resolutions — documented instances where an engineer encountered a unique or non-obvious problem, identified the root cause, and applied a specific fix that worked.

The design premise is recognition-first. When an engineer picks up a P1, they are not browsing — they are scanning for a match. The card layout surfaces the symptom triggers prominently so an engineer can confirm or rule out a match in under five seconds. Only if a match is found does the engineer expand the detail to read the fix.

Who adds entries: A small team of engineers logs resolutions after closing incidents where the fix was non-obvious, undocumented, or likely to recur. Standard troubleshooting steps that are already in vendor documentation do not belong here. If a vendor KB article already covers it, it does not need a Field Intel entry.

Current state: All UI is fully built. The list view, board view, detail modal, add entry panel, filters, and completeness tracking all render correctly in demo mode with 20 pre-loaded seed entries. All SharePoint wiring is written, commented, and ready to activate behind DEMO_MODE = true.

Integration Status
Integration Map
Integration Status
DEMO MODE ACTIVE
SharePoint REST — entry storage, retrieval, and submission
Activates when SP list configured
nav.js — top navigation injected by parent platform
Active — sub-page pattern
No vendor APIs — this console does not call any MSP vendor endpoints
By design — standalone
Authentication — no standalone auth; inherits from parent platform session
SP session used for REST calls
Intentionally no vendor API calls Unlike the IVR Triage Console or SentinelOne dashboard, the Field Intel Console has no vendor integrations. It is a documentation tool, not an operations console. The only external dependency is SharePoint for persistence. This is a deliberate design boundary — keep it clean.
Architecture
System Architecture

The console follows a simple browser → SharePoint REST pattern with no intermediate proxy required. SharePoint's built-in authentication handles identity. The browser calls the SP list API directly using the active SharePoint session cookie.

┌──────────────────────────────────────────────────────────┐ │ Field Intel Console (browser) │ │ loadDashboard() → fetchEntries() │ │ submitEntry() → saveEntry() │ │ DEMO_MODE=true → SEED[] local data (20 entries) │ │ DEMO_MODE=false → SharePoint REST │ └──────────────────────┬───────────────────────────────────┘ │ SP REST API (session auth) ▼ ┌──────────────────────────────────────────────────────────┐ │ SharePoint List: FieldIntelEntries │ │ GET _api/web/lists/getbytitle()/items │ │ POST _api/web/lists/getbytitle()/items │ │ Auth: X-RequestDigest from _api/contextinfo │ └──────────────────────────────────────────────────────────┘
Sub-page pattern This console does not contain its own header or navigation. The parent platform injects nav.js which renders the top bar. The file's <body> tag carries data-nav-active and data-root attributes that nav.js reads to set the active nav state and resolve relative paths. padding-top: var(--th) offsets the fixed nav bar.
Panels & UI
Stat Strip

Four stat cells run in a single full-width strip below the search and filter bar. In demo mode they reflect live counts derived from the seed data on each render. When the SP list is connected, they recalculate on every loadDashboard() call.

Stat Cell Definitions
PROXY-READY
CellValueCalculation
Total Entries All entries in the list entries.length
P1 Resolutions Entries where sev = "P1" entries.filter(e => e.sev === 'P1').length
Added This Month Entries with a date in the current calendar month Compares e.date year + month against new Date()
Unique Tags Distinct tag values across all entries new Set(entries.flatMap(e => e.tags)).size
Panels & UI
List View

The default view. Entries render as stacked cards in reverse-chronological order. The list is re-rendered on every filter or search change. Cards are pure launchers — clicking anywhere on a card opens the detail modal. There is no inline expand.

Each list card shows: entry ID, severity badge, title, "IF YOU'RE SEEING" trigger bullets, Seen On location, product badges, tag chips, and the completeness track. The OPEN › indicator in the top-right corner signals the click behavior.

Trigger-first card design The "IF YOU'RE SEEING" section is deliberately the first thing the eye hits after the title. An engineer on a P1 starts from symptoms, not from a title. The trigger dot color matches the severity (red for P1, yellow for P2, cyan for P3) so urgency is visible at a glance without reading the badge.
List Card Elements
ElementSource FieldNotes
Left accent stripee.sevRed (P1), Yellow (P2), Cyan (P3)
Entry IDe.idFormat: FI-0001, FI-0002… auto-assigned on save
Severity badgee.sevP1 / P2 / P3
Titlee.titleShort descriptive title
Trigger bulletse.triggers[]One bullet per array item — symptom statements
Seen One.seenOnClient name / device / environment context
Product badgese.products[]Cyan outlined badges — vendor/product tags
Tag chipse.tags[]Clickable — clicking a tag activates that tag filter
Completeness trackComputed4-node rail — see Completeness Track section
Date / Authore.date / e.authorTop-right metadata
Panels & UI
Board View

An alternate view toggled via the ≡ LIST / ⊞ BOARD buttons in the page header. The board organises entries into three columns by severity: P1 Critical (red), P2 Moderate (yellow), P3 Low (cyan). Each column header shows a live count of entries matching the current filters.

Board cards are compact versions of list cards — they show ID, title, Seen On, product badges, and the completeness track, but omit the trigger bullets to save column space. Clicking any board card opens the same detail modal as the list view. All filters and search apply identically to both views — switching views does not reset filter state.

View Toggle Behaviour
TriggerAction
Click ≡ LISTShows #entriesContainer, hides #boardContainer, calls renderEntries()
Click ⊞ BOARDShows #boardContainer, hides #entriesContainer, calls renderBoard()
Search / filter changeCalls currentView==='board' ? renderBoard() : renderEntries() — both views respect active filters
Tag chip click (on card)Activates tag filter and re-renders the current view — does not switch view
Panels & UI
Detail Modal

Clicking any card in either list or board view opens a framed detail window over the page. The modal contains the full entry — all four sections with a clickable section navigation rail at the top. It does not navigate away from the current page.

Modal Elements
ElementDetail
Window chromeEntry ID, full title, severity badge, date, author. Top accent stripe matches severity color.
Section nav4-node clip-path rail: 01 Triggers → 02 Root Cause → 03 Fix Applied → 04 Result. Clicking a node smooth-scrolls to that section.
Triggers sectionSymptom bullets, Seen On, product badges
Root Cause sectionPlain text explanation of what was actually happening
Fix Applied sectionCode block with COPY button — copies the exact fix to clipboard. Labeled "PowerShell / NinjaRMM Console".
Result sectionTwo-column row: Result (green border) + Security Note (orange border) if present
Dismiss Methods
Close button (×) in window chrome
Click the dark overlay outside the window
Press Escape key
Panels & UI
Completeness Track

Every card — in both list and board view — carries a 4-node completeness rail. This is a read-only indicator that shows which fields are populated on each entry without opening it. Engineers can scan the list and immediately identify incomplete entries that need follow-up documentation.

Node States
NodeComplete (cyan)Partial (yellow)Empty (dim)
01 Triggerse.triggers.length > 0No trigger bullets logged
02 Root Cause!!e.rootCauseRoot cause field empty
03 Fix!!e.fixFix field empty
04 VerifiedBoth result and security note presentResult present, security note missingNo result logged
Yellow on node 04 is the most common incomplete state Engineers frequently log the fix and result but skip the security note in the heat of an incident. A yellow node 04 is the reminder to come back and add the security context — especially important for exclusions, policy changes, or anything that touches AV or EDR coverage.
Panels & UI
Add Entry Panel

Opened by the + LOG RESOLUTION button in the page header. The panel slides in from the right side over the current view. The form submits to saveEntry() which routes to the SP list in live mode or pushes directly into the in-memory entries[] array in demo mode.

Form Fields
Demo — activates when SP live
FieldRequiredNotes
PriorityYesP1 / P2 / P3 dropdown
Added ByYesEngineer name or initials — free text
TitleYesShort descriptive title — what was the problem
If You're Seeing...YesOne symptom per line. Each line becomes a trigger bullet on the card.
Seen OnRecommendedClient name / device / environment. Not required but important for context.
Root CauseYesWhat was actually happening — plain text
Fix AppliedYesMonospace textarea — paste exact PowerShell, CLI steps, or console instructions
ResultRecommendedWhat happened after the fix was applied
Security NoteOptionalSecurity implications, trade-offs, coverage changes. Drives node 04 to cyan.
Products InvolvedOptionalGrouped multi-select — see Product Groups section
TagsOptionalComma-separated — used for filtering and tag chip display
Fix Applied is monospace for a reason The fix textarea renders in monospace so engineers can paste PowerShell directly and confirm formatting before saving. What is saved is exactly what will display in the code block and be copied by the COPY button. Do not add markdown formatting or headers — plain commands only.
Panels & UI
Filters & Search

All filter controls sit in the page header above the stat strip. They apply to both list and board views simultaneously. Changing any filter re-renders the current view without resetting the other filters.

Filter Controls
ControlFilters OnBehaviour
Search inputtitle, rootCause, fix, result, seenOn, secNote, triggers[], tags[]Case-insensitive substring match across all text fields. Updates on every keystroke.
All Priority dropdowne.sevP1 / P2 / P3 — single select. In board view, selecting P1 collapses the P2 and P3 columns to empty.
All Tags dropdowne.tags[]Single-tag filter populated from all unique tags across all entries. Updates when entries change.
Quick tag chipse.tags[]Top 10 most frequent tags shown as clickable chips. Clicking toggles the tag filter and syncs with the dropdown. Active chip is highlighted cyan.
Data Model
Entry Schema

Each entry is a flat object. In demo mode entries live in the in-memory entries[] array. In live mode they map to SharePoint list columns via mapSPItem() on read and mapToSP() on write.

Entry Object Shape
FieldTypeSP ColumnNotes
idstringTitleFormat: FI-0001. Auto-assigned. Read-only after save.
sevstringPriority"P1" | "P2" | "P3"
titlestringEntryTitleShort descriptive title
triggersstring[]TriggersJSON-serialised array. Each item is one symptom bullet.
seenOnstringSeenOnFree text — client/device/environment context
rootCausestringRootCausePlain text explanation
fixstringFixAppliedRaw commands or steps — rendered in monospace code block
resultstringResultOutcome description
secNotestringSecurityNoteOptional. Security implications or coverage notes.
tagsstring[]TagsComma-separated string in SP, parsed to array in JS
productsstring[]ProductsComma-separated string in SP, parsed to array in JS
authorstringAuthorEngineer name — free text
datestringCreatedISO date string (YYYY-MM-DD). SP Created field on write.
// mapSPItem — SP list item → entry object (used on fetchEntries) function mapSPItem(i) { return { id: i.Title, sev: i.Priority || '', title: i.EntryTitle || '', triggers: JSON.parse(i.Triggers || '[]'), seenOn: i.SeenOn || '', rootCause: i.RootCause || '', fix: i.FixApplied || '', result: i.Result || '', secNote: i.SecurityNote || '', tags: (i.Tags || '').split(',').map(t => t.trim()).filter(Boolean), products: (i.Products || '').split(',').map(t => t.trim()).filter(Boolean), author: i.Author || '', date: i.Created?.slice(0, 10) || '' }; }
Data Model
Product Groups

The Products Involved field in the add entry panel uses a custom grouped multi-select. Products are defined in PRODUCT_GROUPS at the top of the JS block. Items are grouped by category matching the krawczyk.solutions console suite. An Other row at the bottom accepts free-text entries — type the product name and press Enter.

Product Group Definitions
GroupItems
Security & ThreatMicrosoft Defender, SentinelOne, Huntress, RocketCyber, SOAR, Shadow AI Governance
Network & FirewallFortiGate, SonicWall, Meraki, Auvik
Backup & RecoveryDatto, Cove (N-able), ShadowProtect SPX
RMM & EndpointNinjaRMM, ConnectWise Automate, Intune, ScalePad
PSA & TicketingConnectWise Manage, ConnectWise IVR Triage, Engineer Triage
CommunicationsDialpad, 8x8
Identity & AccessKeeper, Duo, Mimecast
Microsoft StackAzure, Microsoft 365, Purview, Power BI
AI & AutomationCopilot, AI Agent Platform, API Command Console
Business & FinanceIngram Micro, TD Synnex, Azure Provisioner
Adding new products To add a product to the list, update the PRODUCT_GROUPS array in the JS block. Existing entries with custom "Other" products are unaffected — those values are stored as plain strings and will continue to display correctly. No migration is needed.
Configuration
SharePoint Configuration

The SP connection is controlled by two variables at the top of the JS block. Setting DEMO_MODE = false activates live SP calls. SP_CONFIG holds the site URL and list name.

// In field-intel-console.html — top of script block const DEMO_MODE = true; // ← set false to activate SP const SP_CONFIG = { siteUrl: 'https://yourtenant.sharepoint.com/sites/yoursite', listName: 'FieldIntelEntries', };
Required SharePoint List Columns
Column NameTypeNotes
TitleSingle lineBuilt-in SP field — used for the FI-XXXX entry ID
PrioritySingle lineValues: P1, P2, P3
EntryTitleSingle lineThe human-readable entry title
TriggersMultiple linesJSON array of trigger strings
SeenOnSingle lineClient/device context
RootCauseMultiple linesPlain text explanation
FixAppliedMultiple lines (plain text)Commands or steps — preserves whitespace
ResultSingle lineOutcome description
SecurityNoteMultiple linesOptional — security implications
TagsSingle lineComma-separated tag string
ProductsSingle lineComma-separated product string
AuthorSingle lineEngineer name — not the SP system author field
Configuration
Activation Checklist
Steps to Activate Live Mode
01
Create the SharePoint list Create a new list named FieldIntelEntries on the target SharePoint site. Add all columns from the Required Columns table above. Match column names exactly — they are case-sensitive in the REST API.
02
Update SP_CONFIG Set SP_CONFIG.siteUrl to your SharePoint site URL and confirm SP_CONFIG.listName matches the list name exactly.
03
Set DEMO_MODE = false Change DEMO_MODE to false. The SEED data array is ignored when demo mode is off — only SP data is shown.
04
Uncomment the real fetch blocks In fetchEntries(), uncomment the SP REST GET call. In saveEntry(), uncomment the POST block including the getDigest() call. Both have complete endpoint paths, headers, and body structure already written.
05
Verify permissions The SharePoint user accessing the page needs Contribute permission on the FieldIntelEntries list to read and write entries. Read-only users will see entries but the + LOG RESOLUTION form will fail with a 403 on submit.
06
Test with one live entry Load the page, confirm entries load from SP (list will be empty), click + LOG RESOLUTION, fill all required fields, and save. Confirm the entry appears in the SP list and re-renders in the console without a page refresh.
07
Remove or archive seed data The SEED array is ignored in live mode and has no effect on SP data. It can be left in place for future demo use or removed to reduce file size — either is fine.
Configuration
Troubleshooting
Common Issues
SymptomCauseFix
Entries load but submit fails with 403 User has Read but not Contribute on the SP list Grant Contribute permission to the list for the accessing user or group.
Submit fails with "Invalid request digest" getDigest() returned a stale or invalid token Confirm SP_CONFIG.siteUrl is the correct site (not a sub-site). The _api/contextinfo call must hit the same site as the list.
Entries load but all fields are empty except ID SP column names do not match mapSPItem() field mapping Log the raw SP response. Verify column internal names (not display names). SP uses the internal name in API responses.
Triggers render as "[object Object]" or raw JSON Triggers column stored as text but not JSON-parsed Confirm JSON.parse(i.Triggers || '[]') in mapSPItem() is present. The Triggers SP column must store a valid JSON array string.
Tag chips and filter dropdown are empty buildTagFilters() called before entries are loaded Confirm buildTagFilters() is called inside init() after entries = await fetchEntries() resolves.
Board view columns all show "NO ENTRIES" Active severity filter is set to a value that excludes all entries in those columns Clear the severity filter dropdown. The board respects all active filters — a P1 filter will empty the P2 and P3 columns.
Detail modal opens but Fix block is empty e.fix is empty string or undefined for that entry Check the SP list entry directly. If the FixApplied column contains content but the modal shows empty, check the mapSPItem() mapping for that field name.
COPY button on fix block does not work navigator.clipboard requires a secure context (HTTPS) Ensure the page is served over HTTPS. SharePoint always serves over HTTPS so this should not occur in production — it may fail on localhost testing.
+ LOG RESOLUTION panel does not open openPanel() not firing — likely a JS error earlier in the page load Check browser console for errors on page load. A JS syntax error can silently block all button handlers.
MSP PLATFORM // FIELD INTEL CONSOLE // KB v1.0 // 2026