feat(web): docs cut-over — documentation moved to docs.autopilotmonitor.com

- Remove app/docs (15 sections incl. agent-internals, sidebar, gates, registry)
  and app/changelog; drop the now-unused private-preview.png
- Permanent redirects in next.config.ts: per-section /docs/* mapping to the
  matching GitBook page, /docs catch-all, /changelog -> platform changelog
- All navigation and deep links point at the GitBook site (public navbar,
  authenticated navbar help menu + overflow, global sidebar, landing footer,
  about cards, preview page, dashboard banner, WelcomeMessage, analyze-rules
  and gather-rules helper links) — external links open in a new tab
- SEO: sitemap no longer emits /docs/* or /changelog, robots allow-list
  trimmed; old URLs 308-redirect so link equity moves to the docs domain

Verified: tsc clean, 506 web tests green, production build succeeds.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Oliver Kieselbach
2026-07-06 18:12:31 +02:00
parent 83e4c309bc
commit b054537ad5
37 changed files with 88 additions and 5807 deletions
@@ -289,15 +289,15 @@ export default function AboutPage() {
<section className="bg-white rounded-xl shadow-sm border border-gray-100 p-8">
<h2 className="text-2xl font-bold text-gray-900 mb-4">Explore Further</h2>
<div className="grid grid-cols-1 sm:grid-cols-2 gap-3 text-sm">
<Link href="/docs" className="rounded-lg border border-gray-200 px-4 py-3 hover:border-blue-300 hover:bg-blue-50/50 transition-colors text-gray-700 font-medium">
<a href="https://docs.autopilotmonitor.com" target="_blank" rel="noopener noreferrer" className="rounded-lg border border-gray-200 px-4 py-3 hover:border-blue-300 hover:bg-blue-50/50 transition-colors text-gray-700 font-medium">
Documentation →
</Link>
</a>
<Link href="/roadmap" className="rounded-lg border border-gray-200 px-4 py-3 hover:border-blue-300 hover:bg-blue-50/50 transition-colors text-gray-700 font-medium">
Roadmap →
</Link>
<Link href="/changelog" className="rounded-lg border border-gray-200 px-4 py-3 hover:border-blue-300 hover:bg-blue-50/50 transition-colors text-gray-700 font-medium">
<a href="https://docs.autopilotmonitor.com/changelog/platform-changelog" target="_blank" rel="noopener noreferrer" className="rounded-lg border border-gray-200 px-4 py-3 hover:border-blue-300 hover:bg-blue-50/50 transition-colors text-gray-700 font-medium">
Changelog →
</Link>
</a>
<Link href="/privacy" className="rounded-lg border border-gray-200 px-4 py-3 hover:border-blue-300 hover:bg-blue-50/50 transition-colors text-gray-700 font-medium">
Privacy Policy →
</Link>
@@ -641,7 +641,7 @@ export default function AnalyzeRulesPage() {
<svg className="w-6 h-6 text-indigo-600" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 6v6m0 0v6m0-6h6m-6 0H6" /></svg>
<div>
<h2 className="text-xl font-semibold text-gray-900">Create Custom Analyze Rule</h2>
<p className="text-sm text-gray-500 mt-1">Define conditions and confidence scoring for issue detection — <Link href="/docs/analyze-rules" className="text-indigo-600 hover:text-indigo-800 underline">see documentation</Link></p>
<p className="text-sm text-gray-500 mt-1">Define conditions and confidence scoring for issue detection — <a href="https://docs.autopilotmonitor.com/rules/analyze-rules" target="_blank" rel="noopener noreferrer" className="text-indigo-600 hover:text-indigo-800 underline">see documentation</a></p>
</div>
</div>
{/* JSON Mode Toggle */}
@@ -1,25 +0,0 @@
import type { Metadata } from "next";
export const metadata: Metadata = {
title: "Changelog",
description:
"Latest updates, improvements, and fixes for Autopilot Monitor. Stay up to date with new features and enhancements for Windows Autopilot monitoring.",
openGraph: {
title: "Changelog | AutopilotMonitor",
description:
"Latest updates, improvements, and fixes for Autopilot Monitor. Stay up to date with new features and enhancements.",
url: "https://www.autopilotmonitor.com/changelog",
},
twitter: {
title: "Changelog | AutopilotMonitor",
description:
"Latest updates, improvements, and fixes for Autopilot Monitor. Stay up to date with new features and enhancements.",
},
alternates: {
canonical: "https://www.autopilotmonitor.com/changelog",
},
};
export default function ChangelogLayout({ children }: { children: React.ReactNode }) {
return <>{children}</>;
}
@@ -1,593 +0,0 @@
"use client";
import Link from "next/link";
import { PublicPageHeader } from "../../components/PublicPageHeader";
export default function ChangelogPage() {
return (
<div className="min-h-screen bg-gray-50">
<PublicPageHeader title="Changelog" />
<main className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
<div className="bg-white rounded-2xl shadow-sm border border-gray-200 p-8 sm:p-10">
{/* Intro */}
<div className="mb-10 pb-8 border-b border-gray-100">
<p className="text-gray-600 leading-relaxed">
This changelog tracks significant platform changes during Private Preview —
architecture updates, data flow changes, and anything else that might briefly
affect the UI or monitoring data. If something looks off, check here first.
A recent entry might explain it.
</p>
<p className="mt-3 text-gray-600 leading-relaxed">
Found a bug or want to give feedback?{" "}
<a
href="https://github.com/okieselbach/Autopilot-Monitor/issues"
target="_blank"
rel="noopener noreferrer"
className="text-blue-600 hover:text-blue-800 underline font-medium"
>
Open a GitHub Issue
</a>
{" "}— it helps more than you might think.
</p>
</div>
{/* Entries — newest first */}
<div className="space-y-10">
<div>
<div className="flex items-center gap-3 mb-3">
<span className="text-xs font-mono font-semibold text-gray-400 uppercase tracking-wider">
2026-06-16 - 12:00 CET
</span>
<span className="inline-flex items-center px-2 py-0.5 rounded-full text-xs font-medium bg-blue-100 text-blue-800">
Platform Update
</span>
</div>
<h2 className="text-base font-semibold text-gray-900 mb-2">
Software hub with self-service vulnerability exposure, faster Fleet Health, and expanded MCP tools
</h2>
<ul className="space-y-2 text-sm text-gray-600 leading-relaxed list-none">
<li className="flex gap-2">
<span className="text-gray-400 flex-shrink-0">•</span>
<span><span className="font-medium text-gray-800">Software hub with self-service vulnerability exposure</span> — The App Health page is now a tabbed <Link href="/apps" className="text-blue-600 hover:text-blue-800 underline">Software</Link> hub bringing app installs, installed-software inventory, and CVE/KEV vulnerability exposure together in one place. For the first time, tenant admins can see their own fleet's vulnerability exposure (Fleet Exposure) — previously a Global-Admin-only view — with per-device matches, a severity breakdown, and data-source sync-status counters.</span>
</li>
<li className="flex gap-2">
<span className="text-gray-400 flex-shrink-0">•</span>
<span><span className="font-medium text-gray-800">Faster Fleet Health on large fleets</span> — Fleet Health now loads from server-aggregated metrics endpoints instead of draining up to 200,000 sessions into the browser, so the dashboard opens far faster on big fleets with identical numbers.</span>
</li>
<li className="flex gap-2">
<span className="text-gray-400 flex-shrink-0">•</span>
<span><span className="font-medium text-gray-800">"Not registered" devices overview</span> — A new view under enrollment validation lists, per serial number, devices rejected with HTTP 403 over the last 14 days because they were not in the tenant's Autopilot or Corporate Identifier registry.</span>
</li>
<li className="flex gap-2">
<span className="text-gray-400 flex-shrink-0">•</span>
<span><span className="font-medium text-gray-800">Richer session detail</span> — The Session Info card now shows Reboots, Enrollment Type (Device Preparation / Autopilot, with PreProvisioned and Gather Rules qualifiers), Join Type (Hybrid / Entra), and a "last contact" tooltip. Per-session reboot count is also stored and queryable via MCP.</span>
</li>
<li className="flex gap-2">
<span className="text-gray-400 flex-shrink-0">•</span>
<span><span className="font-medium text-gray-800">Office &amp; RealmJoin install rows</span> — Microsoft 365 Apps (Office) and RealmJoin packages now appear as first-class rows in the session Install Progress alongside Intune apps, with live timers, durations, and exit-code badges. The RealmJoin agent version is shown in the session System panel, and the RealmJoin watcher is now a per-tenant portal toggle (default off).</span>
</li>
<li className="flex gap-2">
<span className="text-gray-400 flex-shrink-0">•</span>
<span><span className="font-medium text-gray-800">Expanded MCP tools</span> — New <code>get_software_inventory</code> and <code>get_app_install_metrics</code> tools surface installed-software inventory and per-app install metrics (including Delivery Optimization peer/MCC offload savings); <code>get_audit_logs</code> gains action / performed-by / entity-type / entity-id filters; <code>list_tenants</code> and a fleet vulnerability summary were added; raw session/event query tools now return literal table rows; hybrid event search is genuinely semantic; and the tool surface is role-aware so Global-Admin-only tools are hidden from regular users. Analysis output also resolves rule-template placeholders so explanations never leak raw <code>{"{{...}}"}</code> tokens.</span>
</li>
<li className="flex gap-2">
<span className="text-gray-400 flex-shrink-0">•</span>
<span><span className="font-medium text-gray-800">Clearer error reporting</span> — Event and error views now show enriched, human-readable error-code descriptions and clearly distinguish a detection-failure from an install-failure from a "likely stuck" enrollment.</span>
</li>
<li className="flex gap-2">
<span className="text-gray-400 flex-shrink-0">•</span>
<span><span className="font-medium text-gray-800">Deep links survive re-authentication</span> — Opening a session, diagnosis, or other in-app link in a new tab now returns you to that page after login instead of dropping you on the dashboard.</span>
</li>
<li className="flex gap-2">
<span className="text-gray-400 flex-shrink-0">•</span>
<span><span className="font-medium text-gray-800">Health dashboard MCP card</span> — The Health dashboard adds an MCP Server card with version and wake-aware cold-start handling, alongside the SignalR quota card.</span>
</li>
<li className="flex gap-2">
<span className="text-gray-400 flex-shrink-0">•</span>
<span><span className="font-medium text-gray-800">Device auto-block on runaway sessions</span> — Devices that emit an excessive number of session events can now be auto-blocked and their sessions killed, with block/kill-by-session-ID shortcuts and ops-alert integration.</span>
</li>
<li className="flex gap-2">
<span className="text-gray-400 flex-shrink-0">•</span>
<span><span className="font-medium text-gray-800">CPU architecture</span> — Device hardware now reports CPU architecture (<code>x86</code> / <code>x64</code> / <code>ARM</code> / <code>ARM64</code>) as a queryable property.</span>
</li>
<li className="flex gap-2">
<span className="text-gray-400 flex-shrink-0">•</span>
<span><span className="font-medium text-gray-800">Security hardening</span> — Added <code>nosniff</code> and stricter <code>x-forwarded-for</code> handling, tightened query-filter validation, enforced tenant-id presence on scoped endpoints, and patched a prototype-pollution advisory in a web dependency.</span>
</li>
</ul>
</div>
<div>
<div className="flex items-center gap-3 mb-3">
<span className="text-xs font-mono font-semibold text-gray-400 uppercase tracking-wider">
2026-05-19 - 12:00 CET
</span>
<span className="inline-flex items-center px-2 py-0.5 rounded-full text-xs font-medium bg-blue-100 text-blue-800">
Platform Update
</span>
</div>
<h2 className="text-base font-semibold text-gray-900 mb-2">
Safe cascade-delete &amp; tenant offboarding, Intune script display names, full Remediation lifecycle, and Agent V2 robustness
</h2>
<ul className="space-y-2 text-sm text-gray-600 leading-relaxed list-none">
<li className="flex gap-2">
<span className="text-gray-400 flex-shrink-0">•</span>
<span><span className="font-medium text-gray-800">Safe session cascade-delete with restore window</span> — Session deletion is now a snapshot-based, crash-safe cascade across all related tables (events, audit, app installs, vulnerability data, software inventory, etc.) with a deterministic order, hash-verified manifest, and a 33-day restore window.</span>
</li>
<li className="flex gap-2">
<span className="text-gray-400 flex-shrink-0">•</span>
<span><span className="font-medium text-gray-800">Async tenant offboarding</span> — Tenant offboarding from <Link href="/settings" className="text-blue-600 hover:text-blue-800 underline">Settings</Link> is now a queued async cascade that flips the tenant to disabled, waits for the config cache to drain, then safely wipes all 24 tenant-scoped tables with fetch-verify-delete semantics. The UI shows a minute-based countdown and you can close the tab — deletion finishes in the background. Self-service re-onboarding still works after a clean offboard.</span>
</li>
<li className="flex gap-2">
<span className="text-gray-400 flex-shrink-0">•</span>
<span><span className="font-medium text-gray-800">Optional Graph add-on — Intune script display names</span> — A new <Link href="/settings/tenant/optional-graph-capabilities" className="text-blue-600 hover:text-blue-800 underline">Optional Graph capabilities</Link> page lets tenant admins grant a tightly-scoped Graph permission to resolve <em>real</em> Intune Platform Script and Remediation display names in session timelines (instead of bare IDs). Opt-in only — no app manifest change for tenants who skip it. The page provides a copy-paste PowerShell command (and a <code>Grant-AutopilotMonitorAddOn.ps1</code> helper) with idempotent grant / verify / revoke flows.</span>
</li>
<li className="flex gap-2">
<span className="text-gray-400 flex-shrink-0">•</span>
<span><span className="font-medium text-gray-800">Full Intune Remediation lifecycle</span> — Health scripts are now captured end-to-end: detection → remediation → post-detection are folded into a single Remediation cycle card with a parent header showing the overall outcome (Compliant, Remediated successfully, Non-compliant after remediation, Remediation script failed, …). A live "running" indicator appears the moment a script starts, ahead of the consolidated final result. Phase-aware semantics avoid counting a non-compliant detection that was successfully remediated as a "failed" event, and a two-stage emission closes the timing gap on short Autopilot sessions.</span>
</li>
<li className="flex gap-2">
<span className="text-gray-400 flex-shrink-0">•</span>
<span><span className="font-medium text-gray-800">SLA notification spam fix</span> — SLA throttling moved from an in-memory cooldown to a persistent per-tenant status row with CAS-guarded at-most-once semantics. AppInstall SLA now actually evaluates against the same ISO-week window as the dashboard, and a single <code>sla_resolved</code> notification fires when a breach clears. Configurable cooldown via <Link href="/settings/global" className="text-blue-600 hover:text-blue-800 underline">Global Settings</Link>.</span>
</li>
<li className="flex gap-2">
<span className="text-gray-400 flex-shrink-0">•</span>
<span><span className="font-medium text-gray-800">Dashboard stats overhaul</span> — The five dashboard cards (Active Sessions, Success Rate, Avg. Duration, Total Today, Failed Today) are now server-aggregated over the full 7-day window instead of derived from the currently-paginated client list, so they no longer drift as the session table grows. Active Sessions is pinned to In-Progress only; Pending (WhiteGlove waiting for power-on) and Stalled remain visible via list filters. Stats reset cleanly on scope changes.</span>
</li>
<li className="flex gap-2">
<span className="text-gray-400 flex-shrink-0">•</span>
<span><span className="font-medium text-gray-800">Agent V2 robustness</span> — Several correctness and recovery fixes: Classic enrollments with Hello disabled no longer deadlock at the AwaitingHello stage (EspExiting now routes through the Hello-disabled fast-path); AwaitingHello is gated on AccountSetup <em>truly</em> succeeding instead of the page-handoff event; new desktop-detector liveness signals (started / first-poll / no-candidate) help distinguish a dead post-reboot agent from broken DAD wiring; four new <code>agent_shutting_down</code> emit paths (Ctrl+C, process exit, unhandled exception, runtime host exit) close gaps that previously left sessions without a shutdown breadcrumb. Hot-path event dictionaries are pre-sized to skip ~3k Gen0 allocations per session.</span>
</li>
<li className="flex gap-2">
<span className="text-gray-400 flex-shrink-0">•</span>
<span><span className="font-medium text-gray-800">Fail-soft runtime handoff &amp; ASR resilience</span> — A Defender ASR rule blocking WMI process creation can no longer strand a freshly-bootstrapped device. The agent's <code>--install</code> now runs a two-tier fallback (WMI Win32_Process → <code>schtasks /Run</code> → next BootTrigger reboot) and treats a runtime-spawn failure as a warning, not a fatal error. The bootstrap script's process probe remains the canonical "did the agent come up" signal.</span>
</li>
<li className="flex gap-2">
<span className="text-gray-400 flex-shrink-0">•</span>
<span><span className="font-medium text-gray-800">Intune dual-stack certificate selection</span> — On Intune-managed devices that have both the MDM device certificate and the newer MMP-C certificate installed side-by-side, the agent now exact-matches the MDM issuer (<code>CN=Microsoft Intune MDM Device CA</code>) before presenting it for mTLS, instead of letting the OS pick. Resolves a class of <code>SecureChannelFailure</code> / <code>ChainFailed</code> rejections that surfaced on newer Windows builds.</span>
</li>
<li className="flex gap-2">
<span className="text-gray-400 flex-shrink-0">•</span>
<span><span className="font-medium text-gray-800">"Likely stuck" app-install hedge</span> — When ESP times out on the Apps subcategory, the in-flight app is no longer left silently frozen in the Installing bucket. It is now promoted as a hedged "likely stuck" entry with confidence <em>presumed</em>, so operators see which app the enrollment was waiting on at termination.</span>
</li>
<li className="flex gap-2">
<span className="text-gray-400 flex-shrink-0">•</span>
<span><span className="font-medium text-gray-800">Notifications &amp; UX polish</span> — Opt-in "enrollment started" webhook (Teams Legacy / Workflow / Slack) fires on fresh session registration and WhiteGlove Part 2 resume, default off so existing tenants don't get a surprise notification storm. The notification bell is now always visible. Sidebar usage telemetry (full / icons / hidden) is captured as a global App Insights property for understanding portal interaction patterns.</span>
</li>
<li className="flex gap-2">
<span className="text-gray-400 flex-shrink-0">•</span>
<span><span className="font-medium text-gray-800">Bugfixes &amp; polish</span> — Various fixes throughout the whole platform</span>
</li>
</ul>
</div>
<div>
<div className="flex items-center gap-3 mb-3">
<span className="text-xs font-mono font-semibold text-gray-400 uppercase tracking-wider">
2026-05-10 - 12:00 CET
</span>
<span className="inline-flex items-center px-2 py-0.5 rounded-full text-xs font-medium bg-blue-100 text-blue-800">
Platform Update
</span>
</div>
<h2 className="text-base font-semibold text-gray-900 mb-2">
Agent V2 rollout, MS-Graph pagination, SignalR push notifications, and security hardening
</h2>
<ul className="space-y-2 text-sm text-gray-600 leading-relaxed list-none">
<li className="flex gap-2">
<span className="text-orange-500 flex-shrink-0">⚠</span>
<span><span className="font-medium text-gray-800">Agent V2 rollout (action recommended)</span> — The agent has been rebuilt on a new internal architecture (Decision Engine, lifecycle-anchor allowlist, Death-Rattle recovery for crashed runs) for more reliable session detection and stricter completion logic. The Intune bootstrapper script (<code>Install-AutopilotMonitor.ps1</code>) was updated and now verifies the runtime process started after launch. Replace the script in your Intune tenant with the latest version from the repository.</span>
</li>
<li className="flex gap-2">
<span className="text-gray-400 flex-shrink-0">•</span>
<span><span className="font-medium text-gray-800">Submit Logs page</span> — A new <Link href="/settings/tenant/support" className="text-blue-600 hover:text-blue-800 underline">Submit Logs</Link> page lets you send diagnostic files to the Autopilot Monitor team without an associated session, useful for issues caught outside of an active enrollment.</span>
</li>
<li className="flex gap-2">
<span className="text-gray-400 flex-shrink-0">•</span>
<span><span className="font-medium text-gray-800">Real-time notifications via SignalR push</span> — The notification bell now updates purely from SignalR events (one fetch on mount, re-fetch on reconnect) instead of polling every 60 seconds, with audience-aware delivery for tenant admins vs members.</span>
</li>
<li className="flex gap-2">
<span className="text-gray-400 flex-shrink-0">•</span>
<span><span className="font-medium text-gray-800">MS-Graph style pagination</span> — All large list endpoints (sessions, events, audit, ops events, reports) now support opt-in <code>nextLink</code> pagination with HMAC-bound continuation tokens. Dashboard, Fleet Health, and MCP tools have been migrated to the new model.</span>
</li>
<li className="flex gap-2">
<span className="text-gray-400 flex-shrink-0">•</span>
<span><span className="font-medium text-gray-800">MCP server</span> — A new <code>get_resource</code> tool, leaner <code>get_session_summary</code> payloads, and a security &amp; capability audit covering OAuth proxy hardening, access-guard tightening, and pagination of the last three legacy diagnostic tools.</span>
</li>
<li className="flex gap-2">
<span className="text-gray-400 flex-shrink-0">•</span>
<span><span className="font-medium text-gray-800">Backend security hardening</span> — Client-certificate chain trust is now pinned to the embedded Intune root certificate, and query-tenant guards moved to centralized middleware.</span>
</li>
<li className="flex gap-2">
<span className="text-gray-400 flex-shrink-0">•</span>
<span><span className="font-medium text-gray-800">Web hardening &amp; portal split</span> — Tightened Content Security Policy, hardened <code>/go</code> bootstrap error handling, and a host-based middleware now cleanly separates the public site from the authenticated portal.</span>
</li>
<li className="flex gap-2">
<span className="text-gray-400 flex-shrink-0">•</span>
<span><span className="font-medium text-gray-800">Web performance</span> — In-flight request collapser (<code>dedupedAuthFetch</code>) eliminates duplicate parallel fetches, the dashboard load path was refactored</span>
</li>
<li className="flex gap-2">
<span className="text-gray-400 flex-shrink-0">•</span>
<span><span className="font-medium text-gray-800">Delivery Optimization</span> — Download breakdowns now include Microsoft Connected Cache (MCC) and LinkLocal sources, applied symmetrically across all layers (collector, telemetry, dashboard).</span>
</li>
<li className="flex gap-2">
<span className="text-gray-400 flex-shrink-0">•</span>
<span><span className="font-medium text-gray-800">WhiteGlove improvements</span> — Timeline now splits Part 1 / Part 2 at the Part-2 <code>agent_started</code> event (not the legacy <code>whiteglove_resumed</code>), Part-2 architectural cleanup landed on the agent side, summary dialog is suppressed on Part 1, and Modern Deployment EventID 1010 was added to the harmless-noise default list.</span>
</li>
<li className="flex gap-2">
<span className="text-gray-400 flex-shrink-0">•</span>
<span><span className="font-medium text-gray-800">Bugfixes &amp; polish</span> — <code>TenantIdResolver</code> fallbacks for non-Type-6 enrollments and Hybrid Join (CloudDomainJoin + MS-Organization-Access cert), event-driven TenantId wait via RegistryWatcher, software-inventory now accepts AAD/MSA SIDs and emits real registry paths, full-width dashboard toggle with <code>?span=</code> URL persistence, SLA violator link routes correctly, and many smaller fixes across pagination, audit fetching, and submit-diag sidebar entries.</span>
</li>
</ul>
</div>
<div>
<div className="flex items-center gap-3 mb-3">
<span className="text-xs font-mono font-semibold text-gray-400 uppercase tracking-wider">
2026-04-16 - 12:00 CET
</span>
<span className="inline-flex items-center px-2 py-0.5 rounded-full text-xs font-medium bg-blue-100 text-blue-800">
Platform Update
</span>
</div>
<h2 className="text-base font-semibold text-gray-900 mb-2">
Completion state machine, SLA &amp; App Health dashboards, Ops Alerts, and Device Preparation groundwork
</h2>
<ul className="space-y-2 text-sm text-gray-600 leading-relaxed list-none">
<li className="flex gap-2">
<span className="text-gray-400 flex-shrink-0">•</span>
<span><span className="font-medium text-gray-800">Session completion state machine</span> — The agent soon uses a dedicated <code>CompletionStateMachine</code> that combines multiple signals (ESP final exit, Hello, Desktop arrival) to decide when an enrollment is truly done. This fixes several cases where WhiteGlove and Hybrid Join sessions were misclassified or never marked complete.</span>
</li>
<li className="flex gap-2">
<span className="text-gray-400 flex-shrink-0">•</span>
<span><span className="font-medium text-gray-800">SLA tracking dashboard</span> — New SLA monitoring page with per-tenant configuration and notification support when SLAs are breached.</span>
</li>
<li className="flex gap-2">
<span className="text-gray-400 flex-shrink-0">•</span>
<span><span className="font-medium text-gray-800">App Health dashboard</span> — New global view of app deployment health with scoped drill-downs and a configurable column picker.</span>
</li>
<li className="flex gap-2">
<span className="text-gray-400 flex-shrink-0">•</span>
<span><span className="font-medium text-gray-800">Ops Events &amp; Ops Alerts</span> — Operational event log plus admin alerts for backend health, blob storage, runaway sessions, and excessive event counts per session.</span>
</li>
<li className="flex gap-2">
<span className="text-gray-400 flex-shrink-0">•</span>
<span><span className="font-medium text-gray-800">Agent emergency / distress channel</span> — A separate low-overhead channel so the agent can still report critical errors when the normal telemetry path is impaired.</span>
</li>
<li className="flex gap-2">
<span className="text-gray-400 flex-shrink-0">•</span>
<span><span className="font-medium text-gray-800">Enhanced analyze rule engine</span> — New <code>in</code> / <code>not_in</code> compare operators, <code>MarkSessionAsFailed</code> action, template variables, per-rule stats card, and a new ESP certificate-error analyze rule (<code>ANALYZE-ESP-002</code>).</span>
</li>
<li className="flex gap-2">
<span className="text-gray-400 flex-shrink-0">•</span>
<span><span className="font-medium text-gray-800">Delivery Optimization</span> — OS-level DO collector, P2P totals in download progress, and DO usage stats in the geographic drill-down.</span>
</li>
<li className="flex gap-2">
<span className="text-gray-400 flex-shrink-0">•</span>
<span><span className="font-medium text-gray-800">Vulnerability matching improvements</span> — Fuzzy (Jaro-Winkler) CPE matching, confidence levels, data freshness indicators, CVE mapping column in the vulnerability report, and WhiteGlove sessions now also get a vulnerability report.</span>
</li>
<li className="flex gap-2">
<span className="text-gray-400 flex-shrink-0">•</span>
<span><span className="font-medium text-gray-800">Device Preparation (WDP v2) groundwork</span> — The agent now distinguishes Classic vs v2 Autopilot flow, and a device-association validator was added on the backend. Device Preparation support is still in active validation.</span>
</li>
<li className="flex gap-2">
<span className="text-gray-400 flex-shrink-0">•</span>
<span><span className="font-medium text-gray-800">IME version history</span> — Intune Management Extension version history is tracked and surfaced via MCP; agents running on outdated IME versions trigger an alert.</span>
</li>
<li className="flex gap-2">
<span className="text-gray-400 flex-shrink-0">•</span>
<span><span className="font-medium text-gray-800">Known Issues page</span> — Dedicated docs page for ongoing issues (replaces the inline list that used to live in this changelog).</span>
</li>
<li className="flex gap-2">
<span className="text-gray-400 flex-shrink-0">•</span>
<span><span className="font-medium text-gray-800">MCP server</span> — Stateless endpoint, tools split into domain modules, new ops-events tool, tool-call telemetry, improved semantic + keyword search, and an integration test suite.</span>
</li>
<li className="flex gap-2">
<span className="text-gray-400 flex-shrink-0">•</span>
<span><span className="font-medium text-gray-800">Security hardening</span> — Centralized tenant-isolation middleware, OData sanitizer, hardened agent config endpoint, cross-tenant fallback fixes, session-aware auto-unblock, and additional request-size / integrity guards on the self-update path.</span>
</li>
<li className="flex gap-2">
<span className="text-gray-400 flex-shrink-0">•</span>
<span><span className="font-medium text-gray-800">Web performance &amp; refactor</span> — Lazy session loading, response compression, more parallel fetches, and a large internal restructuring of the web app into hooks and utils for easier maintenance.</span>
</li>
<li className="flex gap-2">
<span className="text-gray-400 flex-shrink-0">•</span>
<span><span className="font-medium text-gray-800">Bugfixes &amp; UX polish</span> — Quick search, bootstrap scripts, webhook notifications, WhiteGlove timeline rendering, phase-timeline regressions, report upload size, summary dialog launch fallback, NTP / timezone defaults, and many more small fixes.</span>
</li>
</ul>
</div>
<div>
<div className="flex items-center gap-3 mb-3">
<span className="text-xs font-mono font-semibold text-gray-400 uppercase tracking-wider">
2026-03-30 - 12:00 CET
</span>
<span className="inline-flex items-center px-2 py-0.5 rounded-full text-xs font-medium bg-blue-100 text-blue-800">
Platform Update
</span>
</div>
<h2 className="text-base font-semibold text-gray-900 mb-2">
Updated bootstrapper script, agent crash detection, and quick search
</h2>
<ul className="space-y-2 text-sm text-gray-600 leading-relaxed list-none">
<li className="flex gap-2">
<span className="text-orange-500 flex-shrink-0">⚠</span>
<span><span className="font-medium text-gray-800">Updated bootstrapper script (action recommended)</span> — The bootstrapper script (<code>Install-AutopilotMonitor.ps1</code>) now uses SHA-256 integrity verification for agent downloads instead of MD5. If you deployed the script via Intune, it is recommended to replace it with the latest version from the repository for improved security.</span>
</li>
<li className="flex gap-2">
<span className="text-gray-400 flex-shrink-0">•</span>
<span><span className="font-medium text-gray-800">Agent crash detection</span> — The agent now detects and reports unexpected crashes with automatic recovery. Platform-level metrics (CPU, memory, disk) are collected alongside enrollment events for better diagnostics.</span>
</li>
<li className="flex gap-2">
<span className="text-gray-400 flex-shrink-0">•</span>
<span><span className="font-medium text-gray-800">Global quick search</span> — A fuzzy search across sessions, devices, and users is now available from the navigation bar for fast lookups.</span>
</li>
<li className="flex gap-2">
<span className="text-gray-400 flex-shrink-0">•</span>
<span><span className="font-medium text-gray-800">Rate limiting</span> — Per-user request rate limiting protects the backend from excessive API usage.</span>
</li>
<li className="flex gap-2">
<span className="text-gray-400 flex-shrink-0">•</span>
<span><span className="font-medium text-gray-800">Bugfixes</span> — Vulnerability report rescan persistence, orphaned session handling, timezone parsing, and NTP clock-skew warnings improved.</span>
</li>
</ul>
</div>
<div>
<div className="flex items-center gap-3 mb-3">
<span className="text-xs font-mono font-semibold text-gray-400 uppercase tracking-wider">
2026-03-26 - 12:00 CET
</span>
<span className="inline-flex items-center px-2 py-0.5 rounded-full text-xs font-medium bg-blue-100 text-blue-800">
Platform Update
</span>
</div>
<h2 className="text-base font-semibold text-gray-900 mb-2">
Software inventory &amp; vulnerability analysis, new agent signals, and settings overhaul
</h2>
<ul className="space-y-2 text-sm text-gray-600 leading-relaxed list-none">
<li className="flex gap-2">
<span className="text-gray-400 flex-shrink-0">•</span>
<span><span className="font-medium text-gray-800">Software Inventory &amp; Vulnerability Analysis</span> — The agent now discovers installed software across Registry, WMI, AppX/MSIX, and per-user sources and correlates it against NVD and CISA KEV databases. The dashboard shows a vulnerability report with CVSS scores and severity levels. Includes 240+ curated CPE mappings and strict AppX whitelist filtering.</span>
</li>
<li className="flex gap-2">
<span className="text-gray-400 flex-shrink-0">•</span>
<span><span className="font-medium text-gray-800">SecureBoot &amp; time sync</span> — The agent collects SecureBoot certificate details (with a new analyze rule), auto-detects the timezone, and checks NTP offset to catch time-related enrollment failures.</span>
</li>
<li className="flex gap-2">
<span className="text-gray-400 flex-shrink-0">•</span>
<span><span className="font-medium text-gray-800">Security hardening</span> — Request size limits on all submission endpoints and symlink detection in diagnostic paths guard against DoS and path-traversal attacks.</span>
</li>
<li className="flex gap-2">
<span className="text-gray-400 flex-shrink-0">•</span>
<span><span className="font-medium text-gray-800">Settings reorganization</span> — The sidebar now uses expandable sections for a cleaner navigation. Tenant settings were restructured and consolidated.</span>
</li>
<li className="flex gap-2">
<span className="text-gray-400 flex-shrink-0">•</span>
<span><span className="font-medium text-gray-800">OOBE Config viewer</span> — A modal dialog decodes the OOBE configuration bitmask, showing each bit flag with description and confidence level, and detects the enrollment profile type.</span>
</li>
<li className="flex gap-2">
<span className="text-gray-400 flex-shrink-0">•</span>
<span><span className="font-medium text-gray-800">FAQ page</span> — New Docs section covering supported scenarios, deployment, agent capabilities, and troubleshooting.</span>
</li>
</ul>
</div>
<div>
<div className="flex items-center gap-3 mb-3">
<span className="text-xs font-mono font-semibold text-gray-400 uppercase tracking-wider">
2026-03-19 - 12:00 CET
</span>
<span className="inline-flex items-center px-2 py-0.5 rounded-full text-xs font-medium bg-blue-100 text-blue-800">
Platform Update
</span>
</div>
<h2 className="text-base font-semibold text-gray-900 mb-2">
Navigation overhaul, session architecture, new agent signals, and community rules
</h2>
<ul className="space-y-2 text-sm text-gray-600 leading-relaxed list-none">
<li className="flex gap-2">
<span className="text-gray-400 flex-shrink-0">•</span>
<span><span className="font-medium text-gray-800">Unified sidebar</span> — The entire navigation has been redesigned with a global sidebar. The old top nav is gone; settings and admin areas now have their own sidebar sections. Mobile layout also reworked.</span>
</li>
<li className="flex gap-2">
<span className="text-gray-400 flex-shrink-0">•</span>
<span><span className="font-medium text-gray-800">Session index table</span> — Session storage has been fundamentally re-architected for better scalability and reliability.</span>
</li>
<li className="flex gap-2">
<span className="text-gray-400 flex-shrink-0">•</span>
<span><span className="font-medium text-gray-800">New agent signals</span> — The agent now reports <code>agent_shutdown</code> (clean shutdown), <code>hardware_spec</code> (hardware inventory at enrollment), network interface changes, and clock skew deviations for better diagnostics.</span>
</li>
<li className="flex gap-2">
<span className="text-gray-400 flex-shrink-0">•</span>
<span><span className="font-medium text-gray-800">Self-deploying mode detection</span> — The agent now automatically detects self-deploying scenarios and tracks the enrollment finalization process with dedicated events.</span>
</li>
<li className="flex gap-2">
<span className="text-gray-400 flex-shrink-0">•</span>
<span><span className="font-medium text-gray-800">Notification providers</span> — The webhook notification system now supports three providers: Teams Legacy, Teams Workflow, and Slack — selectable per tenant.</span>
</li>
<li className="flex gap-2">
<span className="text-gray-400 flex-shrink-0">•</span>
<span><span className="font-medium text-gray-800">Community rules</span> — A community rule set for gather and analyze rules has been added. Rules now have a JSON view, severity override, and centralized guardrails. New local admin analyze rule included.</span>
</li>
<li className="flex gap-2">
<span className="text-gray-400 flex-shrink-0">•</span>
<span><span className="font-medium text-gray-800">Geographic drill-down</span> — The geographic performance view now supports drill-down to region and country level.</span>
</li>
<li className="flex gap-2">
<span className="text-gray-400 flex-shrink-0">•</span>
<span><span className="font-medium text-gray-800">Mark as success</span> — Sessions can now be manually marked as successful, e.g. after manually resolved enrollments.</span>
</li>
<li className="flex gap-2">
<span className="text-gray-400 flex-shrink-0">•</span>
<span><span className="font-medium text-gray-800">Feedback system</span> — An integrated feedback system with admin management allows direct feedback from within the portal.</span>
</li>
<li className="flex gap-2">
<span className="text-gray-400 flex-shrink-0">•</span>
<span><span className="font-medium text-gray-800">Tenant settings UX</span> — The central save button in tenant settings has been replaced with individual section save buttons. A new Unrestricted Mode option disables most guardrails per tenant request.</span>
</li>
<li className="flex gap-2">
<span className="text-gray-400 flex-shrink-0">•</span>
<span><span className="font-medium text-gray-800">Docs expanded</span> — New general documentation section, IME pattern explanation, and a public sites sidebar added.</span>
</li>
<li className="flex gap-2">
<span className="text-gray-400 flex-shrink-0">•</span>
<span><span className="font-medium text-gray-800">Backend reliability</span> — Improved cache invalidation and retry logic for transient errors.</span>
</li>
</ul>
</div>
<div>
<div className="flex items-center gap-3 mb-3">
<span className="text-xs font-mono font-semibold text-gray-400 uppercase tracking-wider">
2026-03-10 - 12:00 CET
</span>
<span className="inline-flex items-center px-2 py-0.5 rounded-full text-xs font-medium bg-blue-100 text-blue-800">
Platform Update
</span>
</div>
<h2 className="text-base font-semibold text-gray-900 mb-2">
Security architecture, session timeline improvements, and new agent capabilities
</h2>
<ul className="space-y-2 text-sm text-gray-600 leading-relaxed list-none">
<li className="flex gap-2">
<span className="text-gray-400 flex-shrink-0">•</span>
<span><span className="font-medium text-gray-800">Role-based access control</span> — Admin and Operator roles with role management in Settings. API authorization and policy enforcement middleware ensure proper access control across all endpoints.</span>
</li>
<li className="flex gap-2">
<span className="text-gray-400 flex-shrink-0">•</span>
<span><span className="font-medium text-gray-800">Agent self-update</span> — Agents can now update themselves automatically, ensuring outdated versions in the field get replaced without manual intervention.</span>
</li>
<li className="flex gap-2">
<span className="text-gray-400 flex-shrink-0">•</span>
<span><span className="font-medium text-gray-800">Bootstrap sessions</span> — New bootstrap session flow with explicit token enablement for initial device onboarding. (support for bootstrap tokens enabled by request)</span>
</li>
<li className="flex gap-2">
<span className="text-gray-400 flex-shrink-0">•</span>
<span><span className="font-medium text-gray-800">Raw event timeline</span> — A new raw view of the event timeline with full search support, useful for deep-dive troubleshooting.</span>
</li>
<li className="flex gap-2">
<span className="text-gray-400 flex-shrink-0">•</span>
<span><span className="font-medium text-gray-800">Enrollment summary dialog</span> — Optional summary dialog shown at the end of enrollment, with event timeline search and clickable phases in the phase tracker.</span>
</li>
<li className="flex gap-2">
<span className="text-gray-400 flex-shrink-0">•</span>
<span><span className="font-medium text-gray-800">Original ESP tracking</span> — The agent now tracks the original ESP provisioning status to catch non-IME errors such as certificate failures.</span>
</li>
<li className="flex gap-2">
<span className="text-gray-400 flex-shrink-0">•</span>
<span><span className="font-medium text-gray-800">Analyze &amp; gather rules</span> — Added negative compare operators for analyze rules, XML and JSON gather options, and a built-in &ldquo;old OS version&rdquo; warning rule.</span>
</li>
<li className="flex gap-2">
<span className="text-gray-400 flex-shrink-0">•</span>
<span><span className="font-medium text-gray-800">Email notifications</span> — Email notification (Welcome and instructions) for Joining the Private Preview.</span>
</li>
<li className="flex gap-2">
<span className="text-gray-400 flex-shrink-0">•</span>
<span><span className="font-medium text-gray-800">Agent version management</span> — Block specific agent versions from connecting, along with expanded data retention configuration options.</span>
</li>
<li className="flex gap-2">
<span className="text-gray-400 flex-shrink-0">•</span>
<span><span className="font-medium text-gray-800">Install progress</span> — The agent install progress page now shows download and install phases with elapsed time.</span>
</li>
<li className="flex gap-2">
<span className="text-gray-400 flex-shrink-0">•</span>
<span><span className="font-medium text-gray-800">TPM info collection</span> — TPM details are now collected at enrollment time for improved hardware diagnostics.</span>
</li>
<li className="flex gap-2">
<span className="text-gray-400 flex-shrink-0">•</span>
<span><span className="font-medium text-gray-800">Firewall compatibility</span> — The agent now sends a dedicated User-Agent header to simplify firewall allowlisting.</span>
</li>
</ul>
</div>
<div>
<div className="flex items-center gap-3 mb-3">
<span className="text-xs font-mono font-semibold text-gray-400 uppercase tracking-wider">
2026-03-01 - 16:00 CET
</span>
<span className="inline-flex items-center px-2 py-0.5 rounded-full text-xs font-medium bg-blue-100 text-blue-800">
Pre-Provisioning (WhiteGlove)
</span>
</div>
<h2 className="text-base font-semibold text-gray-900 mb-2">
Ongoing improvements to Pre-Provisioning support (still testing)
</h2>
<p className="text-sm text-gray-600 leading-relaxed">
I'm continuously improving support for Pre-Provisioning (White Glove) scenarios.
The session timeline should now better reflect the provisioning process better, and I'm
working on improving the accuracy of event categorization and timing for these sessions.
If you are using Pre-Provisioning and notice any discrepancies in the timeline or data,
please share your Feedback with me via GitHub Issues. Your feedback is invaluable in
helping me enhance support for these scenarios.
Expect a "Report Session" button in the timeline view soon to make sharing feedback and logs easier!
</p>
</div>
<div>
<div className="flex items-center gap-3 mb-3">
<span className="text-xs font-mono font-semibold text-gray-400 uppercase tracking-wider">
2026-02-27 - 21:38 CET
</span>
<span className="inline-flex items-center px-2 py-0.5 rounded-full text-xs font-medium bg-blue-100 text-blue-800">
Features
</span>
</div>
<h2 className="text-base font-semibold text-gray-900 mb-2">
Configurable Diagnostic Package, Gather Rule Examples, Updated Docs
</h2>
<p className="text-sm text-gray-600 leading-relaxed">
The configurable diagnostic package allows for more flexible data collection and analysis.
Gather rule examples have been added to help users understand how to create their own rules.
Documentation has been updated to reflect these changes and provide guidance on using the features.
</p>
</div>
<div>
<div className="flex items-center gap-3 mb-3">
<span className="text-xs font-mono font-semibold text-gray-400 uppercase tracking-wider">
2026-02-27 - 14:38 CET
</span>
<span className="inline-flex items-center px-2 py-0.5 rounded-full text-xs font-medium bg-blue-100 text-blue-800">
Architecture
</span>
</div>
<h2 className="text-base font-semibold text-gray-900 mb-2">
First implementation of Pre-Provisioning support incl. session timeline visualization
</h2>
<p className="text-sm text-gray-600 leading-relaxed">
The session timeline now also supports sessions that started with Pre-Provisioning
(aka White Glove) — including the provisioning process itself. This is a first
implementation and only tested with a very basic scenario, so if you use
Pre-Provisioning and see anything that looks off in the timeline, please check
the logs and share them via GitHub Issues.
</p>
</div>
<div>
<div className="flex items-center gap-3 mb-3">
<span className="text-xs font-mono font-semibold text-gray-400 uppercase tracking-wider">
2026-02-26 - 10:15 CET
</span>
<span className="inline-flex items-center px-2 py-0.5 rounded-full text-xs font-medium bg-blue-100 text-blue-800">
Architecture
</span>
</div>
<h2 className="text-base font-semibold text-gray-900 mb-2">
Reworked real-time event delivery and session timeline processing
</h2>
<p className="text-sm text-gray-600 leading-relaxed">
The way live session events reach the dashboard timeline was fundamentally
reworked. This should make the timeline more reliable and accurate.
</p>
</div>
</div>
</div>
</main>
</div>
);
}
@@ -27,7 +27,7 @@ export function WelcomeMessage() {
<span className="shrink-0 mt-0.5 w-5 h-5 rounded-full bg-blue-600 text-white text-[10px] font-bold flex items-center justify-center">1</span>
<p className="text-sm text-gray-700">
Follow the{" "}
<a href="/docs/setup" className="text-blue-600 hover:underline font-medium">setup guide</a>
<a href="https://docs.autopilotmonitor.com/getting-started/portal-setup" target="_blank" rel="noopener noreferrer" className="text-blue-600 hover:underline font-medium">setup guide</a>
{" "}to configure your tenant and grant the required permissions.
</p>
</li>
@@ -35,7 +35,7 @@ export function WelcomeMessage() {
<span className="shrink-0 mt-0.5 w-5 h-5 rounded-full bg-blue-600 text-white text-[10px] font-bold flex items-center justify-center">2</span>
<p className="text-sm text-gray-700">
Deploy the{" "}
<a href="/docs/agent-setup" className="text-blue-600 hover:underline font-medium">Intune bootstrapper</a>
<a href="https://docs.autopilotmonitor.com/getting-started/deploy-the-agent" target="_blank" rel="noopener noreferrer" className="text-blue-600 hover:underline font-medium">Intune bootstrapper</a>
{" "}to your Autopilot device groups — the agent installs automatically on first boot.
</p>
</li>
@@ -48,7 +48,7 @@ export function WelcomeMessage() {
{/* Quick links */}
<div className="grid grid-cols-1 sm:grid-cols-2 gap-3">
<a
href="/docs"
href="https://docs.autopilotmonitor.com" target="_blank" rel="noopener noreferrer"
className="group flex items-center gap-3 rounded-lg border border-gray-200 bg-gray-50 px-4 py-3 hover:border-blue-300 hover:bg-blue-50 transition-colors"
>
<span className="shrink-0 w-8 h-8 rounded-lg bg-white border border-gray-200 group-hover:border-blue-200 flex items-center justify-center shadow-sm">
@@ -266,19 +266,23 @@ function HomeContent() {
<span className="font-semibold">Private Preview.</span>{" "}
The platform is under active development.{" "}
If something looks off, check the{" "}
<Link
href="/changelog"
<a
href="https://docs.autopilotmonitor.com/changelog/platform-changelog"
target="_blank"
rel="noopener noreferrer"
className="underline font-medium hover:text-blue-600 dark:hover:text-blue-200"
>
Private Preview Changelog
</Link>{" "}
</a>{" "}
or{" "}
<Link
href="/docs/known-issues"
<a
href="https://docs.autopilotmonitor.com/troubleshooting/service-announcements"
target="_blank"
rel="noopener noreferrer"
className="underline font-medium hover:text-blue-600 dark:hover:text-blue-200"
>
Known Issues
</Link>
</a>
.{" "}
Feedback or bug report?{" "}
<a
@@ -1,75 +0,0 @@
"use client";
import { useMemo } from "react";
import { usePageSections } from "../../hooks/usePageSections";
import { PageSectionItem } from "../../contexts/SidebarContext";
import { useAuth } from "../../contexts/AuthContext";
import { NAV_SECTIONS } from "./docsNavSections";
import {
KeyIcon,
BookOpenIcon,
InformationCircleIcon,
WrenchScrewdriverIcon,
ComputerDesktopIcon,
RocketLaunchIcon,
GearIcon,
ListBulletIcon,
SparklesIcon,
CodeBracketIcon,
QuestionMarkCircleIcon,
CommandLineIcon,
BellIcon,
CpuChipIcon,
} from "../../lib/sidebarIcons";
const SECTION_ICONS: Record<string, React.ReactNode> = {
"private-preview": <KeyIcon />,
"overview": <BookOpenIcon />,
"general": <InformationCircleIcon />,
"setup": <WrenchScrewdriverIcon />,
"agent": <ComputerDesktopIcon />,
"agent-setup": <RocketLaunchIcon />,
"settings": <GearIcon />,
"gather-rules": <ListBulletIcon />,
"analyze-rules": <SparklesIcon />,
"ime-log-patterns": <CodeBracketIcon />,
"faq": <QuestionMarkCircleIcon />,
"known-issues": <BellIcon />,
"mcp-integration": <CommandLineIcon />,
"agent-internals": <CpuChipIcon />,
};
export function DocsSidebar({ children }: { children: React.ReactNode }) {
const { user } = useAuth();
const docsItems: PageSectionItem[] = useMemo(
() =>
NAV_SECTIONS
.filter((s) => !s.hidden && (!s.requiresMcpAccess || user?.hasMcpAccess) && (!s.requiresGlobalAdmin || user?.isGlobalAdmin))
.map((s) => ({
id: s.id,
label: s.label,
icon: SECTION_ICONS[s.id],
href: `/docs/${s.id}`,
})),
[user?.hasMcpAccess, user?.isGlobalAdmin],
);
usePageSections(docsItems, "Contents", "route");
return (
<>
{/* Page header */}
<header className="bg-white shadow">
<div className="py-6 px-4 sm:px-6 lg:px-8">
<h1 className="text-2xl font-normal text-gray-900">Documentation</h1>
</div>
</header>
{/* Content */}
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8 space-y-8">
{children}
</div>
</>
);
}
@@ -1,35 +0,0 @@
"use client";
import dynamic from "next/dynamic";
import type { ComponentType } from "react";
import { useAuth } from "../../contexts/AuthContext";
const GLOBAL_ADMIN_SECTIONS: Record<string, ComponentType> = {
"agent-internals": dynamic(() => import("./sections/SectionAgentInternals").then((m) => ({ default: m.SectionAgentInternals }))),
};
/**
* Client-side gate for Global-Admin-only docs sections.
* Only loads the section content via dynamic import AFTER verifying auth + isGlobalAdmin.
* Returns null (renders nothing) for unauthenticated or non-admin users.
*/
export function GlobalAdminDocsGate({ sectionId }: { sectionId: string }) {
const { user, isLoading, isAuthenticated } = useAuth();
if (isLoading) {
return (
<div className="flex justify-center py-16">
<div className="animate-spin rounded-full h-8 w-8 border-b-2 border-blue-600" />
</div>
);
}
if (!isAuthenticated || !user?.isGlobalAdmin) {
return null;
}
const Section = GLOBAL_ADMIN_SECTIONS[sectionId];
if (!Section) return null;
return <Section />;
}
@@ -1,39 +0,0 @@
"use client";
import dynamic from "next/dynamic";
import type { ComponentType } from "react";
import { useAuth } from "../../contexts/AuthContext";
const MCP_SECTIONS: Record<string, ComponentType> = {
"mcp-integration": dynamic(() => import("./sections/SectionMcpIntegration").then((m) => ({ default: m.SectionMcpIntegration }))),
};
/**
* Client-side gate for MCP-only docs sections.
* Only loads the section content via dynamic import AFTER verifying auth + MCP access.
* Returns null (renders nothing) for unauthenticated or non-MCP users —
* the server-side page.tsx calls notFound() for unknown sections,
* and this component handles the "known but unauthorized" case.
*/
export function McpDocsGate({ sectionId }: { sectionId: string }) {
const { user, isLoading, isAuthenticated } = useAuth();
if (isLoading) {
return (
<div className="flex justify-center py-16">
<div className="animate-spin rounded-full h-8 w-8 border-b-2 border-blue-600" />
</div>
);
}
if (!isAuthenticated || !user?.hasMcpAccess) {
// Return empty — indistinguishable from a non-existent page.
// The sidebar already hides this section for unauthorized users.
return null;
}
const Section = MCP_SECTIONS[sectionId];
if (!Section) return null;
return <Section />;
}
@@ -1,105 +0,0 @@
import { notFound } from "next/navigation";
import type { Metadata } from "next";
import { NAV_SECTIONS, type SectionId } from "../docsNavSections";
import { McpDocsGate } from "../McpDocsGate";
import { GlobalAdminDocsGate } from "../GlobalAdminDocsGate";
import { SectionPrivatePreview } from "../sections/SectionPrivatePreview";
import { SectionGeneral } from "../sections/SectionGeneral";
import { SectionOverview } from "../sections/SectionOverview";
import { SectionSetup } from "../sections/SectionSetup";
import { SectionAgent } from "../sections/SectionAgent";
import { SectionAgentSetup } from "../sections/SectionAgentSetup";
import { SectionSettings } from "../sections/SectionSettings";
import { SectionGatherRules } from "../sections/SectionGatherRules";
import { SectionAnalyzeRules } from "../sections/SectionAnalyzeRules";
import { SectionImeLogPatterns } from "../sections/SectionImeLogPatterns";
import { SectionFaq } from "../sections/SectionFaq";
import { SectionAgentChangelog } from "../sections/SectionAgentChangelog";
import { SectionKnownIssues } from "../sections/SectionKnownIssues";
const SECTION_COMPONENTS: Record<string, React.ComponentType> = {
"private-preview": SectionPrivatePreview,
"general": SectionGeneral,
"overview": SectionOverview,
"setup": SectionSetup,
"agent": SectionAgent,
"agent-setup": SectionAgentSetup,
"settings": SectionSettings,
"gather-rules": SectionGatherRules,
"analyze-rules": SectionAnalyzeRules,
"ime-log-patterns": SectionImeLogPatterns,
"faq": SectionFaq,
"known-issues": SectionKnownIssues,
"agent-changelog": SectionAgentChangelog,
};
function isMcpSection(id: string): boolean {
return NAV_SECTIONS.some((s) => s.id === id && s.requiresMcpAccess);
}
function isGlobalAdminSection(id: string): boolean {
return NAV_SECTIONS.some((s) => s.id === id && s.requiresGlobalAdmin);
}
export function generateStaticParams() {
return NAV_SECTIONS.map((s) => ({ section: s.id }));
}
type Props = { params: Promise<{ section: string }> };
export async function generateMetadata({ params }: Props): Promise<Metadata> {
const { section } = await params;
const nav = NAV_SECTIONS.find((s) => s.id === section);
if (!nav) return {};
return {
title: nav.label,
description: nav.description,
openGraph: {
title: `${nav.label} | AutopilotMonitor Docs`,
description: nav.description,
url: `https://www.autopilotmonitor.com/docs/${section}`,
},
twitter: {
title: `${nav.label} | AutopilotMonitor Docs`,
description: nav.description,
},
alternates: {
canonical: `https://www.autopilotmonitor.com/docs/${section}`,
},
};
}
export default async function DocsSectionPage({ params }: Props) {
const { section } = await params;
const nav = NAV_SECTIONS.find((s) => s.id === section);
if (!nav) notFound();
// Gated sections are rendered entirely client-side via their respective gates
// (dynamic import — no HTML shipped until auth check passes).
const isMcp = isMcpSection(section);
const isAdmin = isGlobalAdminSection(section);
if (!isMcp && !isAdmin && !SECTION_COMPONENTS[section]) notFound();
const SectionContent = (isMcp || isAdmin) ? null : SECTION_COMPONENTS[section]!;
const breadcrumbJsonLd = {
"@context": "https://schema.org",
"@type": "BreadcrumbList",
itemListElement: [
{ "@type": "ListItem", position: 1, name: "Home", item: "https://www.autopilotmonitor.com" },
{ "@type": "ListItem", position: 2, name: "Docs", item: "https://www.autopilotmonitor.com/docs" },
{ "@type": "ListItem", position: 3, name: nav.label, item: `https://www.autopilotmonitor.com/docs/${section}` },
],
};
return (
<>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(breadcrumbJsonLd) }}
/>
{isMcp ? <McpDocsGate sectionId={section} /> : isAdmin ? <GlobalAdminDocsGate sectionId={section} /> : SectionContent && <SectionContent />}
</>
);
}
@@ -1,28 +0,0 @@
interface NavSection {
readonly id: string;
readonly label: string;
readonly description: string;
readonly requiresMcpAccess?: true;
readonly requiresGlobalAdmin?: true;
readonly hidden?: true;
}
export const NAV_SECTIONS: readonly NavSection[] = [
{ id: "private-preview", label: "Private Preview", description: "Join the Autopilot Monitor private preview for early access. Learn about onboarding steps, requirements, and how to start monitoring Windows Autopilot enrollments." },
{ id: "overview", label: "Overview", description: "Explore the Autopilot Monitor architecture and core components. Learn how the agent, backend, and web dashboard work together to monitor Windows Autopilot enrollments." },
{ id: "general", label: "General", description: "Learn general Autopilot Monitor concepts including Admin Mode, session lifecycle statuses, user roles, and how enrollment data flows through the platform." },
{ id: "setup", label: "Setup", description: "Step-by-step guide to setting up Autopilot Monitor. Deploy the bootstrapper package via Microsoft Intune and start monitoring Windows Autopilot enrollments." },
{ id: "agent", label: "Agent", description: "Understand the Autopilot Monitor agent — how it collects enrollment data, communicates with the backend, and provides real-time visibility into Windows deployments." },
{ id: "agent-setup", label: "Agent Setup", description: "Configure and deploy the Autopilot Monitor agent via Microsoft Intune. Covers bootstrapper deployment, agent configuration, and verification of installation." },
{ id: "settings", label: "Settings", description: "Configure Autopilot Monitor settings including tenant options, diagnostics, notification preferences, and advanced platform options for Windows Autopilot monitoring." },
{ id: "gather-rules", label: "Gather Rules", description: "Configure gather rules to control which diagnostics data the Autopilot Monitor agent collects. Define custom log paths and collection criteria for troubleshooting." },
{ id: "analyze-rules", label: "Analyze Rules", description: "Set up analyze rules to automatically evaluate Windows Autopilot enrollments. Define conditions, severity levels, and custom logic to detect issues in real time." },
{ id: "ime-log-patterns", label: "IME Log Patterns", description: "Define regex patterns for parsing the Intune Management Extension (IME) log into structured events. Customize how Autopilot Monitor extracts log entries." },
{ id: "faq", label: "FAQ", description: "Frequently asked questions about Autopilot Monitor — covering setup, agent behavior, troubleshooting common issues, and tips for getting the most out of the platform." },
{ id: "known-issues", label: "Known Issues", description: "Documented issues caused by external changes that affect Autopilot Monitor — breaking changes, known limitations, workarounds, and current status." },
{ id: "mcp-integration", label: "MCP Integration", description: "Connect AI assistants to Autopilot Monitor via Model Context Protocol. Configure MCP clients, explore available tools, and learn how to query enrollment data with natural language.", requiresMcpAccess: true },
{ id: "agent-changelog", label: "Agent Changelog", description: "Changelog of user-facing changes to the Autopilot Monitor agent — new features, behavior changes, and improvements over time.", hidden: true },
{ id: "agent-internals", label: "Agent Internals", description: "Technical deep dive into agent internals — all capabilities, event types, configuration settings, collectors, and architecture details. Global Admin only.", requiresGlobalAdmin: true },
] as const;
export type SectionId = NavSection["id"];
@@ -1,41 +0,0 @@
import type { Metadata } from "next";
import { DocsSidebar } from "./DocsSidebar";
export const metadata: Metadata = {
title: {
template: "%s | AutopilotMonitor Docs",
default: "Documentation | AutopilotMonitor",
},
description:
"Complete setup and configuration guide for Autopilot Monitor. Deploy the bootstrapper via Intune, configure the agent, and monitor enrollments in real time.",
keywords: [
"Autopilot Monitor documentation",
"Autopilot Monitor setup guide",
"Intune bootstrapper deployment",
"Autopilot agent configuration",
"Windows Autopilot setup",
"Autopilot Monitor install",
],
openGraph: {
title: "Documentation | AutopilotMonitor",
description:
"Complete setup and configuration guide for Autopilot Monitor. Deploy the bootstrapper via Intune and start monitoring Windows Autopilot enrollments.",
url: "https://www.autopilotmonitor.com/docs",
},
twitter: {
title: "Documentation | AutopilotMonitor",
description:
"Complete setup and configuration guide for Autopilot Monitor. Deploy the bootstrapper via Intune and start monitoring Windows Autopilot enrollments.",
},
alternates: {
canonical: "https://www.autopilotmonitor.com/docs",
},
};
export default function DocsLayout({ children }: { children: React.ReactNode }) {
return (
<div className="min-h-screen bg-gray-50">
<DocsSidebar>{children}</DocsSidebar>
</div>
);
}
@@ -1,338 +0,0 @@
"use client";
import { useEffect, useState } from "react";
import Link from "next/link";
interface AgentVersionInfo {
version?: string;
url?: string;
bootstrapVersion?: string;
}
const AGENT_VERSION_URL =
"https://autopilotmonitor.blob.core.windows.net/agent/version.json";
export function SectionAgent() {
const [versionInfo, setVersionInfo] = useState<AgentVersionInfo | null>(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
let cancelled = false;
async function fetchVersion() {
try {
const res = await fetch(AGENT_VERSION_URL, { cache: "no-store" });
if (res.ok) {
const data = await res.json();
if (!cancelled) setVersionInfo(data);
}
} catch {
// silently keep null
} finally {
if (!cancelled) setLoading(false);
}
}
fetchVersion();
return () => { cancelled = true; };
}, []);
return (
<section className="bg-white rounded-lg shadow-md p-8">
<div className="flex items-center space-x-3 mb-4">
<svg className="w-8 h-8 text-blue-600 shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 3v2m6-2v2M9 19v2m6-2v2M5 9H3m2 6H3m18-6h-2m2 6h-2M7 19h10a2 2 0 002-2V7a2 2 0 00-2-2H7a2 2 0 00-2 2v10a2 2 0 002 2zM9 9h6v6H9V9z" />
</svg>
<h2 className="text-2xl font-bold text-gray-900">Agent</h2>
</div>
<p className="text-gray-700 mb-6">
The Autopilot Monitor agent is a lightweight .NET application that runs on the device during
the Windows Autopilot enrollment process. It collects real-time telemetry about enrollment
phases, app installations, policy processing, and system events — then streams everything to
the backend for live monitoring and analysis.
</p>
<div className="mb-6">
<div className="flex items-center gap-2 mb-3">
<svg className="w-5 h-5 text-indigo-600 shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
<h3 className="text-lg font-semibold text-gray-900">Full Enrollment Timeline &mdash; From the Very First Second</h3>
</div>
<p className="text-gray-700 mb-4">
Although the agent arrives on the device via the bootstrapper script &mdash; typically a few seconds after
MDM enrollment begins &mdash; it does not miss any earlier activity. The Intune Management Extension (IME)
has been writing detailed log files from the very start of enrollment, and the agent reads those logs
from the beginning on its first launch. This backfill mechanism ensures complete coverage of the entire
enrollment timeline, with no blind spots.
</p>
<div className="space-y-3 text-sm text-gray-700">
<div className="flex items-start gap-3 p-3 bg-indigo-50 border border-indigo-100 rounded-lg">
<span className="text-indigo-600 font-bold mt-0.5 shrink-0">1</span>
<div>
<span className="font-medium text-gray-900">IME logs from the start:</span>{" "}
The Intune Management Extension begins logging immediately when enrollment starts &mdash; long before
the agent exists on the device. App downloads, installations, ESP phase transitions, and policy
processing are all recorded into CMTrace-formatted log files on disk.
</div>
</div>
<div className="flex items-start gap-3 p-3 bg-indigo-50 border border-indigo-100 rounded-lg">
<span className="text-indigo-600 font-bold mt-0.5 shrink-0">2</span>
<div>
<span className="font-medium text-gray-900">Backfill on first launch:</span>{" "}
When the agent starts for the first time, it reads the IME log files from byte position zero. Every
historical entry &mdash; app state changes, phase transitions, download progress, script executions &mdash; is
parsed and processed as if the agent had been running the whole time. Archived (rotated) log files
are included and processed before the current log to preserve chronological order.
</div>
</div>
<div className="flex items-start gap-3 p-3 bg-indigo-50 border border-indigo-100 rounded-lg">
<span className="text-indigo-600 font-bold mt-0.5 shrink-0">3</span>
<div>
<span className="font-medium text-gray-900">Real-time from there:</span>{" "}
After the initial backfill completes, the agent switches to incremental polling. It tracks the byte
position in each log file and reads only new data on each cycle, providing real-time visibility into
ongoing enrollment activity without re-processing earlier entries.
</div>
</div>
</div>
<p className="mt-3 text-sm text-gray-500">
The result is a complete, chronologically accurate record of every app installation, ESP phase, and
enrollment signal from T=0 &mdash; regardless of when the agent was installed on the device.
</p>
</div>
<div className="mb-6 grid grid-cols-1 md:grid-cols-2 gap-4">
<div className="p-5 bg-blue-50 border border-blue-200 rounded-lg">
<div className="flex items-center gap-3 mb-2">
<svg className="w-5 h-5 text-blue-600 shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M7 7h.01M7 3h5c.512 0 1.024.195 1.414.586l7 7a2 2 0 010 2.828l-7 7a2 2 0 01-2.828 0l-7-7A1.994 1.994 0 013 12V7a4 4 0 014-4z" />
</svg>
<span className="font-semibold text-blue-900">Latest Agent Version</span>
</div>
{loading ? (
<div className="flex items-center gap-2 text-sm text-blue-700">
<svg className="w-4 h-4 animate-spin" fill="none" viewBox="0 0 24 24">
<circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4" />
<path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z" />
</svg>
Loading version info...
</div>
) : versionInfo?.version ? (
<div className="flex items-center gap-3">
<span className="inline-flex items-center px-3 py-1.5 bg-blue-100 text-blue-800 text-lg font-mono font-bold rounded-md">
v{versionInfo.version}
</span>
<Link href="/docs/agent-changelog" className="text-sm text-blue-600 hover:text-blue-800 hover:underline">
View Changelog
</Link>
</div>
) : (
<p className="text-sm text-blue-700">Version information is currently unavailable.</p>
)}
</div>
<div className="p-5 bg-blue-50 border border-blue-200 rounded-lg">
<div className="flex items-center gap-3 mb-2">
<svg className="w-5 h-5 text-blue-600 shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M7 7h.01M7 3h5c.512 0 1.024.195 1.414.586l7 7a2 2 0 010 2.828l-7 7a2 2 0 01-2.828 0l-7-7A1.994 1.994 0 013 12V7a4 4 0 014-4z" />
</svg>
<span className="font-semibold text-blue-900">Latest Bootstrapper Script Version</span>
</div>
{loading ? (
<div className="flex items-center gap-2 text-sm text-blue-700">
<svg className="w-4 h-4 animate-spin" fill="none" viewBox="0 0 24 24">
<circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4" />
<path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z" />
</svg>
Loading version info...
</div>
) : versionInfo?.bootstrapVersion ? (
<div className="flex items-center gap-3">
<span className="inline-flex items-center px-3 py-1.5 bg-blue-100 text-blue-800 text-lg font-mono font-bold rounded-md">
v{versionInfo.bootstrapVersion}
</span>
</div>
) : (
<p className="text-sm text-blue-700">Version information is currently unavailable.</p>
)}
</div>
</div>
<div className="mb-6">
<div className="flex items-center gap-2 mb-3">
<svg className="w-5 h-5 text-green-600 shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z" />
</svg>
<h3 className="text-lg font-semibold text-gray-900">Binary Integrity Verification</h3>
</div>
<p className="text-gray-700 mb-4">
Agent binaries are protected by SHA-256 integrity verification at two stages: during download
(package integrity) and at runtime (executable integrity). This ensures the binary has not been
tampered with, corrupted during transfer, or modified after installation.
</p>
<div className="space-y-3 text-sm text-gray-700">
<div className="flex items-start gap-3 p-3 bg-green-50 border border-green-100 rounded-lg">
<span className="text-green-600 font-bold mt-0.5 shrink-0">1</span>
<div>
<span className="font-medium text-gray-900">Build-time hash:</span>{" "}
When a new agent version is built, the CI/CD pipeline computes two SHA-256 hashes: one
for the agent ZIP package (stored in <span className="font-mono text-xs bg-green-100 px-1 py-0.5 rounded">version.json</span>)
and one for the agent executable itself (stored in the backend configuration).
</div>
</div>
<div className="flex items-start gap-3 p-3 bg-green-50 border border-green-100 rounded-lg">
<span className="text-green-600 font-bold mt-0.5 shrink-0">2</span>
<div>
<span className="font-medium text-gray-900">Download verification:</span>{" "}
Both the bootstrapper script and the agent&apos;s self-updater verify the SHA-256 hash of
the downloaded package before installation. If the hash does not match, installation is aborted.
</div>
</div>
<div className="flex items-start gap-3 p-3 bg-green-50 border border-green-100 rounded-lg">
<span className="text-green-600 font-bold mt-0.5 shrink-0">3</span>
<div>
<span className="font-medium text-gray-900">Backend cross-check:</span>{" "}
The expected ZIP hash is also stored in the backend and delivered to the agent via the
authenticated configuration endpoint — a second, independent trust channel. An attacker
would need to compromise both the download server and the backend API simultaneously.
</div>
</div>
<div className="flex items-start gap-3 p-3 bg-green-50 border border-green-100 rounded-lg">
<span className="text-green-600 font-bold mt-0.5 shrink-0">4</span>
<div>
<span className="font-medium text-gray-900">Runtime integrity check:</span>{" "}
After fetching its configuration from the backend, the running agent computes the SHA-256
hash of its own executable and compares it against the EXE hash provided in the
configuration response. A mismatch triggers an emergency alert, detecting post-installation
tampering or binary corruption on disk.
</div>
</div>
</div>
<p className="mt-3 text-sm text-gray-500">
All communication uses HTTPS (TLS 1.2+). The agent authenticates to the backend using the
device&apos;s MDM client certificate, ensuring only authorized devices receive configuration data.
</p>
</div>
<div className="mb-6">
<div className="flex items-center gap-2 mb-3">
<svg className="w-5 h-5 text-purple-600 shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M8 9l3 3-3 3m5 0h3M5 20h14a2 2 0 002-2V6a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" />
</svg>
<h3 className="text-lg font-semibold text-gray-900">Command-Line Parameters</h3>
</div>
<p className="text-gray-700 mb-4">
The agent accepts command-line parameters for testing, debugging, and advanced scenarios.
These are passed when launching the agent executable directly.
</p>
<div className="border border-purple-200 rounded-lg overflow-hidden mb-4">
<div className="px-4 py-2.5 bg-purple-50 border-b border-purple-200">
<p className="font-semibold text-sm text-purple-900">Session &amp; Lifecycle</p>
</div>
<div className="px-4 py-3 space-y-3 text-sm text-gray-700">
<div>
<span className="font-mono text-xs bg-purple-50 px-1.5 py-0.5 rounded font-medium">--new-session</span>
<p className="mt-1">Deletes existing session data and starts a fresh session. Useful when the agent needs to be
restarted on a device without carrying over stale data from a previous run.</p>
</div>
<div>
<span className="font-mono text-xs bg-purple-50 px-1.5 py-0.5 rounded font-medium">--no-cleanup</span>
<p className="mt-1">Suppresses self-destruct after enrollment &mdash; agent files and the scheduled task remain on the
device. Helpful for post-enrollment debugging and log analysis.</p>
</div>
<div>
<span className="font-mono text-xs bg-purple-50 px-1.5 py-0.5 rounded font-medium">--keep-logfile</span>
<p className="mt-1">Preserves the log directory during self-destruct. Logs remain on disk for later analysis
even after the agent cleans up everything else.</p>
</div>
<div>
<span className="font-mono text-xs bg-purple-50 px-1.5 py-0.5 rounded font-medium">--reboot-on-complete</span>
<p className="mt-1">Reboots the device after enrollment completes. The reboot is delayed by 10 seconds by default
(configurable via the remote configuration). Useful when a reboot is required to finalize
device setup but not configured as a tenant default.</p>
</div>
<div>
<span className="font-mono text-xs bg-purple-50 px-1.5 py-0.5 rounded font-medium">--disable-geolocation</span>
<p className="mt-1">Disables geo-location detection. The agent will not attempt to resolve the device&apos;s
geographic location via IP-based lookup. Useful in restricted network environments or when
location data is not desired.</p>
</div>
</div>
</div>
<div className="border border-purple-200 rounded-lg overflow-hidden mb-4">
<div className="px-4 py-2.5 bg-purple-50 border-b border-purple-200">
<p className="font-semibold text-sm text-purple-900">Authentication &amp; Bootstrap</p>
</div>
<div className="px-4 py-3 space-y-3 text-sm text-gray-700">
<div>
<span className="font-mono text-xs bg-purple-50 px-1.5 py-0.5 rounded font-medium">--bootstrap-token &lt;token&gt;</span>
<p className="mt-1">Provides a bootstrap token for pre-MDM authentication during OOBE, before an MDM client
certificate is available on the device.</p>
</div>
<div>
<span className="font-mono text-xs bg-purple-50 px-1.5 py-0.5 rounded font-medium">--await-enrollment</span>
<p className="mt-1">The agent waits for the MDM client certificate to become available before starting monitoring.
Timeout can be configured with <span className="font-mono text-xs bg-gray-100 px-1 py-0.5 rounded">--await-enrollment-timeout</span>.</p>
</div>
<div>
<span className="font-mono text-xs bg-purple-50 px-1.5 py-0.5 rounded font-medium">--await-enrollment-timeout &lt;minutes&gt;</span>
<p className="mt-1">Maximum time in minutes to wait for the MDM certificate. Default: <span className="font-mono text-xs bg-gray-100 px-1 py-0.5 rounded">480</span> (8 hours).</p>
</div>
</div>
</div>
<div className="border border-purple-200 rounded-lg overflow-hidden mb-4">
<div className="px-4 py-2.5 bg-purple-50 border-b border-purple-200">
<p className="font-semibold text-sm text-purple-900">Testing &amp; Replay</p>
</div>
<div className="px-4 py-3 space-y-3 text-sm text-gray-700">
<div>
<span className="font-mono text-xs bg-purple-50 px-1.5 py-0.5 rounded font-medium">--ime-log-path &lt;path&gt;</span>
<p className="mt-1">Custom path to IME log files. Allows testing with logs collected from other devices
without running a real enrollment.</p>
</div>
<div>
<span className="font-mono text-xs bg-purple-50 px-1.5 py-0.5 rounded font-medium">--replay-log-dir &lt;path&gt;</span>
<p className="mt-1">Replays real IME log files from the specified directory and simulates a complete enrollment
in fast-forward. Creates a real session in the backend &mdash; device information is collected from
the current machine (WMI/Registry), while enrollment events are extracted from the log files.
Ideal for testing, demos, or analyzing past enrollments without waiting for a live enrollment.</p>
</div>
<div>
<span className="font-mono text-xs bg-purple-50 px-1.5 py-0.5 rounded font-medium">--replay-speed-factor &lt;n&gt;</span>
<p className="mt-1">Time compression factor for log replay. Default: <span className="font-mono text-xs bg-gray-100 px-1 py-0.5 rounded">50</span>.
A factor of 50 means a 50-minute enrollment replays in approximately 1 minute. Delays between
events are divided by this factor, capped at 5 seconds per delay.</p>
</div>
</div>
</div>
<div className="p-4 bg-green-50 border border-green-200 rounded-lg mb-4">
<p className="font-semibold text-sm text-green-900 mb-2">Example &mdash; Replay a captured enrollment</p>
<div className="bg-green-100 rounded px-3 py-2 text-xs font-mono text-green-900 mb-2">
AutopilotMonitor.Agent.exe --replay-log-dir &quot;C:\Logs\IME&quot; --replay-speed-factor 100
</div>
<p className="text-sm text-green-800">
Replays a previously captured enrollment at 100x speed, creating a full session visible in the dashboard.
</p>
</div>
<div className="p-4 bg-amber-50 border border-amber-200 rounded-lg">
<div className="flex items-start gap-2">
<svg className="w-4 h-4 text-amber-600 mt-0.5 shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L4.082 16.5c-.77.833.192 2.5 1.732 2.5z" />
</svg>
<p className="text-sm text-amber-800">
Parameters like <span className="font-mono text-xs bg-amber-100 px-1 py-0.5 rounded">--replay-log-dir</span> are
intended for testing and development environments only &mdash; do not use them in production deployments.
</p>
</div>
</div>
</div>
</section>
);
}
@@ -1,196 +0,0 @@
export function SectionAgentChangelog() {
return (
<section className="bg-white rounded-lg shadow-md p-8">
<div className="flex items-center space-x-3 mb-4">
<svg className="w-8 h-8 text-blue-600 shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2" />
</svg>
<h2 className="text-2xl font-bold text-gray-900">Agent Changelog</h2>
</div>
<p className="text-gray-600 mb-8">
User-facing changes to the Autopilot Monitor agent, newest first. Only includes changes that affect agent behavior on the device.
</p>
{/* ── June 2026 ────────────────────────────────── */}
<ChangelogBlock title="June 2026">
<Li>Optional keep-awake during the User-ESP (Account Setup) phase — when enabled per tenant (off by default), the agent keeps the device awake so it can&apos;t drop into standby and stall app installs or account setup; the hold is released automatically once the phase completes, and device reboots are unaffected</Li>
<Li>Fewer stuck enrollments — Classic sessions where a skipped user-ESP app or an advisory &quot;continue anyway&quot; ESP failure left completion waiting now resolve through a short completion deadline instead of running into the 6-hour timeout</Li>
<Li>Desktop-arrival detection no longer stalls on devices where the owner lookup failed — the agent resolves the signed-in user via a Windows session (WTS) query, with the previous method as fallback</Li>
<Li>When an app still installing blocks enrollment completion, the agent now names the specific app holding up the AccountSetup gate instead of just reporting a stall</Li>
<Li>Office (M365 Apps) install tracking is more accurate — pre-installed OEM / consumer Office no longer triggers a false &quot;install failed&quot;, and Office install progress now survives agent restarts and reboots</Li>
<Li>Low-disk-space warning — agent emits a one-shot warning when free space drops below 2&nbsp;GB during enrollment (re-arms once space recovers above 3&nbsp;GB)</Li>
<Li>Repetitive ModernDeployment event bursts are rolled up into a single entry and excluded from the idle timer — less timeline noise, and they no longer keep the collector awake</Li>
<Li>Hello for Business policy is no longer reported as <code className="text-xs bg-gray-100 px-1 py-0.5 rounded">not_configured</code> when it simply couldn&apos;t be detected, avoiding misleading Hello status</Li>
<Li>New liveness signals show what enrollment completion is waiting on, and flag a session that is parked without a deadline — making stuck sessions easier to spot</Li>
<Li>Startup events (e.g. timezone, NTP, geo-location) are de-duplicated across agent restarts, so a reboot mid-enrollment no longer repeats them in the timeline</Li>
<Li>RealmJoin client detection is now an opt-in per-tenant setting (off by default) and additionally reports the RealmJoin release channel alongside its version</Li>
<Li>Agent records the device&apos;s outbound (egress) IP for network correlation during enrollment</Li>
<Li>Each agent request now carries a correlation ID for end-to-end tracing across agent and backend, making request-level troubleshooting easier</Li>
<Li>Microsoft 365 Apps (Office) install tracking — agent surfaces the real Office Click-to-Run install that the Intune &quot;integrated&quot; app hides (IME reports done within a minute or two while Office keeps streaming in the background); shown as its own install row with live Delivery Optimization download progress</Li>
<Li>Provisioning-package detection — agent scans for Windows provisioning packages (<code className="text-xs bg-gray-100 px-1 py-0.5 rounded">.ppkg</code>) applied to the device and reports them in a single scan event; security rules flag packages outside a built-in allow-list of Windows-inbox packages</Li>
<Li>AutoLogon detection — agent reports the device&apos;s automatic sign-in (AutoLogon) configuration; security rules now flag it only when a plaintext password is actually stored, so normal Autopilot enrollments no longer produce false positives</Li>
<Li>ESP sub-category state changes are now surfaced even when they aren&apos;t failures (e.g. retry or recovery transitions) for clearer visibility into ESP progress</Li>
<Li>Stall-probe file and registry scans now enforce a hard timeout so a slow or locked source can no longer hang the probe</Li>
</ChangelogBlock>
{/* ── May 2026 ─────────────────────────────────── */}
<ChangelogBlock title="May 2026">
<Li>RealmJoin client detection — agent detects the RealmJoin client, reports its version, tracks deployment-phase changes, and surfaces per-package install progress</Li>
<Li>Device hardware now reports CPU architecture (<code className="text-xs bg-gray-100 px-1 py-0.5 rounded">x86</code> / <code className="text-xs bg-gray-100 px-1 py-0.5 rounded">x64</code> / <code className="text-xs bg-gray-100 px-1 py-0.5 rounded">ARM</code> / <code className="text-xs bg-gray-100 px-1 py-0.5 rounded">ARM64</code>)</Li>
<Li>Startup power-state check — agent warns when the device is running on battery below 80%, a frequent driver behind power-management enrollment stalls (enrollments are more reliable on AC power)</Li>
<Li>ESP app-install failures are now classified by their HRESULT, surface all failure types (failed / not-installed / error), and a 30-second settle window catches results that arrive late</Li>
<Li>Crash mini-dumps are captured for deeper post-mortem analysis when a previous-run crash is detected</Li>
<Li>More accurate Health Script results — compliant detections are no longer mislabeled as failed, and detection failures now produce an actionable message for admins</Li>
<Li>Fewer false enrollment failures — ESP &quot;continue anyway&quot; with AccountSetup, and self-deploying scenarios, now get a settle window before a failure is finalized</Li>
<Li>Shutdown, diagnostics, and summary events are no longer dropped after a terminal enrollment decision</Li>
<Li>Bootstrap reports its version so the bootstrap script version is visible in the session</Li>
<Li>Agent retries the remote-config fetch with wire-visible fallback when the first attempt fails</Li>
<Li>Security hardening for agent self-update, diagnostics URL handling, and PowerShell argument escaping</Li>
<Li><strong>Agent V2 is now the primary production line</strong> — V2 replaces V1 as the default install. Existing V1 devices keep working; new installs ship the V2 build (bootstrap script and binary renamed from <code className="text-xs bg-gray-100 px-1 py-0.5 rounded">.V2</code> to standard)</Li>
<Li>Health Scripts lifecycle monitoring — detection, remediation, and post-remediation phases are each captured as separate timeline events with a live &quot;script running&quot; indicator before the result lands</Li>
<Li>Apps still installing when ESP-Apps times out are flagged as &quot;likely stuck&quot; instead of disappearing from the timeline — admins now see the app name and a hedged outcome</Li>
<Li>ASR / EDR-blocked install handoff no longer strands devices — runtime spawn fails soft and the BootTrigger task picks the agent back up on next reboot</Li>
<Li>Hello-disabled enrollments now complete reliably — the Classic v1 path no longer deadlocks waiting for a Hello signal that will never arrive (previously ran into the 6h max-lifetime timer)</Li>
<Li>AccountSetup must truly succeed before Hello can trigger completion — prevents premature <code className="text-xs bg-gray-100 px-1 py-0.5 rounded">enrollment_complete</code> when AccountSetup actually failed</Li>
<Li>Hybrid User-Driven (HAADJ) enrollment-completion gaps closed — more completion paths recognized, fewer sessions stuck in the timeout fallback</Li>
<Li>TPM PSS unsupported is reported as a distinct distress reason — older devices (e.g. Surface Book 1 with 2015-era Infineon TPM firmware) that can&apos;t do RSA-PSS now get a clear failure category instead of a generic Schannel error</Li>
<Li>Intune dual-stack certificate selection fix — on devices with both MDM and MMP-C client certs, the agent now picks the correct <em>Microsoft Intune MDM Device CA</em> cert and avoids backend chain-validation rejection</Li>
<Li>Client certificate rejections surface with structured backend warnings and V2 distress cert-context (thumbprint, subject, issuer, validity) — easier to diagnose mTLS auth failures</Li>
<Li>Tenant ID resolution falls back to the CloudDomainJoin registry (<code className="text-xs bg-gray-100 px-1 py-0.5 rounded">TenantInfo</code> + <code className="text-xs bg-gray-100 px-1 py-0.5 rounded">JoinInfo</code>) when the Enrollments key is empty — covers pre-Type-6 enrollments and MS-Organization-Access cert paths</Li>
<Li>Event-driven Tenant ID wait via RegistryWatcher — agent reacts to registry changes during pre-enrollment instead of polling</Li>
<Li>Desktop Arrival Detector liveness signals (started / first-poll / no-candidate) help distinguish &quot;agent dead post-reboot&quot; from &quot;user never logged in&quot; in sessions that time out without a desktop_arrived</Li>
<Li>Detailed shutdown reasons — when the agent exits unexpectedly (Ctrl+C, process exit, unhandled exception, runtime host exit) the cause is recorded in the timeline</Li>
<Li>Prior-run crash is surfaced in the next session via a &quot;death rattle&quot; event, so a mid-enrollment agent crash is visible instead of silently lost</Li>
<Li>V2 diagnostics ZIP is size- and count-capped with streaming output — no more multi-gigabyte uploads on long or noisy sessions</Li>
<Li>Diagnostics ZIP now includes the <code className="text-xs bg-gray-100 px-1 py-0.5 rounded">State</code> and <code className="text-xs bg-gray-100 px-1 py-0.5 rounded">Spool</code> folders for richer post-mortem analysis</Li>
<Li>Agent log files rotate at a size cap — no unbounded growth on long-running devices</Li>
<Li>New &quot;Submit Logs&quot; page — admins can upload diagnostics files for analysis even when no active session exists on the device</Li>
<Li>Delivery Optimization breakdown adds MCC (Microsoft Connected Cache) and LinkLocal sources across <code className="text-xs bg-gray-100 px-1 py-0.5 rounded">download_progress</code> and <code className="text-xs bg-gray-100 px-1 py-0.5 rounded">do_telemetry</code> events</Li>
<Li>Software inventory now correctly enumerates Azure AD and personal MSA user profiles (these SIDs were previously skipped)</Li>
<Li>Hardware spec event reports VM detection — security analyze rules skip VMs to avoid false-positive vulnerability reports</Li>
<Li>Bootstrap <code className="text-xs bg-gray-100 px-1 py-0.5 rounded">--install</code> mode preserves an existing <code className="text-xs bg-gray-100 px-1 py-0.5 rounded">bootstrap-config.json</code> instead of clobbering customer settings on re-install</Li>
<Li>Optional &quot;enrollment started&quot; webhook fires at session registration — opt-in notification at the very start of an enrollment</Li>
</ChangelogBlock>
{/* ── April 2026 ───────────────────────────────── */}
<ChangelogBlock title="April 2026">
<Li>Delivery Optimization monitoring — agent tracks Windows DO download activity (OS level) during app installs and reports download performance metrics per application</Li>
<Li>ConfigMgr co-management detection — agent detects Configuration Manager client presence and reports co-management status with confidence scoring</Li>
<Li>Non-whitelisted hardware detection with optional admin alerts when devices with unapproved hardware models enroll</Li>
<Li>IME version change tracking — Intune Management Extension version updates are recorded</Li>
<Li>Hello for Business skip detection — agent now distinguishes between Hello setup being completed, timed out, or explicitly skipped</Li>
<Li>User-profile-aware diagnostics — gather rules and diagnostics log paths can reference the logged-on user profile directory</Li>
<Li>Improved vulnerability matching accuracy using fuzzy Jaro-Winkler scoring</Li>
<Li>Faster agent startup through optimized initialization flow</Li>
<Li>ESP provisioning status verification before enrollment completion — agent checks category outcomes and waits up to 30s for pending results to settle</Li>
<Li>Structured error codes (exit codes, HRESULT) extracted from IME log patterns and included in timeline events</Li>
<Li>Dual-hash integrity verification — ZIP package hash checked at download, separate EXE hash verified at runtime against backend to detect post-installation tampering</Li>
<Li>Vulnerability matching improvements — confidence levels, platform-aware filtering, and exclude patterns for more accurate reports</Li>
<Li>Vulnerability reports now available during pre-provisioning (White Glove) sessions</Li>
<Li>More reliable enrollment summary dialog launch with desktop fallback strategy</Li>
<Li>PowerShell script output is now fully captured in the timeline (multi-line output was previously truncated)</Li>
<Li>More reliable bootstrap and download handling with improved timeout and rate-limit behavior</Li>
<Li>Agent reports self-update events so updates are visible in the session timeline</Li>
<Li>Emergency channel — agent can send distress signals when it detects critical failures</Li>
<Li>ESP &quot;resumed&quot; event is now only emitted for Hybrid Join scenarios (avoids noise on other paths)</Li>
<Li>Improved crash recovery — completion state is persisted so the agent can resume correctly after an unexpected restart</Li>
</ChangelogBlock>
{/* ── Late March 2026 ──────────────────────────── */}
<ChangelogBlock title="Late March 2026">
<Li>Agent crash detection — crashes are automatically detected and reported to the backend</Li>
<Li>SHA-256 integrity verification for agent downloads (bootstrapper + self-updater verify hash before install)</Li>
<Li>Reboot tracking — reboots during enrollment are now tracked and visible in the timeline</Li>
<Li>NTP time sync check with clock skew warning when device time is significantly off</Li>
<Li>Automatic timezone detection and configuration</Li>
<Li>SecureBoot certificate collection for security posture reporting</Li>
<Li>IME process watcher — detects when the Intune Management Extension starts or stops</Li>
<Li>Network change detection — captures network adapter changes during enrollment</Li>
<Li>Agent self-update mechanism — outdated agents in the field update themselves automatically</Li>
<Li>Unrestricted mode option (per-tenant) to disable most guard rails</Li>
<Li>Notification system reworked — supports Teams (legacy + Workflow), Slack, and custom webhooks</Li>
</ChangelogBlock>
{/* ── Mid March 2026 ───────────────────────────── */}
<ChangelogBlock title="Mid March 2026">
<Li>Software inventory collection with automatic vulnerability correlation (CVE matching)</Li>
<Li>Hardware specification event — detailed hardware info collected and reported</Li>
<Li>Agent shutdown event — clean shutdown is now explicitly tracked</Li>
<Li>Postponed app detection and handling during enrollment</Li>
<Li>Self-deploying mode detection and event tracking</Li>
<Li>Enrollment summary dialog shown on the device after enrollment completes</Li>
<Li>ESP provisioning status tracking — catches non-IME errors like certificate failures</Li>
<Li>PowerShell script execution tracking during enrollment</Li>
<Li>Clock skew detection with geo-location failure reporting</Li>
<Li>Community analyze rules support</Li>
</ChangelogBlock>
{/* ── Early March 2026 ─────────────────────────── */}
<ChangelogBlock title="Early March 2026">
<Li>Bootstrap session support — monitoring starts before MDM enrollment (during OOBE)</Li>
<Li>ESP configuration detection — identifies ESP settings on the device</Li>
<Li>TPM info collection for device details</Li>
<Li>Activity-aware idle timeout replaces fixed 4-hour collector limit (default: 15 min idle)</Li>
<Li>Reliable session end-detection for all deployment scenarios (user-driven, pre-provisioning, hybrid)</Li>
<Li>Network performance data collection (latency, throughput)</Li>
<Li>Geographic location support via IP-based lookup</Li>
<Li>Emergency break — remote kill switch to stop agents</Li>
<Li>Automatic retry on transient backend errors</Li>
<Li>Custom User-Agent header for easier firewall allowlisting</Li>
<Li>ESP state tracking via registry watcher</Li>
<Li>XML and JSON file gathering in diagnostics</Li>
<Li>Configurable <code className="text-xs bg-gray-100 px-1 py-0.5 rounded">--await-enrollment</code> parameter for pre-enrollment wait</Li>
</ChangelogBlock>
{/* ── Late February 2026 ───────────────────────── */}
<ChangelogBlock title="Late February 2026">
<Li>Pre-Provisioning (White Glove) support — full end-to-end monitoring of pre-provisioning sessions</Li>
<Li>mTLS for all agent-to-backend communication (consolidated endpoints)</Li>
<Li>Diagnostics SAS URL fetched on-demand — no longer stored on disk</Li>
<Li>Max collector duration policy (configurable per tenant)</Li>
<Li>Diagnostics package upload from device</Li>
<Li>Configurable reboot-on-complete and keep-logfile options via remote config</Li>
<Li>Configurable diagnostics log paths (global + per-tenant)</Li>
<Li>Lenovo model detection fix (WMI query)</Li>
</ChangelogBlock>
{/* ── Mid February 2026 ────────────────────────── */}
<ChangelogBlock title="Mid February 2026">
<Li>Windows Autopilot v2 (Device Preparation) support</Li>
<Li>GatherRules guard rails — prevents collection of overly broad paths</Li>
<Li>IME log replay for testing and demos (<code className="text-xs bg-gray-100 px-1 py-0.5 rounded">--replay-log-dir</code>)</Li>
<Li>Agent state persistence — survives reboots and resumes monitoring</Li>
<Li>Embedded Intune root + intermediate certificates for chain validation</Li>
<Li>OS info and boot time collection</Li>
<Li>Hello screen detection improvements</Li>
<Li>Download progress tracking</Li>
</ChangelogBlock>
{/* ── Early February 2026 ──────────────────────── */}
<ChangelogBlock title="Early February 2026">
<Li>Initial agent release</Li>
<Li>Real-time enrollment telemetry (IME log parsing, ESP phases, app installs)</Li>
<Li>Geolocation support for enrollment sessions</Li>
<Li>Hello screen detector for enrollment completion</Li>
<Li>Reboot-on-complete support</Li>
<Li>Session ID persistence across agent restarts</Li>
<Li>Bootstrap token authentication for pre-MDM scenarios</Li>
</ChangelogBlock>
</section>
);
}
/* ── Helpers ──────────────────────────────────────────── */
function ChangelogBlock({ title, children }: { title: string; children: React.ReactNode }) {
return (
<div className="mb-6">
<h3 className="text-lg font-semibold text-gray-900 mb-2 border-b border-gray-200 pb-1">{title}</h3>
<ul className="space-y-1.5 text-sm text-gray-700 list-disc list-inside">{children}</ul>
</div>
);
}
function Li({ children }: { children: React.ReactNode }) {
return <li>{children}</li>;
}
File diff suppressed because it is too large Load Diff
@@ -1,200 +0,0 @@
export function SectionAgentSetup() {
return (
<section className="bg-white rounded-lg shadow-md p-8">
<div className="flex items-center space-x-3 mb-4">
<svg className="w-8 h-8 text-blue-600 shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12" />
</svg>
<h2 className="text-2xl font-bold text-gray-900">Agent Setup via Intune</h2>
</div>
<p className="text-gray-700 mb-4">
The Autopilot Monitor agent is deployed to devices using a PowerShell bootstrapper script distributed as an
Intune <strong>Platform Script</strong>. The script downloads, installs, and registers the agent automatically —
no manual steps on the device are required.
</p>
<div className="mb-6 p-4 bg-green-50 border border-green-200 rounded-lg text-sm text-green-900">
<p className="font-semibold mb-2 flex items-center gap-2">
<svg className="w-4 h-4 text-green-600 shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z" />
</svg>
Safe to assign broadly — already-enrolled devices are not affected
</p>
<p className="mb-3">
Before installing anything, the bootstrapper runs a series of pre-requisite checks. The agent is only
installed when <strong>all</strong> checks pass. Devices that do not meet the criteria are skipped silently.
</p>
<ul className="space-y-1.5 ml-1">
<li className="flex items-start gap-2">
<span className="text-green-600 font-bold mt-0.5 shrink-0">✓</span>
<span><strong>No previous deployment:</strong> A registry marker{" "}
<span className="font-mono text-xs bg-green-100 px-1.5 py-0.5 rounded">HKLM:\SOFTWARE\AutopilotMonitor\Deployed</span>{" "}
is the only artifact that survives agent self-destruct — everything else is removed. This marker acts as a critical security gate that permanently prevents repeated execution of the bootstrapper and agent on the same device.</span>
</li>
<li className="flex items-start gap-2">
<span className="text-green-600 font-bold mt-0.5 shrink-0">✓</span>
<span><strong>No real user profiles:</strong> Combines WMI ({" "}
<span className="font-mono text-xs bg-green-100 px-1.5 py-0.5 rounded">Win32_UserProfile.Special</span>{" "}
) and filesystem checks under{" "}
<span className="font-mono text-xs bg-green-100 px-1.5 py-0.5 rounded">C:\Users</span>{" "}
— system profiles (defaultuser*, Public, Default) are excluded. Real user profiles indicate the device is already in productive use.</span>
</li>
<li className="flex items-start gap-2">
<span className="text-green-600 font-bold mt-0.5 shrink-0">✓</span>
<span><strong>No previous user logon:</strong> Checks{" "}
<span className="font-mono text-xs bg-green-100 px-1.5 py-0.5 rounded">LastLoggedOnUser</span>{" "}
in the LogonUI registry — during Device ESP no real user has logged on yet. A real username indicates the device has been used interactively.</span>
</li>
<li className="flex items-start gap-2">
<span className="text-green-600 font-bold mt-0.5 shrink-0">✓</span>
<span><strong>Within bootstrap window:</strong> Device uptime must be under 12 hours. Prevents installation on devices that have been sitting powered on without completing enrollment. Sleep and standby do not reset this timer.</span>
</li>
<li className="flex items-start gap-2">
<span className="text-green-600 font-bold mt-0.5 shrink-0">✓</span>
<span><strong>Agent not already installed:</strong> If the agent binary is already present at the expected path, the script skips re-installation.</span>
</li>
</ul>
<p className="mt-3 text-green-800">
The agent is <strong>temporary by design</strong>: once the Autopilot enrollment completes, the agent
uninstalls itself and removes the scheduled task. It only exists on the device for the duration of the
enrollment process.
</p>
<div className="mt-4 pt-4 border-t border-green-200">
<p className="font-semibold mb-1 flex items-center gap-2">
<svg className="w-4 h-4 text-green-600 shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z" />
</svg>
Test it yourself: Dry-run before deployment
</p>
<p className="text-green-800 mb-2">
Want to verify which devices would receive the agent? Run this read-only check in PowerShell on any
machine — it evaluates all bootstrap guards and transparently reports the install decision.
No changes are made, only read operations:
</p>
<div className="bg-green-100 rounded px-3 py-2 font-mono text-xs select-all mb-2">
irm &apos;https://autopilotmonitor.blob.core.windows.net/agent/Test-ShouldBootstrapAgent.ps1&apos; | iex
</div>
<div className="flex flex-wrap items-center gap-2">
<a
href="https://github.com/okieselbach/Autopilot-Monitor/blob/main/scripts/Bootstrap/Test-ShouldBootstrapAgent.ps1"
target="_blank"
rel="noopener noreferrer"
className="inline-flex items-center gap-2 px-3 py-1.5 bg-green-700 hover:bg-green-800 text-white text-xs font-medium rounded-lg transition-colors"
>
<svg className="w-3.5 h-3.5" fill="currentColor" viewBox="0 0 24 24">
<path d="M12 0C5.37 0 0 5.37 0 12c0 5.31 3.435 9.795 8.205 11.385.6.105.825-.255.825-.57 0-.285-.015-1.23-.015-2.235-3.015.555-3.795-.735-4.035-1.41-.135-.345-.72-1.41-1.23-1.695-.42-.225-1.02-.78-.015-.795.945-.015 1.62.87 1.845 1.23 1.08 1.815 2.805 1.305 3.495.99.105-.78.42-1.305.765-1.605-2.67-.3-5.46-1.335-5.46-5.925 0-1.305.465-2.385 1.23-3.225-.12-.3-.54-1.53.12-3.18 0 0 1.005-.315 3.3 1.23.96-.27 1.98-.405 3-.405s2.04.135 3 .405c2.295-1.56 3.3-1.23 3.3-1.23.66 1.65.24 2.88.12 3.18.765.84 1.23 1.905 1.23 3.225 0 4.605-2.805 5.625-5.475 5.925.435.375.81 1.095.81 2.22 0 1.605-.015 2.895-.015 3.3 0 .315.225.69.825.57A12.02 12.02 0 0024 12c0-6.63-5.37-12-12-12z" />
</svg>
Test-ShouldBootstrapAgent.ps1
</a>
<a
href="https://raw.githubusercontent.com/okieselbach/Autopilot-Monitor/refs/heads/main/scripts/Bootstrap/Test-ShouldBootstrapAgent.ps1"
target="_blank"
rel="noopener noreferrer"
className="inline-flex items-center gap-1.5 px-2.5 py-1.5 text-green-700 hover:text-green-900 text-xs font-medium rounded-md transition-colors"
>
<svg className="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14" />
</svg>
Raw script
</a>
</div>
</div>
</div>
<ol className="space-y-5">
<li className="flex gap-4">
<span className="flex-shrink-0 w-7 h-7 rounded-full bg-blue-600 text-white text-sm font-bold flex items-center justify-center">1</span>
<div>
<p className="font-semibold text-gray-900">Download the bootstrapper script</p>
<p className="text-sm text-gray-600 mt-1 mb-2">
Download the PowerShell script that installs and configures the Autopilot Monitor agent:
</p>
<div className="flex flex-wrap items-center gap-2">
<a
href="https://github.com/okieselbach/Autopilot-Monitor/blob/main/scripts/Bootstrap/Install-AutopilotMonitor.ps1"
target="_blank"
rel="noopener noreferrer"
className="inline-flex items-center gap-2 px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white text-sm font-medium rounded-lg transition-colors"
>
<svg className="w-4 h-4" fill="currentColor" viewBox="0 0 24 24">
<path d="M12 0C5.37 0 0 5.37 0 12c0 5.31 3.435 9.795 8.205 11.385.6.105.825-.255.825-.57 0-.285-.015-1.23-.015-2.235-3.015.555-3.795-.735-4.035-1.41-.135-.345-.72-1.41-1.23-1.695-.42-.225-1.02-.78-.015-.795.945-.015 1.62.87 1.845 1.23 1.08 1.815 2.805 1.305 3.495.99.105-.78.42-1.305.765-1.605-2.67-.3-5.46-1.335-5.46-5.925 0-1.305.465-2.385 1.23-3.225-.12-.3-.54-1.53.12-3.18 0 0 1.005-.315 3.3 1.23.96-.27 1.98-.405 3-.405s2.04.135 3 .405c2.295-1.56 3.3-1.23 3.3-1.23.66 1.65.24 2.88.12 3.18.765.84 1.23 1.905 1.23 3.225 0 4.605-2.805 5.625-5.475 5.925.435.375.81 1.095.81 2.22 0 1.605-.015 2.895-.015 3.3 0 .315.225.69.825.57A12.02 12.02 0 0024 12c0-6.63-5.37-12-12-12z" />
</svg>
Install-AutopilotMonitor.ps1
</a>
<a
href="https://raw.githubusercontent.com/okieselbach/Autopilot-Monitor/refs/heads/main/scripts/Bootstrap/Install-AutopilotMonitor.ps1"
target="_blank"
rel="noopener noreferrer"
className="inline-flex items-center gap-1.5 px-2.5 py-1.5 text-gray-500 hover:text-gray-700 text-xs font-medium rounded-md transition-colors"
>
<svg className="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14" />
</svg>
Raw script
</a>
</div>
</div>
</li>
<li className="flex gap-4">
<span className="flex-shrink-0 w-7 h-7 rounded-full bg-blue-600 text-white text-sm font-bold flex items-center justify-center">2</span>
<div>
<p className="font-semibold text-gray-900">Create a Platform Script in Intune</p>
<p className="text-sm text-gray-600 mt-1">
In the <strong>Microsoft Intune admin center</strong>, navigate to{" "}
<span className="font-mono text-xs bg-gray-100 px-1.5 py-0.5 rounded">Devices → Scripts and remediations → Platform scripts</span>{" "}
and click <strong>+ Add → Windows 10 and later</strong>.
</p>
<div className="mt-3 bg-gray-50 rounded-lg p-4 text-sm space-y-1.5 text-gray-700">
<p className="font-medium text-gray-900 mb-2">Recommended script settings:</p>
<p><span className="font-medium w-48 inline-block">Name:</span> Install Autopilot Monitor</p>
<p><span className="font-medium w-48 inline-block">Script:</span> <em>Upload the downloaded .ps1 file</em></p>
<p><span className="font-medium w-48 inline-block">Run this script using logged on credentials:</span> No</p>
<p><span className="font-medium w-48 inline-block">Enforce script signature check:</span> No</p>
<p><span className="font-medium w-48 inline-block">Run script in 64-bit PowerShell:</span> Yes</p>
</div>
</div>
</li>
<li className="flex gap-4">
<span className="flex-shrink-0 w-7 h-7 rounded-full bg-blue-600 text-white text-sm font-bold flex items-center justify-center">3</span>
<div>
<p className="font-semibold text-gray-900">Assign to a device group</p>
<p className="text-sm text-gray-600 mt-1">
Assign the script to the device group that covers your Autopilot-enrolled devices. The two most common choices are:
</p>
<ul className="mt-2 space-y-1.5 text-sm text-gray-700 ml-2">
<li className="flex items-start gap-2">
<span className="text-blue-600 font-bold mt-0.5">•</span>
<span><strong>All devices</strong> — built-in Intune group, covers every managed device</span>
</li>
<li className="flex items-start gap-2">
<span className="text-blue-600 font-bold mt-0.5">•</span>
<span>
A dynamic Azure AD group for Autopilot devices using the membership rule{" "}
<span className="font-mono text-xs bg-gray-100 px-1.5 py-0.5 rounded">(device.devicePhysicalIds -any _ -startsWith &quot;[ZTDId]&quot;)</span>
{" "}— targets only Autopilot-registered hardware
</span>
</li>
</ul>
<p className="mt-2 text-sm text-gray-500 italic">
The &quot;All Autopilot devices&quot; dynamic group is preferred if you want to limit telemetry to Autopilot-enrolled hardware only.
</p>
</div>
</li>
<li className="flex gap-4">
<span className="flex-shrink-0 w-7 h-7 rounded-full bg-green-600 text-white text-sm font-bold flex items-center justify-center">✓</span>
<div>
<p className="font-semibold text-gray-900">Done</p>
<p className="text-sm text-gray-600 mt-1">
Once the script runs on a device, the agent installs itself, creates a scheduled task under
SYSTEM, and begins monitoring the Autopilot enrollment immediately. Sessions will appear in
your dashboard within seconds of the agent starting.
</p>
</div>
</li>
</ol>
</section>
);
}
@@ -1,425 +0,0 @@
export function SectionAnalyzeRules() {
return (
<section className="bg-white rounded-lg shadow-md p-8 space-y-8">
<div className="flex items-center space-x-3 mb-2">
<svg className="w-8 h-8 text-indigo-500 shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z" />
</svg>
<h2 className="text-2xl font-bold text-gray-900">Analyze Rules</h2>
</div>
<p className="text-gray-700 leading-relaxed">
Analyze Rules define <strong>when and why the agent flags an issue</strong> during enrollment. Each rule evaluates
events collected during the session and produces a <strong>confidence score</strong>. If the score reaches the configured
threshold the rule fires, creating a finding that appears in the session timeline and the analysis summary.
</p>
<div className="p-4 bg-blue-50 border border-blue-200 rounded-lg text-sm text-blue-900">
<p className="font-semibold mb-1">How scoring works</p>
<p>Every rule starts with a <strong>Base Confidence</strong> value (0–100). <strong>Confidence Factors</strong> are optional
conditions that add or subtract points when matched. The final score is compared to the <strong>Confidence Threshold</strong>.
The rule fires only if <code className="bg-blue-100 px-1 rounded">base + factors &ge; threshold</code>.</p>
</div>
{/* ── Conditions ── */}
<h3 className="text-xl font-semibold text-gray-900 pt-4 border-t border-gray-200">Conditions</h3>
<p className="text-gray-700 text-sm">
Conditions define <strong>what events or data</strong> the rule looks for. All <em>required</em> conditions must match
for the rule to proceed to scoring. Optional conditions are used only as confidence factors.
</p>
<div className="space-y-4">
{/* event_type */}
<div className="border border-gray-200 rounded-lg overflow-hidden">
<div className="px-4 py-2.5 bg-gray-100 border-b border-gray-200">
<p className="font-semibold text-sm text-gray-900">Source: <code className="font-mono">event_type</code></p>
</div>
<div className="px-4 py-4 space-y-2 text-sm text-gray-700">
<p>Checks whether a specific event type was emitted during the session. The most common condition type.</p>
<div className="grid grid-cols-1 sm:grid-cols-3 gap-3 text-xs">
<div><p className="font-medium text-gray-900">Signal</p><p className="text-gray-500">A label for this condition (e.g., <code className="bg-gray-100 px-1 rounded">app_failed</code>)</p></div>
<div><p className="font-medium text-gray-900">Event Type</p><p className="text-gray-500">The exact event type to look for (e.g., <code className="bg-gray-100 px-1 rounded">app_install_failed</code>)</p></div>
<div><p className="font-medium text-gray-900">Operator</p><p className="text-gray-500"><code className="bg-gray-100 px-1 rounded">exists</code> — the event occurred at all</p></div>
</div>
<div className="p-3 bg-green-50 border border-green-200 rounded-lg text-xs">
<p className="font-semibold text-green-900 mb-1">Example — detect any app installation failure</p>
<p>Signal: <strong>app_failed</strong> · Source: <strong>event_type</strong> · Event Type: <strong>app_install_failed</strong> · Operator: <strong>exists</strong></p>
</div>
</div>
</div>
{/* event_data */}
<div className="border border-gray-200 rounded-lg overflow-hidden">
<div className="px-4 py-2.5 bg-gray-100 border-b border-gray-200">
<p className="font-semibold text-sm text-gray-900">Source: <code className="font-mono">event_data</code></p>
</div>
<div className="px-4 py-4 space-y-2 text-sm text-gray-700">
<p>Inspects a field inside the <code className="bg-gray-100 px-1 rounded">data</code> payload of a specific event type. Use this to match on values like error codes or app names.</p>
<div className="p-3 bg-amber-50 border border-amber-200 rounded text-xs text-amber-900">
<strong>Important:</strong> The available data fields depend on <strong>which collector type</strong> produced the event.
Structured collectors (Registry, WMI, JSON, XML) expose individual named fields.
<strong>Command</strong> collectors produce only raw text — use <code className="bg-amber-100 px-1 rounded">dataField: &quot;output&quot;</code> with <code className="bg-amber-100 px-1 rounded">contains</code> or <code className="bg-amber-100 px-1 rounded">regex</code> to search the command output.
See the <em>Data fields by collector type</em> table in the Gather Rules section for a full reference.
</div>
<div className="grid grid-cols-1 sm:grid-cols-2 gap-3 text-xs mt-2">
<div>
<p className="font-medium text-gray-900">Operators</p>
<ul className="mt-1 space-y-0.5 text-gray-500">
<li><code className="bg-gray-100 px-1 rounded">equals</code> — exact match</li>
<li><code className="bg-gray-100 px-1 rounded">contains</code> / <code className="bg-gray-100 px-1 rounded">not_contains</code> — substring match</li>
<li><code className="bg-gray-100 px-1 rounded">regex</code> / <code className="bg-gray-100 px-1 rounded">not_regex</code> — regular expression match</li>
<li><code className="bg-gray-100 px-1 rounded">gt / lt / gte / lte</code> — numeric comparisons</li>
<li><code className="bg-gray-100 px-1 rounded">exists</code> / <code className="bg-gray-100 px-1 rounded">not_exists</code> — field presence check</li>
</ul>
</div>
<div>
<p className="font-medium text-gray-900">Common data fields</p>
<ul className="mt-1 space-y-0.5 text-gray-500">
<li><code className="bg-gray-100 px-1 rounded">errorCode</code> — Win32 / HTTP error code</li>
<li><code className="bg-gray-100 px-1 rounded">appName</code> — application name</li>
<li><code className="bg-gray-100 px-1 rounded">exitCode</code> — process exit code</li>
<li><code className="bg-gray-100 px-1 rounded">phase</code> — enrollment phase name</li>
<li><code className="bg-gray-100 px-1 rounded">output</code> — command stdout (Command collector)</li>
<li><code className="bg-gray-100 px-1 rounded">error_output</code> — command stderr (Command collector)</li>
</ul>
</div>
</div>
<div className="p-3 bg-green-50 border border-green-200 rounded-lg text-xs">
<p className="font-semibold text-green-900 mb-1">Example — detect error code 0x80070002</p>
<p>Source: <strong>event_data</strong> · Event Type: <strong>app_install_failed</strong> · Data Field: <strong>errorCode</strong> · Operator: <strong>equals</strong> · Value: <strong>0x80070002</strong></p>
</div>
<div className="p-3 bg-green-50 border border-green-200 rounded-lg text-xs">
<p className="font-semibold text-green-900 mb-1">Example — check command output for a certificate subject</p>
<p>Source: <strong>event_data</strong> · Event Type: <strong>gather_machine_cert_store</strong> · Data Field: <strong>output</strong> · Operator: <strong>not_contains</strong> · Value: <strong>CN=MyCertificate</strong></p>
<p className="text-green-700 mt-1">Confidence Factor: <code className="bg-green-100 px-1 rounded">gather_machine_cert_store.error_output exists</code> → +10 (command had errors)</p>
</div>
</div>
</div>
{/* event_data_array */}
<div className="border border-gray-200 rounded-lg overflow-hidden">
<div className="px-4 py-2.5 bg-gray-100 border-b border-gray-200">
<p className="font-semibold text-sm text-gray-900">Source: <code className="font-mono">event_data_array</code></p>
</div>
<div className="px-4 py-4 space-y-2 text-sm text-gray-700">
<p>Iterates an <strong>array field</strong> inside a single event and tests a sub-field on each element. The condition matches when <strong>any</strong> element satisfies the operator. Use this when one event carries a list (e.g. all detected provisioning packages) and you want to react per item — without needing one event per item.</p>
<div className="grid grid-cols-1 sm:grid-cols-3 gap-3 text-xs">
<div><p className="font-medium text-gray-900">Data Field</p><p className="text-gray-500">The array to iterate (e.g. <code className="bg-gray-100 px-1 rounded">artifacts</code>)</p></div>
<div><p className="font-medium text-gray-900">Item Field</p><p className="text-gray-500">Sub-field on each element to test (e.g. <code className="bg-gray-100 px-1 rounded">identity</code>). Leave empty to test scalar elements.</p></div>
<div><p className="font-medium text-gray-900">Operator / Value</p><p className="text-gray-500">Same operators as <code className="bg-gray-100 px-1 rounded">event_data</code>; applied to each element</p></div>
</div>
<div className="p-3 bg-blue-50 border border-blue-200 rounded text-xs text-blue-900">
<strong>Allow-list pattern:</strong> pair <code className="bg-blue-100 px-1 rounded">not_regex</code> with an allow-list regex in <em>Value</em>. The condition then fires only for elements <strong>not</strong> on the list — every allow-listed element is ignored. Evidence carries the first non-matching item (under the item-field name, so <code className="bg-blue-100 px-1 rounded">{`{{identity}}`}</code> interpolates) plus a <code className="bg-blue-100 px-1 rounded">matchCount</code>.
</div>
<div className="p-3 bg-green-50 border border-green-200 rounded-lg text-xs">
<p className="font-semibold text-green-900 mb-1">Example — flag a provisioning package not on the allow-list</p>
<p>Source: <strong>event_data_array</strong> · Event Type: <strong>provisioning_package_scan</strong> · Data Field: <strong>artifacts</strong> · Item Field: <strong>identity</strong> · Operator: <strong>not_regex</strong> · Value: <strong>{`^(?:Power\\.Settings|SecureStart\\.Settings)\\b`}</strong></p>
<p className="text-green-700 mt-1">Anchor the allow-list with <code className="bg-green-100 px-1 rounded">^</code> (start) and <code className="bg-green-100 px-1 rounded">\b</code> (boundary) — an unanchored substring pattern would also allow-list an impostor like <code className="bg-green-100 px-1 rounded">Contoso.Power.Settings.Backdoor</code>.</p>
</div>
</div>
</div>
{/* event_count */}
<div className="border border-gray-200 rounded-lg overflow-hidden">
<div className="px-4 py-2.5 bg-gray-100 border-b border-gray-200">
<p className="font-semibold text-sm text-gray-900">Source: <code className="font-mono">event_count</code></p>
</div>
<div className="px-4 py-4 space-y-2 text-sm text-gray-700">
<p>Checks how many times a specific event type occurred. Use with <code className="bg-gray-100 px-1 rounded">count_gte</code> or <code className="bg-gray-100 px-1 rounded">gt</code> to detect repeated failures.</p>
<div className="p-3 bg-green-50 border border-green-200 rounded-lg text-xs">
<p className="font-semibold text-green-900 mb-1">Example — detect 3 or more app failures</p>
<p>Source: <strong>event_count</strong> · Event Type: <strong>app_install_failed</strong> · Operator: <strong>count_gte</strong> · Value: <strong>3</strong></p>
</div>
</div>
</div>
{/* phase_duration */}
<div className="border border-gray-200 rounded-lg overflow-hidden">
<div className="px-4 py-2.5 bg-gray-100 border-b border-gray-200">
<p className="font-semibold text-sm text-gray-900">Source: <code className="font-mono">phase_duration</code></p>
</div>
<div className="px-4 py-4 space-y-2 text-sm text-gray-700">
<p>Measures how long a specific enrollment phase took (in seconds). Use with <code className="bg-gray-100 px-1 rounded">gt</code> or <code className="bg-gray-100 px-1 rounded">gte</code> to detect phases that run too long.</p>
<div className="p-3 bg-green-50 border border-green-200 rounded-lg text-xs">
<p className="font-semibold text-green-900 mb-1">Example — detect App Installation phase &gt; 1 hour</p>
<p>Source: <strong>phase_duration</strong> · Data Field: <strong>AppsDevice</strong> · Operator: <strong>gt</strong> · Value: <strong>3600</strong></p>
</div>
</div>
</div>
{/* event_correlation */}
<div className="border border-gray-200 rounded-lg overflow-hidden">
<div className="px-4 py-2.5 bg-gray-100 border-b border-gray-200">
<p className="font-semibold text-sm text-gray-900">Source: <code className="font-mono">event_correlation</code></p>
</div>
<div className="px-4 py-4 space-y-2 text-sm text-gray-700">
<p>Joins two event types on a shared field within a time window. Useful for detecting causal relationships — e.g., a network error that precedes a download failure.</p>
<div className="grid grid-cols-1 sm:grid-cols-2 gap-3 text-xs">
<div>
<p className="font-medium text-gray-900">Extra fields</p>
<ul className="mt-1 space-y-0.5 text-gray-500">
<li><code className="bg-gray-100 px-1 rounded">Correlate Event Type</code> — the second event to join with</li>
<li><code className="bg-gray-100 px-1 rounded">Join Field</code> — field that must match on both events</li>
<li><code className="bg-gray-100 px-1 rounded">Time Window (s)</code> — max seconds between the two events</li>
<li><code className="bg-gray-100 px-1 rounded">Event A Filter</code> — optional filter on the first event</li>
</ul>
</div>
<div className="p-3 bg-green-50 border border-green-200 rounded-lg">
<p className="font-semibold text-green-900 mb-1">Example — network error before download failure</p>
<p className="text-gray-700">Event Type A: <strong>network_error</strong></p>
<p className="text-gray-700">Correlate Event Type: <strong>app_download_failed</strong></p>
<p className="text-gray-700">Join Field: <strong>sessionId</strong></p>
<p className="text-gray-700">Time Window: <strong>120</strong> seconds</p>
</div>
</div>
</div>
</div>
</div>
{/* ── Trigger Types ── */}
<h3 className="text-xl font-semibold text-gray-900 pt-4 border-t border-gray-200">Trigger Types</h3>
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
<div className="border border-gray-200 rounded-lg p-4">
<p className="font-semibold text-gray-900 text-sm mb-1">Single</p>
<p className="text-xs text-gray-600">Evaluates each matching event independently. The rule fires once for every event that satisfies all required conditions.</p>
</div>
<div className="border border-gray-200 rounded-lg p-4">
<p className="font-semibold text-gray-900 text-sm mb-1">Correlation</p>
<p className="text-xs text-gray-600">Uses <code className="bg-gray-100 px-1 rounded">event_correlation</code> conditions to join two event streams. Fires when matching pairs are found within the time window.</p>
</div>
</div>
{/* ── Confidence ── */}
<h3 className="text-xl font-semibold text-gray-900 pt-4 border-t border-gray-200">Confidence Scoring</h3>
<div className="space-y-3 text-sm text-gray-700">
<p>The confidence model lets rules express <em>uncertainty</em>. A rule can fire with lower confidence when only partial evidence is present, and higher confidence when multiple corroborating signals align.</p>
<div className="border border-gray-200 rounded-lg overflow-hidden">
<table className="w-full text-xs">
<thead className="bg-gray-50 border-b border-gray-200">
<tr>
<th className="px-4 py-2 text-left font-semibold text-gray-700">Field</th>
<th className="px-4 py-2 text-left font-semibold text-gray-700">Description</th>
</tr>
</thead>
<tbody className="divide-y divide-gray-100">
<tr><td className="px-4 py-2 font-mono">baseConfidence</td><td className="px-4 py-2 text-gray-600">Starting score (0–100) when all required conditions match.</td></tr>
<tr><td className="px-4 py-2 font-mono">confidenceThreshold</td><td className="px-4 py-2 text-gray-600">Minimum score needed to fire the rule.</td></tr>
<tr><td className="px-4 py-2 font-mono">confidenceFactors</td><td className="px-4 py-2 text-gray-600">Optional conditions that add or subtract points from the base score when matched.</td></tr>
</tbody>
</table>
</div>
<div className="p-3 bg-amber-50 border border-amber-200 rounded-lg text-xs text-amber-900">
<strong>Tip:</strong> Start with <code className="bg-amber-100 px-1 rounded">baseConfidence: 50</code> and <code className="bg-amber-100 px-1 rounded">confidenceThreshold: 40</code>. Add confidence factors for additional signals (e.g., +20 if a specific error code matches, -10 if the app subsequently succeeded).
</div>
</div>
{/* ── Full Rule Examples ── */}
<h3 className="text-xl font-semibold text-gray-900 pt-4 border-t border-gray-200">Example Rules</h3>
<div className="space-y-5">
{/* Example 1 */}
<div className="border border-gray-200 rounded-lg overflow-hidden">
<div className="px-4 py-2.5 bg-indigo-50 border-b border-indigo-200">
<p className="font-semibold text-sm text-indigo-900">Example 1 — Repeated App Install Failure</p>
<p className="text-xs text-indigo-700 mt-0.5">Detect when three or more app installations fail in the same session</p>
</div>
<div className="px-4 py-4 text-xs space-y-2">
<div className="grid grid-cols-2 sm:grid-cols-4 gap-2">
<div><p className="text-gray-500">Category</p><p className="font-medium">apps</p></div>
<div><p className="text-gray-500">Severity</p><p className="font-medium">high</p></div>
<div><p className="text-gray-500">Base Confidence</p><p className="font-medium">60</p></div>
<div><p className="text-gray-500">Threshold</p><p className="font-medium">40</p></div>
</div>
<div className="bg-gray-50 border border-gray-200 rounded px-3 py-2 font-mono space-y-1">
<p className="text-gray-400">{`// Condition 1 (required)`}</p>
<p>{`source: "event_count" eventType: "app_install_failed" operator: "count_gte" value: "3"`}</p>
<p className="text-gray-400 pt-1">{`// Confidence Factor (+20 if error code indicates timeout)`}</p>
<p>{`signal: "timeout_code" condition: "errorCode contains 0x800704C7" weight: 20`}</p>
</div>
</div>
</div>
{/* Example 2 */}
<div className="border border-gray-200 rounded-lg overflow-hidden">
<div className="px-4 py-2.5 bg-indigo-50 border-b border-indigo-200">
<p className="font-semibold text-sm text-indigo-900">Example 2 — App Installation Phase Too Long</p>
<p className="text-xs text-indigo-700 mt-0.5">Fire when the Apps (Device) ESP phase exceeds 45 minutes</p>
</div>
<div className="px-4 py-4 text-xs space-y-2">
<div className="grid grid-cols-2 sm:grid-cols-4 gap-2">
<div><p className="text-gray-500">Category</p><p className="font-medium">esp</p></div>
<div><p className="text-gray-500">Severity</p><p className="font-medium">warning</p></div>
<div><p className="text-gray-500">Base Confidence</p><p className="font-medium">70</p></div>
<div><p className="text-gray-500">Threshold</p><p className="font-medium">50</p></div>
</div>
<div className="bg-gray-50 border border-gray-200 rounded px-3 py-2 font-mono space-y-1">
<p className="text-gray-400">{`// Condition (required)`}</p>
<p>{`source: "phase_duration" dataField: "AppsDevice" operator: "gt" value: "2700"`}</p>
</div>
</div>
</div>
{/* Example 3 */}
<div className="border border-gray-200 rounded-lg overflow-hidden">
<div className="px-4 py-2.5 bg-indigo-50 border-b border-indigo-200">
<p className="font-semibold text-sm text-indigo-900">Example 3 — Network Error Preceding Download Failure</p>
<p className="text-xs text-indigo-700 mt-0.5">Correlate a network drop with a subsequent app download failure within 2 minutes</p>
</div>
<div className="px-4 py-4 text-xs space-y-2">
<div className="grid grid-cols-2 sm:grid-cols-4 gap-2">
<div><p className="text-gray-500">Trigger</p><p className="font-medium">correlation</p></div>
<div><p className="text-gray-500">Category</p><p className="font-medium">network</p></div>
<div><p className="text-gray-500">Base Confidence</p><p className="font-medium">75</p></div>
<div><p className="text-gray-500">Threshold</p><p className="font-medium">60</p></div>
</div>
<div className="bg-gray-50 border border-gray-200 rounded px-3 py-2 font-mono space-y-1">
<p className="text-gray-400">{`// Correlation condition`}</p>
<p>{`source: "event_correlation" eventType: "network_error"`}</p>
<p>{`correlateEventType: "app_download_failed" joinField: "sessionId" timeWindowSeconds: 120`}</p>
</div>
</div>
</div>
{/* Example 4 */}
<div className="border border-gray-200 rounded-lg overflow-hidden">
<div className="px-4 py-2.5 bg-indigo-50 border-b border-indigo-200">
<p className="font-semibold text-sm text-indigo-900">Example 4 — Specific App Blocked by Disk Space</p>
<p className="text-xs text-indigo-700 mt-0.5">Detect a download stall caused by low disk space for a named application</p>
</div>
<div className="px-4 py-4 text-xs space-y-2">
<div className="grid grid-cols-2 sm:grid-cols-4 gap-2">
<div><p className="text-gray-500">Category</p><p className="font-medium">apps</p></div>
<div><p className="text-gray-500">Severity</p><p className="font-medium">critical</p></div>
<div><p className="text-gray-500">Base Confidence</p><p className="font-medium">55</p></div>
<div><p className="text-gray-500">Threshold</p><p className="font-medium">40</p></div>
</div>
<div className="bg-gray-50 border border-gray-200 rounded px-3 py-2 font-mono space-y-1">
<p className="text-gray-400">{`// Condition 1 — app failure occurred`}</p>
<p>{`source: "event_type" eventType: "app_install_failed" operator: "exists"`}</p>
<p className="text-gray-400 pt-1">{`// Condition 2 — error code is disk-full (0x80070070)`}</p>
<p>{`source: "event_data" eventType: "app_install_failed" dataField: "errorCode" operator: "equals" value: "0x80070070"`}</p>
<p className="text-gray-400 pt-1">{`// Confidence Factor (+30 if disk space event also fired)`}</p>
<p>{`signal: "disk_event" condition: "event_type disk_space_low exists" weight: 30`}</p>
</div>
</div>
</div>
{/* Example 5 */}
<div className="border border-gray-200 rounded-lg overflow-hidden">
<div className="px-4 py-2.5 bg-indigo-50 border-b border-indigo-200">
<p className="font-semibold text-sm text-indigo-900">Example 5 — Analyze Command Output (Gather Rule)</p>
<p className="text-xs text-indigo-700 mt-0.5">Check if a certificate subject is missing from certutil output</p>
</div>
<div className="px-4 py-4 text-xs space-y-2">
<div className="p-2 bg-gray-100 rounded text-gray-600">
<strong>Gather Rule:</strong> <code>certutil -store My</code> → outputs as event type <code>gather_machine_cert_store</code>
</div>
<div className="grid grid-cols-2 sm:grid-cols-4 gap-2">
<div><p className="text-gray-500">Category</p><p className="font-medium">identity</p></div>
<div><p className="text-gray-500">Severity</p><p className="font-medium">warning</p></div>
<div><p className="text-gray-500">Base Confidence</p><p className="font-medium">50</p></div>
<div><p className="text-gray-500">Threshold</p><p className="font-medium">40</p></div>
</div>
<div className="bg-gray-50 border border-gray-200 rounded px-3 py-2 font-mono space-y-1">
<p className="text-gray-400">{`// Condition 1 — certutil data was gathered`}</p>
<p>{`source: "event_type" eventType: "gather_machine_cert_store" operator: "exists"`}</p>
<p className="text-gray-400 pt-1">{`// Condition 2 — certificate subject not found in command output`}</p>
<p>{`source: "event_data" eventType: "gather_machine_cert_store" dataField: "output" operator: "not_contains" value: "CN=MyCert"`}</p>
<p className="text-gray-400 pt-1">{`// Confidence Factor (+20 if command produced no output at all)`}</p>
<p>{`signal: "no_output" condition: "gather_machine_cert_store.output not_exists" weight: 20`}</p>
<p className="text-gray-400">{`// Confidence Factor (+10 if command had errors)`}</p>
<p>{`signal: "cmd_error" condition: "gather_machine_cert_store.error_output exists" weight: 10`}</p>
</div>
</div>
</div>
{/* Example 6 */}
<div className="border border-gray-200 rounded-lg overflow-hidden">
<div className="px-4 py-2.5 bg-indigo-50 border-b border-indigo-200">
<p className="font-semibold text-sm text-indigo-900">Example 6 — Unexpected Provisioning Package (array + allow-list)</p>
<p className="text-xs text-indigo-700 mt-0.5">Fire for any provisioning package (PPKG) that is not on an allow-list — from the scan event(s) that list them all</p>
</div>
<div className="px-4 py-4 text-xs space-y-2">
<div className="p-2 bg-gray-100 rounded text-gray-600">
The agent emits a <code>provisioning_package_scan</code> event whose <code>artifacts</code> array lists every PPKG it found (each with an <code>identity</code>). This rule iterates that array instead of expecting one event per package. On devices with very many packages the array is split across several <code>provisioning_package_scan</code> events (<code>chunkIndex</code>/<code>chunkCount</code>) — <code>event_data_array</code> evaluates across all of them, so nothing is missed. (A separate built-in rule, <strong>ANALYZE-SEC-007</strong>, flags the rare case where a per-source collection cap was hit.)
</div>
<div className="grid grid-cols-2 sm:grid-cols-4 gap-2">
<div><p className="text-gray-500">Category</p><p className="font-medium">security</p></div>
<div><p className="text-gray-500">Severity</p><p className="font-medium">warning</p></div>
<div><p className="text-gray-500">Base Confidence</p><p className="font-medium">80</p></div>
<div><p className="text-gray-500">Threshold</p><p className="font-medium">40</p></div>
</div>
<div className="bg-gray-50 border border-gray-200 rounded px-3 py-2 font-mono space-y-1">
<p className="text-gray-400">{`// Condition (required) — any artifact identity NOT on the allow-list`}</p>
<p>{`source: "event_data_array" eventType: "provisioning_package_scan"`}</p>
<p>{`dataField: "artifacts" itemField: "identity" operator: "not_regex"`}</p>
<p>{`value: "^(?:Microsoft\\.Windows\\.Cosa|Power\\.EnergyEstimationEngine|Power\\.Settings|SecureStart\\.Settings)\\b"`}</p>
<p className="text-gray-400 pt-1">{`// Explanation can reference the offending item: "Unexpected package: {{identity}}"`}</p>
</div>
<p className="text-gray-600">The allow-list above covers the Windows OS-inbox packages that ship on every device, so a clean machine stays quiet. The pattern is <strong>anchored</strong> (<code className="bg-gray-100 px-1 rounded">^(?:…)\b</code>), so to allow your own vendor/recovery packages insert a new alternative <strong>inside the group, before the closing <code className="bg-gray-100 px-1 rounded">)</code></strong> — e.g. <code className="bg-gray-100 px-1 rounded">{`…|SecureStart\\.Settings|Acme\\.Recovery)\\b`}</code> (appending after the <code className="bg-gray-100 px-1 rounded">)</code> won&apos;t match). The built-in rules <strong>ANALYZE-SEC-005</strong> (always on) and <strong>ANALYZE-SEC-006</strong> (template, customizable allow-list) use exactly this pattern.</p>
</div>
</div>
</div>
{/* ── Template Rules ── */}
<h3 className="text-xl font-semibold text-gray-900 pt-4 border-t border-gray-200">Template Rules</h3>
<p className="text-gray-700 text-sm">
Some community rules contain <strong>placeholder values</strong> that must be customized for your environment before
they can work correctly. These rules are marked with a <span className="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-amber-100 text-amber-800 border border-amber-200">Requires Setup</span> badge.
</p>
<div className="space-y-4">
<div className="border border-amber-200 rounded-lg overflow-hidden">
<div className="px-4 py-2.5 bg-amber-50 border-b border-amber-200">
<p className="font-semibold text-sm text-amber-900">How template rules work</p>
</div>
<div className="px-4 py-4 space-y-3 text-sm text-gray-700">
<ol className="list-decimal list-inside space-y-2">
<li>When you click the <strong>enable toggle</strong> on a template rule, a configuration dialog opens instead of directly enabling the rule.</li>
<li>The dialog highlights the fields that need your environment-specific values (e.g., a certificate subject name).</li>
<li>After you enter your values and click <strong>Save &amp; Enable</strong>, a <strong>custom copy</strong> of the rule is created for your tenant with your values applied.</li>
<li>The original template rule remains disabled. Your custom copy is fully editable — you can adjust conditions, confidence, or other settings as needed.</li>
</ol>
<div className="p-3 bg-blue-50 border border-blue-200 rounded-lg text-xs text-blue-900">
<strong>Note:</strong> If you delete the custom copy, the template rule becomes available again and you can re-configure it.
Centrally updated templates (via reseed) do not affect your existing custom copies.
</div>
</div>
</div>
<div className="border border-gray-200 rounded-lg overflow-hidden">
<div className="px-4 py-2.5 bg-indigo-50 border-b border-indigo-200">
<p className="font-semibold text-sm text-indigo-900">Example — No Machine Certificates Found</p>
<p className="text-xs text-indigo-700 mt-0.5">Template rule that checks for a specific certificate subject in the local machine store</p>
</div>
<div className="px-4 py-4 text-xs space-y-2">
<p className="text-gray-600">This rule ships with the placeholder <code className="bg-gray-100 px-1 rounded">CN=YOUR-CERTIFICATE-SUBJECT</code>.
When you enable it, you are prompted to enter your actual certificate subject (e.g., <code className="bg-gray-100 px-1 rounded">CN=Contoso Root CA</code>).
The system creates a custom rule with your value automatically substituted into the condition.</p>
<div className="grid grid-cols-2 sm:grid-cols-4 gap-2 mt-2">
<div><p className="text-gray-500">Rule ID</p><p className="font-medium">ANALYZE-ID-001</p></div>
<div><p className="text-gray-500">Variable</p><p className="font-medium">Certificate Subject</p></div>
<div><p className="text-gray-500">Placeholder</p><p className="font-medium font-mono">CN=YOUR-CERTIFICATE-SUBJECT</p></div>
<div><p className="text-gray-500">Custom Copy ID</p><p className="font-medium font-mono">ANALYZE-ID-001-CUSTOM</p></div>
</div>
</div>
</div>
</div>
{/* ── JSON editing tip ── */}
<div className="p-4 bg-gray-50 border border-gray-200 rounded-lg text-sm text-gray-700">
<p className="font-semibold text-gray-900 mb-1">JSON editing</p>
<p>The Analyze Rules editor supports a <strong>JSON mode</strong> accessible via the Form / JSON toggle in the top-right of the create and edit panels.
Use JSON mode to author complex rules with multiple conditions, confidence factors, remediation steps, and <code className="bg-gray-100 px-1 rounded">event_correlation</code> properties that go beyond what the form UI exposes.</p>
</div>
</section>
);
}
@@ -1,169 +0,0 @@
import Link from "next/link";
function FaqItem({ question, children }: { question: string; children: React.ReactNode }) {
return (
<div className="border-b border-gray-100 pb-6 last:border-b-0 last:pb-0">
<h3 className="text-base font-semibold text-gray-900 mb-2">{question}</h3>
<div className="text-gray-700 text-sm leading-relaxed space-y-2">{children}</div>
</div>
);
}
export function SectionFaq() {
return (
<section className="bg-white rounded-lg shadow-md p-8">
<div className="flex items-center space-x-3 mb-4">
<svg className="w-8 h-8 text-blue-600 shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M8.228 9c.549-1.165 2.03-2 3.772-2 2.21 0 4 1.343 4 3 0 1.4-1.278 2.575-3.006 2.907-.542.104-.994.54-.994 1.093m0 3h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
<h2 className="text-2xl font-bold text-gray-900">Frequently Asked Questions</h2>
</div>
<p className="text-gray-700 leading-relaxed mb-8">
Common questions about Autopilot Monitor — from initial setup to day-to-day usage.
</p>
<div className="space-y-6">
{/* --- General --- */}
<h3 className="text-lg font-semibold text-gray-900 border-b border-gray-200 pb-2">General</h3>
<FaqItem question="What is Autopilot Monitor?">
<p>
Autopilot Monitor gives IT admins real-time visibility into Windows Autopilot enrollment sessions.
A lightweight agent runs on devices during enrollment and streams events to a web portal where you
can watch progress, diagnose failures, and review historical sessions.
</p>
</FaqItem>
<FaqItem question="Which Autopilot scenarios are supported?">
<p>
The agent supports <strong>Windows Autopilot</strong> and <strong>Autopilot Device Preparation</strong> (early testing)
enrollment flows. <strong>User-Driven</strong> and <strong>Pre-Provisioned</strong> (aka White Glove) flows are supported.
</p>
</FaqItem>
<FaqItem question="Is Autopilot Monitor free?">
<p>
Autopilot Monitor is currently in <strong>private preview</strong>. During the preview period access
is granted after approval. See the{" "}
<Link href="/docs/private-preview" className="text-blue-600 hover:underline">Private Preview</Link>{" "}
page for details on how to get started.
</p>
</FaqItem>
<FaqItem question="Where is my data stored?">
<p>
All session data is stored in our Azure environment in the <strong>West Europe</strong> region.
The backend runs as Azure Functions with Azure Table Storage. The agent communicates
securely with our backend endpoint and all data remains under your control.
</p>
</FaqItem>
{/* --- Setup & Agent --- */}
<h3 className="text-lg font-semibold text-gray-900 border-b border-gray-200 pb-2 mt-8">Setup &amp; Agent</h3>
<FaqItem question="How do I deploy the agent to devices?">
<p>
The agent is deployed through Intune as a bootstrapper PowerShell script. The{" "}
<Link href="/docs/agent-setup" className="text-blue-600 hover:underline">Agent Setup</Link>{" "}
guide walks you through the complete process.
</p>
</FaqItem>
<FaqItem question="Does the agent run permanently on the device?">
<p>
No. The agent is designed to run <strong>only during the enrollment window</strong>. It automatically
stops after the session completes or after an idle timeout. It does not run as a persistent background
service.
</p>
</FaqItem>
<FaqItem question="What data does the agent collect?">
<p>
The agent collects enrollment-related events: ESP phase transitions, app and script installations,
registry changes, IME log entries, and performance snapshots. It does <strong>not</strong> collect
personal user data, browsing history, or anything outside the enrollment process. See the{" "}
<Link href="/docs/agent" className="text-blue-600 hover:underline">Agent</Link>{" "}
page for the full list of collected data.
</p>
</FaqItem>
<FaqItem question="How does the agent authenticate?">
<p>
The agent uses the MDM <strong>client certificate</strong> issued from your Intune MDM system.
Every API call includes the certificate and device-identifying headers which the backend validates
against your tenant&apos;s configuration. In addition the client is validated against your Intune
tenant (registered as Autopilot device) to ensure it is belonging to your tenant before accepting
any data. This ensures that only devices under your management can send data to the backend.
</p>
</FaqItem>
{/* --- Portal & Features --- */}
<h3 className="text-lg font-semibold text-gray-900 border-b border-gray-200 pb-2 mt-8">Portal &amp; Features</h3>
<FaqItem question="What are Gather Rules?">
<p>
Gather Rules let you run custom diagnostic commands on devices during enrollment and collect the
output centrally. For example, you can read specific registry keys, run PowerShell commands, or
collect log files (Guardrails are applied). See the{" "}
<Link href="/docs/gather-rules" className="text-blue-600 hover:underline">Gather Rules</Link>{" "}
documentation for details and examples.
</p>
</FaqItem>
<FaqItem question="What are Analyze Rules?">
<p>
Analyze Rules automatically evaluate every enrollment session against configurable patterns
and flag known issues — like a missing app, a failed policy, or an unexpected reboot.
They surface problems with a clear description and suggested fix so you don&apos;t have to
manually hunt through event timelines. Learn more on the{" "}
<Link href="/docs/analyze-rules" className="text-blue-600 hover:underline">Analyze Rules</Link>{" "}
page.
</p>
</FaqItem>
<FaqItem question="Can I export or download diagnostics data?">
<p>
Yes. Each session detail view has a diagnostics download option that bundles the relevant logfiles
and gathered data into a downloadable package for offline analysis or sharing.
</p>
</FaqItem>
{/* --- Troubleshooting --- */}
<h3 className="text-lg font-semibold text-gray-900 border-b border-gray-200 pb-2 mt-8">Troubleshooting</h3>
<FaqItem question="The agent is deployed but I don't see any sessions in the portal.">
<p>
Check these common causes in order:
</p>
<ol className="list-decimal list-inside space-y-1 ml-2">
<li>Ensure the device is registered in Intune as an Autopilot device.</li>
<li>Verify if the Hardware Model and Vendor are allowed in the Tenant Settings - Hardware Whitelist.</li>
<li>Confirm the device can reach your Azure Functions backend endpoint (no firewall/proxy blocking).</li>
<li>Review the agent log at <code className="bg-gray-100 px-1 rounded text-xs">%ProgramData%\AutopilotMonitor\Logs</code> for error details.</li>
</ol>
</FaqItem>
<FaqItem question="A session shows as 'In Progress' but the enrollment already finished.">
<p>
This can happen when the completion signal is missed — for example if the device reboots
before the agent can detect the final state. The session will automatically transition
to a terminal state after the agent&apos;s max lifetime timer expires (default 6 hours).
You can also manually mark it as success or failure from the session detail view.
</p>
</FaqItem>
<FaqItem question="Where can I find the agent log files?">
<p>
Agent logs are stored at{" "}
<code className="bg-gray-100 px-1 rounded text-xs">%ProgramData%\AutopilotMonitor\Logs</code>{" "}
on the device. These logs contain detailed information about the agent&apos;s startup, event
collection, and communication with the backend.
</p>
</FaqItem>
</div>
</section>
);
}
@@ -1,461 +0,0 @@
"use client";
import { useState } from "react";
import {
REGISTRY_PREFIX_CATEGORIES,
COMMAND_CATEGORIES,
ALLOWED_FILE_PREFIXES,
ALLOWED_WMI_QUERY_PREFIXES,
} from "@/utils/guardrails.generated";
function GuardToggle({ label, children }: { label: string; children: React.ReactNode }) {
const [open, setOpen] = useState(false);
return (
<div>
<button
onClick={() => setOpen(v => !v)}
className="flex items-center gap-1 text-xs text-gray-500 hover:text-gray-700 mt-1 select-none"
>
<span>{open ? "▾" : "▸"}</span>
<span>{label}</span>
</button>
{open && <div className="mt-1">{children}</div>}
</div>
);
}
export function SectionGatherRules() {
return (
<section className="bg-white rounded-lg shadow-md p-8 space-y-8">
<div className="flex items-center space-x-3 mb-2">
<svg className="w-8 h-8 text-indigo-500 shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2" />
</svg>
<h2 className="text-2xl font-bold text-gray-900">Gather Rules</h2>
</div>
<p className="text-gray-700 leading-relaxed">
Gather Rules let you define <strong>what data the agent should collect</strong> from the device during enrollment.
Each rule specifies a <strong>collector type</strong> (how to collect), a <strong>target</strong> (what to collect),
optional <strong>parameters</strong> (filters and options), and a <strong>trigger</strong> (when to collect).
Results are sent as events to the backend and appear in the session timeline.
</p>
<div className="p-4 bg-blue-50 border border-blue-200 rounded-lg text-sm text-blue-900">
<p className="font-semibold mb-1">Security</p>
<p>All collector types enforce allowlists on the agent to prevent unauthorized data access.
Registry paths, file paths, WMI queries, and commands are validated against hardcoded allowlists before execution.
If a rule targets a disallowed resource, the agent emits a <code className="bg-blue-100 px-1 rounded">security_warning</code> event instead.</p>
</div>
{/* ── Collector Types ── */}
<h3 className="text-xl font-semibold text-gray-900 pt-4 border-t border-gray-200">Collector Types</h3>
{/* Registry */}
<div className="border border-gray-200 rounded-lg overflow-hidden">
<div className="px-4 py-2.5 bg-gray-100 border-b border-gray-200">
<p className="font-semibold text-sm text-gray-900">Registry</p>
</div>
<div className="px-4 py-4 space-y-3 text-sm text-gray-700">
<p>Reads values from the Windows Registry.</p>
<div>
<p className="font-medium text-gray-900">Target</p>
<p>Full registry path including hive prefix.</p>
<code className="block mt-1 bg-gray-50 border border-gray-200 rounded px-3 py-2 text-xs">HKLM\SOFTWARE\Microsoft\Enrollments</code>
</div>
<div>
<p className="font-medium text-gray-900">Parameters</p>
<ul className="list-disc ml-5 space-y-1">
<li><code className="bg-gray-100 px-1 rounded">valueName</code> — Read a specific value. Leave empty to read all values in the key (max 50).</li>
<li><code className="bg-gray-100 px-1 rounded">listSubkeys</code> — Set to <code className="bg-gray-100 px-1 rounded">true</code> to enumerate subkey names instead of values (max 100). Useful for keys like <code className="bg-gray-100 px-1 rounded">PolicyManager\current\device</code> where subkeys represent policy areas.</li>
</ul>
</div>
<div>
<p className="font-medium text-gray-900">Allowed Prefixes</p>
<p className="text-xs text-gray-500 mt-0.5">All paths are under <code className="bg-gray-100 px-1 rounded">HKLM\</code> or <code className="bg-gray-100 px-1 rounded">HKCU\</code>. Segment-bounded matching — subkeys are allowed, but sibling keys are not.</p>
<GuardToggle label="Show allowed registry prefixes">
<div className="bg-gray-50 border border-gray-200 rounded px-3 py-2 text-xs font-mono space-y-1">
{REGISTRY_PREFIX_CATEGORIES.map((cat, i) => (
<div key={cat.category}>
<p className={`text-gray-400 font-sans not-italic${i > 0 ? " pt-1" : ""}`}>{cat.category}</p>
{cat.items.map((p) => <p key={p}>{p}</p>)}
</div>
))}
</div>
</GuardToggle>
</div>
<div className="p-3 bg-green-50 border border-green-200 rounded-lg">
<p className="font-semibold text-green-900 text-xs mb-1">Example</p>
<p className="text-xs text-green-800">Read the BitLocker recovery key status:</p>
<code className="block mt-1 text-xs">Target: <strong>HKLM\SYSTEM\CurrentControlSet\Control\BitLockerStatus</strong></code>
</div>
</div>
</div>
{/* Event Log */}
<div className="border border-gray-200 rounded-lg overflow-hidden">
<div className="px-4 py-2.5 bg-gray-100 border-b border-gray-200">
<p className="font-semibold text-sm text-gray-900">Event Log</p>
</div>
<div className="px-4 py-4 space-y-3 text-sm text-gray-700">
<p>Reads entries from Windows Event Logs — supports both <strong>classic logs</strong> (Application, System, Security)
and <strong>operational/analytic logs</strong> (e.g., <code className="bg-gray-100 px-1 rounded">Microsoft-Windows-Shell-Core/Operational</code>).</p>
<div>
<p className="font-medium text-gray-900">Target</p>
<p>The full event log name.</p>
<code className="block mt-1 bg-gray-50 border border-gray-200 rounded px-3 py-2 text-xs">Microsoft-Windows-Shell-Core/Operational</code>
</div>
<div>
<p className="font-medium text-gray-900">Parameters</p>
<ul className="list-disc ml-5 space-y-1">
<li><code className="bg-gray-100 px-1 rounded">eventId</code> — Filter by a specific Event ID (e.g., <code className="bg-gray-100 px-1 rounded">62407</code>). Leave empty for all events.</li>
<li><code className="bg-gray-100 px-1 rounded">messageFilter</code> — Contains-filter on the event message. Use <code className="bg-gray-100 px-1 rounded">*</code> as wildcard (e.g., <code className="bg-gray-100 px-1 rounded">*ESPProgress*</code>).</li>
<li><code className="bg-gray-100 px-1 rounded">maxEntries</code> — Max events to return (1–50, default: 10).</li>
<li><code className="bg-gray-100 px-1 rounded">source</code> — Filter by provider/source name.</li>
</ul>
</div>
<div className="p-3 bg-green-50 border border-green-200 rounded-lg">
<p className="font-semibold text-green-900 text-xs mb-1">Example — ESP Progress Telemetry</p>
<p className="text-xs text-green-800">Collect Shell-Core ESP progress events at enrollment completion:</p>
<div className="mt-1 text-xs space-y-0.5">
<p>Target: <strong>Microsoft-Windows-Shell-Core/Operational</strong></p>
<p>Event ID: <strong>62407</strong></p>
<p>Message Filter: <strong>*ESPProgress*</strong></p>
<p>Max Entries: <strong>50</strong></p>
<p>Trigger: <strong>On Event</strong> → <code className="bg-green-100 px-1 rounded">enrollment_complete</code></p>
</div>
</div>
</div>
</div>
{/* WMI Query */}
<div className="border border-gray-200 rounded-lg overflow-hidden">
<div className="px-4 py-2.5 bg-gray-100 border-b border-gray-200">
<p className="font-semibold text-sm text-gray-900">WMI Query</p>
</div>
<div className="px-4 py-4 space-y-3 text-sm text-gray-700">
<p>Executes a WMI/CIM query using full <strong>WQL syntax</strong>. The target must be a complete <code className="bg-gray-100 px-1 rounded">SELECT</code> statement.</p>
<div>
<p className="font-medium text-gray-900">Target</p>
<p>Full WQL query string. Must start with an allowed class prefix.</p>
<code className="block mt-1 bg-gray-50 border border-gray-200 rounded px-3 py-2 text-xs">SELECT * FROM Win32_BIOS</code>
</div>
<div>
<p className="font-medium text-gray-900">Allowed WMI Classes</p>
<GuardToggle label="Show allowed WMI classes">
<div className="bg-gray-50 border border-gray-200 rounded px-3 py-2 text-xs font-mono columns-2 space-y-0.5">
{ALLOWED_WMI_QUERY_PREFIXES.map((q) => {
const cls = q.replace(/^SELECT \* FROM /i, "");
return <p key={cls}>{cls}</p>;
})}
</div>
</GuardToggle>
</div>
<div className="p-3 bg-green-50 border border-green-200 rounded-lg">
<p className="font-semibold text-green-900 text-xs mb-1">Example — Network Adapter Monitoring</p>
<p className="text-xs text-green-800">Monitor network adapters every 30 seconds during enrollment:</p>
<div className="mt-1 text-xs space-y-0.5">
<p>Target: <strong>SELECT * FROM Win32_NetworkAdapterConfiguration</strong></p>
<p>Trigger: <strong>Interval</strong> → 30 seconds</p>
</div>
</div>
</div>
</div>
{/* File */}
<div className="border border-gray-200 rounded-lg overflow-hidden">
<div className="px-4 py-2.5 bg-gray-100 border-b border-gray-200">
<p className="font-semibold text-sm text-gray-900">File</p>
</div>
<div className="px-4 py-4 space-y-3 text-sm text-gray-700">
<p>Checks file or directory existence and optionally reads file content. Environment variables are expanded.</p>
<div>
<p className="font-medium text-gray-900">Target</p>
<p>File or directory path. Environment variables like <code className="bg-gray-100 px-1 rounded">%ProgramData%</code> are supported.
The custom token <code className="bg-gray-100 px-1 rounded">%LOGGED_ON_USER_PROFILE%</code> resolves to the logged-on user&apos;s profile path (e.g. <code className="bg-gray-100 px-1 rounded">C:\Users\JohnDoe</code>).
Only <code className="bg-gray-100 px-1 rounded">AppData\Local</code> and <code className="bg-gray-100 px-1 rounded">AppData\Roaming</code> subdirectories are allowed.</p>
<code className="block mt-1 bg-gray-50 border border-gray-200 rounded px-3 py-2 text-xs">C:\Windows\Panther\UnattendGC\setupact.log</code>
</div>
<div className="p-3 bg-amber-50 border border-amber-200 rounded-lg text-xs text-amber-900">
<p className="font-semibold mb-1">%LOGGED_ON_USER_PROFILE% token</p>
<p>The agent runs as SYSTEM — standard variables like <code className="bg-amber-100 px-1 rounded">%USERPROFILE%</code> or <code className="bg-amber-100 px-1 rounded">%LOCALAPPDATA%</code> resolve to the SYSTEM profile, not the logged-on user.
Use <code className="bg-amber-100 px-1 rounded">%LOGGED_ON_USER_PROFILE%</code> instead to target user-specific log files.</p>
<p className="mt-1">Example: <code className="bg-amber-100 px-1 rounded">%LOGGED_ON_USER_PROFILE%\AppData\Local\RealmJoin\Logs\*.log</code></p>
<p className="mt-1 text-amber-700">During SYSTEM-context phases (before user logon), rules using this token are skipped automatically until a user session is detected.</p>
</div>
<div>
<p className="font-medium text-gray-900">Parameters</p>
<ul className="list-disc ml-5 space-y-1">
<li><code className="bg-gray-100 px-1 rounded">readContent</code> — Set to <code className="bg-gray-100 px-1 rounded">true</code> to read file content (files must be &lt;50 KB). The agent reads the <strong>last 4000 characters</strong> — most relevant for log files where recent entries are at the end.</li>
</ul>
</div>
<div>
<p className="font-medium text-gray-900">Allowed Path Prefixes</p>
<GuardToggle label="Show allowed file path prefixes">
<div className="bg-gray-50 border border-gray-200 rounded px-3 py-2 text-xs font-mono space-y-0.5">
{ALLOWED_FILE_PREFIXES.map((p) => <p key={p}>{p}</p>)}
</div>
</GuardToggle>
</div>
<div className="p-3 bg-green-50 border border-green-200 rounded-lg">
<p className="font-semibold text-green-900 text-xs mb-1">Example</p>
<p className="text-xs text-green-800">Read the Panther setup log on failure:</p>
<div className="mt-1 text-xs space-y-0.5">
<p>Target: <strong>C:\Windows\Panther\setuperr.log</strong></p>
<p>Parameters: <code className="bg-green-100 px-1 rounded">readContent: true</code></p>
<p>Trigger: <strong>On Event</strong> → <code className="bg-green-100 px-1 rounded">enrollment_failed</code></p>
</div>
</div>
</div>
</div>
{/* Command (Allowlisted) */}
<div className="border border-gray-200 rounded-lg overflow-hidden">
<div className="px-4 py-2.5 bg-gray-100 border-b border-gray-200">
<p className="font-semibold text-sm text-gray-900">Command (Allowlisted)</p>
</div>
<div className="px-4 py-4 space-y-3 text-sm text-gray-700">
<p>Runs a pre-approved command (PowerShell or CLI). Only commands from the <strong>exact allowlist</strong> are permitted — custom commands are blocked.</p>
<div>
<p className="font-medium text-gray-900">Target</p>
<p>The exact command string as it appears in the allowlist. Must match exactly (case-insensitive).</p>
</div>
<div>
<p className="font-medium text-gray-900">Allowed Commands</p>
<GuardToggle label="Show allowed commands">
<div className="bg-gray-50 border border-gray-200 rounded px-3 py-2 text-xs font-mono space-y-0.5">
{COMMAND_CATEGORIES.map((cat) => (
<div key={cat.category}>
<p className="text-gray-400"># {cat.category}</p>
{cat.items.map((cmd) => <p key={cmd}>{cmd}</p>)}
</div>
))}
</div>
</GuardToggle>
</div>
<div className="p-4 bg-amber-50 border border-amber-200 rounded-lg text-xs text-amber-900">
<p className="font-semibold mb-1">Data fields produced</p>
<p className="mb-2">Unlike structured collectors (JSON, XML, WMI) where individual fields are extracted, a command produces <strong>raw text output</strong>. The event data contains:</p>
<ul className="list-disc ml-5 space-y-0.5">
<li><code className="bg-amber-100 px-1 rounded">output</code> — Standard output (stdout) of the command, max 32 KB</li>
<li><code className="bg-amber-100 px-1 rounded">error_output</code> — Standard error (stderr), max 8 KB</li>
<li><code className="bg-amber-100 px-1 rounded">exit_code</code> — Process exit code (0 = success)</li>
<li><code className="bg-amber-100 px-1 rounded">command</code> — The command string that was executed</li>
</ul>
<p className="mt-2">In Analyze Rules, use <code className="bg-amber-100 px-1 rounded">dataField: &quot;output&quot;</code> with operators like <code className="bg-amber-100 px-1 rounded">contains</code>, <code className="bg-amber-100 px-1 rounded">not_contains</code>, or <code className="bg-amber-100 px-1 rounded">regex</code> to inspect the command output.</p>
</div>
<div className="p-3 bg-green-50 border border-green-200 rounded-lg">
<p className="font-semibold text-green-900 text-xs mb-1">Example — TPM at Enrollment Complete</p>
<div className="mt-1 text-xs space-y-0.5">
<p>Target: <strong>Get-Tpm</strong></p>
<p>Trigger: <strong>On Event</strong> → <code className="bg-green-100 px-1 rounded">enrollment_complete</code></p>
</div>
</div>
</div>
</div>
{/* Log Parser */}
<div className="border border-gray-200 rounded-lg overflow-hidden">
<div className="px-4 py-2.5 bg-gray-100 border-b border-gray-200">
<p className="font-semibold text-sm text-gray-900">Log Parser</p>
</div>
<div className="px-4 py-4 space-y-3 text-sm text-gray-700">
<p>Parses log files using regex patterns with named capture groups.
Each match emits a separate event. Supports <strong>CMTrace</strong> format (default) and <strong>plain text</strong> mode.
Supports position tracking to resume from the last read position.</p>
<div>
<p className="font-medium text-gray-900">Target</p>
<p>Path to a log file. Environment variables and the <code className="bg-gray-100 px-1 rounded">%LOGGED_ON_USER_PROFILE%</code> token are expanded. Supports <strong>wildcards</strong> (<code className="bg-gray-100 px-1 rounded">*</code> and <code className="bg-gray-100 px-1 rounded">?</code>) in the filename to match multiple files.</p>
<div className="mt-1 bg-gray-50 border border-gray-200 rounded px-3 py-2 text-xs font-mono space-y-0.5">
<p>%ProgramData%\Microsoft\IntuneManagementExtension\Logs\AppWorkload.log</p>
<p className="text-gray-400"># Wildcard examples:</p>
<p>%ProgramData%\Microsoft\IntuneManagementExtension\Logs\AppWorkload*.log</p>
<p>C:\Windows\Logs\CBS\CBS-??????.log</p>
<p className="text-gray-400"># User profile example:</p>
<p>%LOGGED_ON_USER_PROFILE%\AppData\Local\RealmJoin\Logs\*.log</p>
</div>
<p className="text-xs text-gray-400 mt-1">Wildcard matches are sorted by last write time (newest first), capped at 20 files. Position tracking works per file.</p>
</div>
<div>
<p className="font-medium text-gray-900">Parameters</p>
<ul className="list-disc ml-5 space-y-1">
<li><code className="bg-gray-100 px-1 rounded">pattern</code> <span className="text-red-500">(required)</span> — Regex with named capture groups, e.g., <code className="bg-gray-100 px-1 rounded">{`(?<appName>\\w+)`}</code></li>
<li><code className="bg-gray-100 px-1 rounded">format</code> — <code className="bg-gray-100 px-1 rounded">cmtrace</code> (default) or <code className="bg-gray-100 px-1 rounded">text</code>.
CMTrace mode parses log structure and matches regex against the message field.
Text mode matches regex directly against each raw line.</li>
<li><code className="bg-gray-100 px-1 rounded">trackPosition</code> — <code className="bg-gray-100 px-1 rounded">true</code> (default) to resume from last read position across executions.</li>
<li><code className="bg-gray-100 px-1 rounded">maxLines</code> — Max lines to read per file per execution (default: 1000).</li>
</ul>
</div>
<div className="space-y-2">
<div className="p-3 bg-green-50 border border-green-200 rounded-lg">
<p className="font-semibold text-green-900 text-xs mb-1">Example — CMTrace: IME App Workload</p>
<div className="mt-1 text-xs space-y-0.5">
<p>Target: <strong>%ProgramData%\Microsoft\IntuneManagementExtension\Logs\AppWorkload.log</strong></p>
<p>Format: <strong>CMTrace</strong> (default)</p>
<p>Pattern: <strong>{`(?<action>Install|Uninstall).*(?<appName>[A-Za-z0-9_-]+)`}</strong></p>
<p>Trigger: <strong>Interval</strong> → 30 seconds</p>
</div>
</div>
<div className="p-3 bg-green-50 border border-green-200 rounded-lg">
<p className="font-semibold text-green-900 text-xs mb-1">Example — Plain Text: CBS Logs with Wildcard</p>
<div className="mt-1 text-xs space-y-0.5">
<p>Target: <strong>C:\Windows\Logs\CBS\CBS*.log</strong></p>
<p>Format: <strong>Text</strong></p>
<p>Pattern: <strong>{`(?<timestamp>\\d{4}-\\d{2}-\\d{2}).*(?<level>Error|Warning).*(?<message>.*)`}</strong></p>
<p>Trigger: <strong>Startup</strong></p>
</div>
</div>
</div>
</div>
</div>
{/* JSON (JSONPath) */}
<div className="border border-gray-200 rounded-lg overflow-hidden">
<div className="px-4 py-2.5 bg-gray-100 border-b border-gray-200">
<p className="font-semibold text-sm text-gray-900">JSON (JSONPath)</p>
</div>
<div className="px-4 py-4 space-y-3 text-sm text-gray-700">
<p>Parses a <strong>JSON file</strong> and extracts values using <strong>JSONPath</strong> expressions.
Returns matched values as event data. File size limit is 200 KB.</p>
<div>
<p className="font-medium text-gray-900">Target</p>
<p>Path to a JSON file. Environment variables are expanded. Must be within allowed directories (same as File collector).</p>
</div>
<div>
<p className="font-medium text-gray-900">Parameters</p>
<ul className="list-disc ml-5 space-y-1">
<li><code className="bg-gray-100 px-1 rounded">jsonpath</code> <span className="text-red-500">(required)</span> — JSONPath expression to query the document.</li>
<li><code className="bg-gray-100 px-1 rounded">maxResults</code> — Maximum matches to return (default: 20, max: 100).</li>
</ul>
</div>
<div>
<p className="font-medium text-gray-900">JSONPath Syntax</p>
<div className="bg-gray-50 border border-gray-200 rounded px-3 py-2 text-xs font-mono space-y-0.5">
<p><span className="text-gray-400">$</span> — Root element</p>
<p><span className="text-gray-400">$.key</span> — Property of root</p>
<p><span className="text-gray-400">$.store.book[0]</span> — First array element</p>
<p><span className="text-gray-400">$.store.book[*].author</span> — All authors</p>
<p><span className="text-gray-400">$..price</span> — Recursive descent (all prices anywhere)</p>
<p><span className="text-gray-400">{`$.items[?(@.active==true)]`}</span> — Filter expression</p>
</div>
</div>
<div className="p-3 bg-green-50 border border-green-200 rounded-lg">
<p className="font-semibold text-green-900 text-xs mb-1">Example — Read IME Policy JSON</p>
<div className="mt-1 text-xs space-y-0.5">
<p>Target: <strong>C:\ProgramData\Microsoft\IntuneManagementExtension\Logs\HealthScripts.json</strong></p>
<p>JSONPath: <strong>$..DetectionScript</strong></p>
<p>Trigger: <strong>Startup</strong></p>
</div>
</div>
</div>
</div>
{/* XML (XPath) */}
<div className="border border-gray-200 rounded-lg overflow-hidden">
<div className="px-4 py-2.5 bg-gray-100 border-b border-gray-200">
<p className="font-semibold text-sm text-gray-900">XML (XPath)</p>
</div>
<div className="px-4 py-4 space-y-3 text-sm text-gray-700">
<p>Parses an <strong>XML file</strong> and extracts values using <strong>XPath</strong> expressions.
Returns matched elements/attributes as event data. File size limit is 200 KB. DTD processing is disabled for security.</p>
<div>
<p className="font-medium text-gray-900">Target</p>
<p>Path to an XML file. Environment variables are expanded. Must be within allowed directories (same as File collector).</p>
</div>
<div>
<p className="font-medium text-gray-900">Parameters</p>
<ul className="list-disc ml-5 space-y-1">
<li><code className="bg-gray-100 px-1 rounded">xpath</code> <span className="text-red-500">(required)</span> — XPath expression to query the document.</li>
<li><code className="bg-gray-100 px-1 rounded">namespaces</code> — Namespace declarations (format: <code className="bg-gray-100 px-1 rounded">prefix=uri;prefix2=uri2</code>).</li>
<li><code className="bg-gray-100 px-1 rounded">maxResults</code> — Maximum matches to return (default: 20, max: 100).</li>
</ul>
</div>
<div>
<p className="font-medium text-gray-900">XPath Syntax</p>
<div className="bg-gray-50 border border-gray-200 rounded px-3 py-2 text-xs font-mono space-y-0.5">
<p><span className="text-gray-400">/root/element</span> — Absolute path</p>
<p><span className="text-gray-400">//element</span> — Anywhere in document</p>
<p><span className="text-gray-400">{`/root/item[@id='1']`}</span> — Attribute filter</p>
<p><span className="text-gray-400">/root/element/@attr</span> — Attribute value</p>
<p><span className="text-gray-400">/root/element/text()</span> — Text content</p>
<p><span className="text-gray-400">count(//item)</span> — Count elements</p>
</div>
</div>
<div className="p-3 bg-green-50 border border-green-200 rounded-lg">
<p className="font-semibold text-green-900 text-xs mb-1">Example — Unattend.xml Settings</p>
<div className="mt-1 text-xs space-y-0.5">
<p>Target: <strong>C:\Windows\Panther\unattend.xml</strong></p>
<p>XPath: <strong>{`//ns:setting[@name='ComputerName']/@value`}</strong></p>
<p>Namespaces: <strong>ns=urn:schemas-microsoft-com:unattend</strong></p>
<p>Trigger: <strong>Startup</strong></p>
</div>
</div>
</div>
</div>
{/* ── Trigger Types ── */}
<h3 className="text-xl font-semibold text-gray-900 pt-4 border-t border-gray-200">Trigger Types</h3>
<p className="text-gray-700 text-sm">Triggers define <strong>when</strong> a gather rule executes. Choose the trigger that matches your collection needs.</p>
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
<div className="border border-gray-200 rounded-lg p-4">
<p className="font-semibold text-gray-900 text-sm mb-1">Startup</p>
<p className="text-xs text-gray-600">Runs once when the agent starts monitoring. Use for collecting initial device state (BIOS, TPM, OS info).</p>
</div>
<div className="border border-gray-200 rounded-lg p-4">
<p className="font-semibold text-gray-900 text-sm mb-1">Interval</p>
<p className="text-xs text-gray-600">Runs repeatedly at a configurable interval (5–3600 seconds). Use for continuous monitoring like network status or policy changes.</p>
</div>
<div className="border border-gray-200 rounded-lg p-4">
<p className="font-semibold text-gray-900 text-sm mb-1">Phase Change</p>
<p className="text-xs text-gray-600">Runs when enrollment transitions to a specific phase. Valid phases:</p>
<p className="text-xs text-gray-500 mt-1 font-mono">Start, DevicePreparation, DeviceSetup, AppsDevice, AccountSetup, AppsUser, FinalizingSetup, Complete, Failed</p>
</div>
<div className="border border-gray-200 rounded-lg p-4">
<p className="font-semibold text-gray-900 text-sm mb-1">On Event</p>
<p className="text-xs text-gray-600">Runs when a specific event type is emitted by the agent. Common event types:</p>
<p className="text-xs text-gray-500 mt-1 font-mono">enrollment_complete, enrollment_failed, app_install_failed, app_install_succeeded, phase_change</p>
<div className="mt-2 p-2 bg-amber-50 border border-amber-200 rounded text-xs text-amber-800">
<strong>Tip:</strong> Use <code className="bg-amber-100 px-1 rounded">enrollment_complete</code> or <code className="bg-amber-100 px-1 rounded">enrollment_failed</code> to collect data &quot;at the end&quot; of enrollment.
</div>
</div>
</div>
{/* ── Output ── */}
<h3 className="text-xl font-semibold text-gray-900 pt-4 border-t border-gray-200">Output</h3>
<p className="text-gray-700 text-sm">
Each gather rule execution emits an event with the configured <strong>Output Event Type</strong> and <strong>Severity</strong>.
The collected data is stored in the event&apos;s <code className="bg-gray-100 px-1 rounded">data</code> field as key-value pairs.
These events appear in the session timeline and can be inspected by <strong>Analyze Rules</strong> using the <code className="bg-gray-100 px-1 rounded">event_data</code> condition source.
</p>
<div className="p-4 bg-amber-50 border border-amber-200 rounded-lg text-sm text-amber-900">
<p className="font-semibold mb-2">Data fields by collector type</p>
<p className="text-xs mb-3">Each collector type produces different data fields. When writing Analyze Rules, you reference these fields via <code className="bg-amber-100 px-1 rounded">dataField</code> in <code className="bg-amber-100 px-1 rounded">event_data</code> conditions.</p>
<div className="border border-amber-200 rounded-lg overflow-hidden">
<table className="w-full text-xs">
<thead className="bg-amber-100/50 border-b border-amber-200">
<tr>
<th className="px-3 py-1.5 text-left font-semibold">Collector</th>
<th className="px-3 py-1.5 text-left font-semibold">Data Fields</th>
</tr>
</thead>
<tbody className="divide-y divide-amber-100">
<tr><td className="px-3 py-1.5 font-medium">Registry</td><td className="px-3 py-1.5">Value names as keys (e.g., <code className="bg-amber-100 px-1 rounded">DisplayName</code>), or <code className="bg-amber-100 px-1 rounded">subkey_count</code> + <code className="bg-amber-100 px-1 rounded">subkey_0</code>, <code className="bg-amber-100 px-1 rounded">subkey_1</code>, …</td></tr>
<tr><td className="px-3 py-1.5 font-medium">Event Log</td><td className="px-3 py-1.5">Event properties as key-value pairs (varies by event)</td></tr>
<tr><td className="px-3 py-1.5 font-medium">WMI Query</td><td className="px-3 py-1.5">WMI object properties as keys (e.g., <code className="bg-amber-100 px-1 rounded">Name</code>, <code className="bg-amber-100 px-1 rounded">Status</code>)</td></tr>
<tr><td className="px-3 py-1.5 font-medium">File</td><td className="px-3 py-1.5"><code className="bg-amber-100 px-1 rounded">exists</code>, <code className="bg-amber-100 px-1 rounded">path</code>, <code className="bg-amber-100 px-1 rounded">size_bytes</code>, <code className="bg-amber-100 px-1 rounded">content</code> (if readContent is true)</td></tr>
<tr className="bg-amber-100/30"><td className="px-3 py-1.5 font-medium">Command</td><td className="px-3 py-1.5"><code className="bg-amber-100 px-1 rounded">output</code> (stdout), <code className="bg-amber-100 px-1 rounded">error_output</code> (stderr), <code className="bg-amber-100 px-1 rounded">exit_code</code>, <code className="bg-amber-100 px-1 rounded">command</code> — raw text only, no parsed fields</td></tr>
<tr><td className="px-3 py-1.5 font-medium">Log Parser</td><td className="px-3 py-1.5">Named capture groups from regex (e.g., <code className="bg-amber-100 px-1 rounded">appName</code>, <code className="bg-amber-100 px-1 rounded">action</code>)</td></tr>
<tr><td className="px-3 py-1.5 font-medium">JSON</td><td className="px-3 py-1.5">Matched JSON values as structured key-value pairs</td></tr>
<tr><td className="px-3 py-1.5 font-medium">XML</td><td className="px-3 py-1.5">Matched XML elements/attributes as key-value pairs</td></tr>
</tbody>
</table>
</div>
</div>
</section>
);
}
@@ -1,180 +0,0 @@
export function SectionGeneral() {
return (
<section className="bg-white rounded-lg shadow-md p-8">
<div className="flex items-center space-x-3 mb-4">
<svg className="w-8 h-8 text-blue-600 shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M13 16h-1v-4h-1m1-4h.01M12 2a10 10 0 100 20 10 10 0 000-20z" />
</svg>
<h2 className="text-2xl font-bold text-gray-900">General</h2>
</div>
<p className="text-gray-700 leading-relaxed mb-8">
This section covers general concepts and UI features of the Autopilot Monitor portal that apply
across different pages.
</p>
{/* Admin Mode */}
<div className="mb-8">
<h3 className="text-lg font-semibold text-gray-900 mb-3 flex items-center gap-2">
<svg className="w-5 h-5 text-amber-500 shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
<path strokeLinecap="round" strokeLinejoin="round" d="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z" />
</svg>
Admin Mode
</h3>
<p className="text-gray-700 leading-relaxed mb-4">
Admin Mode is a safety toggle that gates access to destructive operations in the portal. It is only
available to users with the <strong>Admin</strong> role and must be explicitly enabled before any
destructive action can be performed. This prevents accidental deletions during normal day-to-day use.
</p>
<div className="bg-amber-50 border border-amber-200 rounded-lg px-4 py-3 mb-4 text-sm text-amber-900">
<div className="flex items-start gap-2">
<svg className="mt-0.5 h-5 w-5 shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 9v2m0 4h.01M12 2a10 10 0 100 20 10 10 0 000-20z" />
</svg>
<span>
Admin Mode is <strong>not persistent</strong> — it is stored in the browser&apos;s local storage and
resets when you clear your browser data. It is recommended to keep Admin Mode disabled when not actively
performing administrative actions.
</span>
</div>
</div>
<h4 className="text-sm font-semibold text-gray-800 mb-2">How to enable</h4>
<p className="text-gray-700 text-sm leading-relaxed mb-4">
Click the <strong>gear icon</strong> in the top navigation bar to open the settings menu. Under the{" "}
<strong>Administration</strong> section, toggle <strong>Admin Mode</strong> on. The toggle turns amber
when active and shows an <strong>ON</strong> label.
</p>
<h4 className="text-sm font-semibold text-gray-800 mb-2">What Admin Mode unlocks</h4>
<div className="overflow-x-auto">
<table className="w-full text-sm border border-gray-200 rounded-lg overflow-hidden">
<thead>
<tr className="bg-gray-50">
<th className="text-left px-4 py-2.5 font-semibold text-gray-700 border-b border-gray-200">Action</th>
<th className="text-left px-4 py-2.5 font-semibold text-gray-700 border-b border-gray-200">Location</th>
<th className="text-left px-4 py-2.5 font-semibold text-gray-700 border-b border-gray-200">Description</th>
</tr>
</thead>
<tbody className="divide-y divide-gray-100">
<tr>
<td className="px-4 py-2.5 font-medium text-gray-900">Delete Session</td>
<td className="px-4 py-2.5 text-gray-600">Dashboard &rarr; Actions column</td>
<td className="px-4 py-2.5 text-gray-600">
Permanently deletes an enrollment session and all associated event data. An additional{" "}
<strong>Actions</strong> column appears in the session table when Admin Mode is active.
</td>
</tr>
<tr>
<td className="px-4 py-2.5 font-medium text-gray-900">Mark as Failed</td>
<td className="px-4 py-2.5 text-gray-600">Session Detail page</td>
<td className="px-4 py-2.5 text-gray-600">
Manually marks a session that is currently <em>In Progress</em> or <em>Pending</em> as failed.
Useful when a session is stuck and will never complete on its own.
</td>
</tr>
<tr>
<td className="px-4 py-2.5 font-medium text-gray-900">Mark as Succeeded</td>
<td className="px-4 py-2.5 text-gray-600">Session Detail page</td>
<td className="px-4 py-2.5 text-gray-600">
Manually marks a session that is currently <em>In Progress</em> or <em>Pending</em> as succeeded.
Triggers the agent to stop monitoring and perform cleanup on the device (final data upload,
diagnostics collection, and optionally self-destruct based on tenant configuration).
</td>
</tr>
</tbody>
</table>
</div>
</div>
{/* Session Lifecycle */}
<div className="mb-8">
<h3 className="text-lg font-semibold text-gray-900 mb-3 flex items-center gap-2">
<svg className="w-5 h-5 text-blue-500 shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
<path strokeLinecap="round" strokeLinejoin="round" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" />
</svg>
Session Statuses
</h3>
<p className="text-gray-700 leading-relaxed mb-4">
Every enrollment session passes through a series of statuses that reflect the current state
of the Autopilot enrollment process on the device.
</p>
<div className="overflow-x-auto">
<table className="w-full text-sm border border-gray-200 rounded-lg overflow-hidden">
<thead>
<tr className="bg-gray-50">
<th className="text-left px-4 py-2.5 font-semibold text-gray-700 border-b border-gray-200">Status</th>
<th className="text-left px-4 py-2.5 font-semibold text-gray-700 border-b border-gray-200">Meaning</th>
</tr>
</thead>
<tbody className="divide-y divide-gray-100">
<tr>
<td className="px-4 py-2.5"><span className="inline-flex items-center px-2 py-0.5 rounded-full text-xs font-medium bg-blue-100 text-blue-800">InProgress</span></td>
<td className="px-4 py-2.5 text-gray-600">Enrollment events are actively being received from the device. The agent is monitoring the enrollment process.</td>
</tr>
<tr>
<td className="px-4 py-2.5"><span className="inline-flex items-center px-2 py-0.5 rounded-full text-xs font-medium bg-yellow-100 text-yellow-800">Pending</span></td>
<td className="px-4 py-2.5 text-gray-600">The session has been registered but is waiting for the user enrollment phase. This typically occurs after a White Glove (pre-provisioning) enrollment, where the device phase is complete and the device is waiting for the user to sign in and continue enrollment.</td>
</tr>
<tr>
<td className="px-4 py-2.5"><span className="inline-flex items-center px-2 py-0.5 rounded-full text-xs font-medium bg-green-100 text-green-800">Succeeded</span></td>
<td className="px-4 py-2.5 text-gray-600">The enrollment finished successfully. The device passed through all expected phases, or was manually marked as succeeded via Admin Mode.</td>
</tr>
<tr>
<td className="px-4 py-2.5"><span className="inline-flex items-center px-2 py-0.5 rounded-full text-xs font-medium bg-red-100 text-red-800">Failed</span></td>
<td className="px-4 py-2.5 text-gray-600">The enrollment ended in failure — either detected automatically by the agent or manually marked as failed via Admin Mode.</td>
</tr>
</tbody>
</table>
</div>
</div>
{/* Roles */}
<div>
<h3 className="text-lg font-semibold text-gray-900 mb-3 flex items-center gap-2">
<svg className="w-5 h-5 text-gray-500 shrink-0" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
<path strokeLinecap="round" strokeLinejoin="round" d="M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0z" />
</svg>
User Roles
</h3>
<p className="text-gray-700 leading-relaxed mb-4">
Access to the portal is controlled by role-based permissions. Each team member is assigned a role
that determines what they can see and do.
</p>
<div className="overflow-x-auto">
<table className="w-full text-sm border border-gray-200 rounded-lg overflow-hidden">
<thead>
<tr className="bg-gray-50">
<th className="text-left px-4 py-2.5 font-semibold text-gray-700 border-b border-gray-200">Role</th>
<th className="text-left px-4 py-2.5 font-semibold text-gray-700 border-b border-gray-200">Permissions</th>
</tr>
</thead>
<tbody className="divide-y divide-gray-100">
<tr>
<td className="px-4 py-2.5 font-medium text-gray-900">Admin</td>
<td className="px-4 py-2.5 text-gray-600">
Full access to all tenant configuration, sessions, diagnostics, and settings. Can manage team members,
enable Admin Mode for destructive operations, and configure all tenant-level settings.
The first user to sign in for a tenant is automatically granted the Admin role.
</td>
</tr>
<tr>
<td className="px-4 py-2.5 font-medium text-gray-900">Operator</td>
<td className="px-4 py-2.5 text-gray-600">
Can view sessions, manage Bootstrap Tokens (if enabled), and execute actions on devices. Cannot enable Admin Mode
or perform destructive operations like deleting sessions.
</td>
</tr>
</tbody>
</table>
</div>
</div>
</section>
);
}
@@ -1,273 +0,0 @@
export function SectionImeLogPatterns() {
return (
<section className="bg-white rounded-lg shadow-md p-8 space-y-8">
<div className="flex items-center space-x-3 mb-2">
<svg className="w-8 h-8 text-violet-500 shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M17.25 6.75L22.5 12l-5.25 5.25m-10.5 0L1.5 12l5.25-5.25m7.5-3l-4.5 16.5" />
</svg>
<h2 className="text-2xl font-bold text-gray-900">IME Log Patterns</h2>
</div>
<p className="text-gray-700 leading-relaxed">
IME Log Patterns are <strong>regular expressions (regex)</strong> that the Autopilot Monitor agent uses to
parse the <strong>Intune Management Extension (IME) log file</strong> in real time. Each line of the IME log is matched
against the active patterns — when a regex matches, the agent extracts data via <strong>named capture groups</strong> and
fires the corresponding <strong>action</strong>, producing a structured event that appears in the session timeline.
</p>
<div className="p-4 bg-blue-50 border border-blue-200 rounded-lg text-sm text-blue-900">
<p className="font-semibold mb-1">Why regex?</p>
<p>The IME log is a plain-text file with no structured format. Regex patterns allow the agent to reliably
extract information from free-form log lines — app download progress, install status changes, ESP phase transitions,
and more — without depending on a specific log format version.</p>
</div>
{/* ── How it works ── */}
<h3 className="text-xl font-semibold text-gray-900 pt-4 border-t border-gray-200">How It Works</h3>
<div className="space-y-3 text-sm text-gray-700">
<div className="grid grid-cols-1 sm:grid-cols-3 gap-4">
<div className="border border-gray-200 rounded-lg p-4">
<p className="font-semibold text-gray-900 mb-1">1. Pattern Matching</p>
<p className="text-xs text-gray-600">The agent reads the IME log line by line. Each line is tested against
all active patterns whose <strong>category</strong> applies to the current enrollment phase.</p>
</div>
<div className="border border-gray-200 rounded-lg p-4">
<p className="font-semibold text-gray-900 mb-1">2. Data Extraction</p>
<p className="text-xs text-gray-600">When a regex matches, <strong>named capture groups</strong> (e.g.{" "}
<code className="bg-gray-100 px-1 rounded">{`(?<appId>...)`}</code>) extract values from the log line
and pass them to the action handler.</p>
</div>
<div className="border border-gray-200 rounded-lg p-4">
<p className="font-semibold text-gray-900 mb-1">3. Event Generation</p>
<p className="text-xs text-gray-600">The action handler processes the extracted data and emits a
<strong> structured event</strong> — for example an app state change, an ESP phase transition,
or an error detection.</p>
</div>
</div>
</div>
{/* ── Pattern Structure ── */}
<h3 className="text-xl font-semibold text-gray-900 pt-4 border-t border-gray-200">Pattern Structure</h3>
<p className="text-gray-700 text-sm">
Each pattern is a JSON object with the following fields:
</p>
<div className="border border-gray-200 rounded-lg overflow-hidden">
<table className="w-full text-xs">
<thead className="bg-gray-50 border-b border-gray-200">
<tr>
<th className="px-4 py-2 text-left font-semibold text-gray-700">Field</th>
<th className="px-4 py-2 text-left font-semibold text-gray-700">Description</th>
</tr>
</thead>
<tbody className="divide-y divide-gray-100">
<tr><td className="px-4 py-2 font-mono">patternId</td><td className="px-4 py-2 text-gray-600">Unique identifier for the pattern (e.g. <code className="bg-gray-100 px-1 rounded">IME-DOWNLOADING</code>).</td></tr>
<tr><td className="px-4 py-2 font-mono">category</td><td className="px-4 py-2 text-gray-600">When the pattern is active: <code className="bg-gray-100 px-1 rounded">always</code>, <code className="bg-gray-100 px-1 rounded">currentPhase</code>, or <code className="bg-gray-100 px-1 rounded">otherPhases</code>.</td></tr>
<tr><td className="px-4 py-2 font-mono">pattern</td><td className="px-4 py-2 text-gray-600">The regex (C# syntax) applied to each log line. Uses named capture groups to extract values.</td></tr>
<tr><td className="px-4 py-2 font-mono">action</td><td className="px-4 py-2 text-gray-600">The handler that processes the match (e.g. <code className="bg-gray-100 px-1 rounded">updateStateDownloading</code>).</td></tr>
<tr><td className="px-4 py-2 font-mono">description</td><td className="px-4 py-2 text-gray-600">Human-readable description of what the pattern detects.</td></tr>
<tr><td className="px-4 py-2 font-mono">enabled</td><td className="px-4 py-2 text-gray-600">Whether the pattern is active. Disabled patterns are skipped during log parsing.</td></tr>
<tr><td className="px-4 py-2 font-mono">parameters</td><td className="px-4 py-2 text-gray-600">Optional key-value pairs passed to the action handler for additional configuration.</td></tr>
</tbody>
</table>
</div>
{/* ── Categories ── */}
<h3 className="text-xl font-semibold text-gray-900 pt-4 border-t border-gray-200">Categories</h3>
<p className="text-gray-700 text-sm">
Categories control <strong>when</strong> a pattern is evaluated relative to the current ESP phase:
</p>
<div className="grid grid-cols-1 sm:grid-cols-3 gap-4">
<div className="border-l-4 border-emerald-400 bg-emerald-50 rounded-r-lg p-4">
<p className="font-semibold text-sm text-emerald-900 mb-1">always</p>
<p className="text-xs text-emerald-800">Evaluated on <strong>every log line</strong>, regardless of the current phase. Used for universal signals like agent version detection, IME restarts, or enrollment completion.</p>
</div>
<div className="border-l-4 border-blue-400 bg-blue-50 rounded-r-lg p-4">
<p className="font-semibold text-sm text-blue-900 mb-1">currentPhase</p>
<p className="text-xs text-blue-800">Only evaluated during the <strong>active ESP phase</strong>. Used for tracking app downloads, installs, and other progress within the phase the user is currently in.</p>
</div>
<div className="border-l-4 border-purple-400 bg-purple-50 rounded-r-lg p-4">
<p className="font-semibold text-sm text-purple-900 mb-1">otherPhases</p>
<p className="text-xs text-purple-800">Evaluated for <strong>non-active phases</strong>. Used to detect apps that were already completed in a previous phase, so they can be filtered from the current view.</p>
</div>
</div>
{/* ── Actions ── */}
<h3 className="text-xl font-semibold text-gray-900 pt-4 border-t border-gray-200">Actions</h3>
<p className="text-gray-700 text-sm">
Each pattern specifies an <strong>action</strong> — a handler in the agent that processes the regex match and produces the corresponding event. The action determines what happens when the pattern matches.
</p>
<div className="border border-gray-200 rounded-lg overflow-hidden">
<table className="w-full text-xs">
<thead className="bg-gray-50 border-b border-gray-200">
<tr>
<th className="px-4 py-2 text-left font-semibold text-gray-700">Action</th>
<th className="px-4 py-2 text-left font-semibold text-gray-700">Purpose</th>
<th className="px-4 py-2 text-left font-semibold text-gray-700">Capture Groups</th>
</tr>
</thead>
<tbody className="divide-y divide-gray-100">
<tr><td className="px-4 py-2 font-mono">imeAgentVersion</td><td className="px-4 py-2 text-gray-600">Detect IME agent version</td><td className="px-4 py-2 font-mono text-gray-500">agentVersion</td></tr>
<tr><td className="px-4 py-2 font-mono">imeStarted</td><td className="px-4 py-2 text-gray-600">IME agent started</td><td className="px-4 py-2 text-gray-500">—</td></tr>
<tr><td className="px-4 py-2 font-mono">espPhaseDetected</td><td className="px-4 py-2 text-gray-600">ESP phase transition</td><td className="px-4 py-2 font-mono text-gray-500">espPhase</td></tr>
<tr><td className="px-4 py-2 font-mono">policiesDiscovered</td><td className="px-4 py-2 text-gray-600">App policies JSON found</td><td className="px-4 py-2 font-mono text-gray-500">policies</td></tr>
<tr><td className="px-4 py-2 font-mono">setCurrentApp</td><td className="px-4 py-2 text-gray-600">Set current app being processed</td><td className="px-4 py-2 font-mono text-gray-500">id</td></tr>
<tr><td className="px-4 py-2 font-mono">updateStateDownloading</td><td className="px-4 py-2 text-gray-600">App download progress</td><td className="px-4 py-2 font-mono text-gray-500">bytes, ofbytes</td></tr>
<tr><td className="px-4 py-2 font-mono">updateStateInstalling</td><td className="px-4 py-2 text-gray-600">App installation started</td><td className="px-4 py-2 text-gray-500">—</td></tr>
<tr><td className="px-4 py-2 font-mono">updateStateInstalled</td><td className="px-4 py-2 text-gray-600">App installation completed</td><td className="px-4 py-2 text-gray-500">—</td></tr>
<tr><td className="px-4 py-2 font-mono">updateStateError</td><td className="px-4 py-2 text-gray-600">App error detected</td><td className="px-4 py-2 text-gray-500">—</td></tr>
<tr><td className="px-4 py-2 font-mono">updateStateSkipped</td><td className="px-4 py-2 text-gray-600">App skipped</td><td className="px-4 py-2 text-gray-500">—</td></tr>
<tr><td className="px-4 py-2 font-mono">updateStatePostponed</td><td className="px-4 py-2 text-gray-600">App postponed</td><td className="px-4 py-2 text-gray-500">—</td></tr>
<tr><td className="px-4 py-2 font-mono">espTrackStatus</td><td className="px-4 py-2 text-gray-600">ESP tracked install status</td><td className="px-4 py-2 font-mono text-gray-500">from, to, id</td></tr>
<tr><td className="px-4 py-2 font-mono">updateName</td><td className="px-4 py-2 text-gray-600">Update app display name</td><td className="px-4 py-2 font-mono text-gray-500">id, name</td></tr>
<tr><td className="px-4 py-2 font-mono">updateWin32AppState</td><td className="px-4 py-2 text-gray-600">Win32 app state change</td><td className="px-4 py-2 font-mono text-gray-500">id, state</td></tr>
<tr><td className="px-4 py-2 font-mono">ignoreCompletedApp</td><td className="px-4 py-2 text-gray-600">App already completed in prior phase</td><td className="px-4 py-2 text-gray-500">—</td></tr>
<tr><td className="px-4 py-2 font-mono">cancelStuckAndSetCurrent</td><td className="px-4 py-2 text-gray-600">Cancel stuck app, set new current</td><td className="px-4 py-2 font-mono text-gray-500">id</td></tr>
<tr><td className="px-4 py-2 font-mono">enrollmentCompleted</td><td className="px-4 py-2 text-gray-600">Enrollment completed</td><td className="px-4 py-2 text-gray-500">—</td></tr>
</tbody>
</table>
</div>
{/* ── Named Capture Groups ── */}
<h3 className="text-xl font-semibold text-gray-900 pt-4 border-t border-gray-200">Named Capture Groups</h3>
<p className="text-gray-700 text-sm">
Capture groups are the bridge between the regex and the action handler. They use the syntax{" "}
<code className="bg-gray-100 px-1 rounded">{`(?<name>...)`}</code> to extract specific values from the matched log line.
</p>
<div className="p-4 bg-amber-50 border border-amber-200 rounded-lg text-sm text-amber-900">
<p className="font-semibold mb-1">GUID Placeholder</p>
<p>Patterns can use the <code className="bg-amber-100 px-1 rounded">{`{GUID}`}</code> placeholder, which the agent
automatically expands to a standard GUID regex pattern. This avoids repeating the verbose GUID regex in every pattern
that needs to match application IDs.</p>
</div>
{/* ── Examples ── */}
<h3 className="text-xl font-semibold text-gray-900 pt-4 border-t border-gray-200">Example Patterns</h3>
<div className="space-y-5">
{/* Example 1 */}
<div className="border border-gray-200 rounded-lg overflow-hidden">
<div className="px-4 py-2.5 bg-violet-50 border-b border-violet-200">
<p className="font-semibold text-sm text-violet-900">Example 1 — Detect IME Agent Version</p>
<p className="text-xs text-violet-700 mt-0.5">Category: <strong>always</strong> — matches on every log line</p>
</div>
<div className="px-4 py-4 text-xs space-y-2">
<div className="bg-gray-50 border border-gray-200 rounded px-3 py-2 font-mono space-y-1">
<p className="text-gray-400">{`// Pattern`}</p>
<p>{`Agent version is: (?<agentVersion>[\\d.]+)`}</p>
<p className="text-gray-400 pt-1">{`// Action: imeAgentVersion`}</p>
</div>
<div className="p-3 bg-green-50 border border-green-200 rounded-lg">
<p className="font-semibold text-green-900 mb-1">What happens</p>
<p className="text-green-800">When the IME log contains <code className="bg-green-100 px-1 rounded">Agent version is: 1.83.2405.0001</code>,
the capture group <code className="bg-green-100 px-1 rounded">agentVersion</code> extracts <code className="bg-green-100 px-1 rounded">1.83.2405.0001</code> and
the agent records the IME version for the session.</p>
</div>
</div>
</div>
{/* Example 2 */}
<div className="border border-gray-200 rounded-lg overflow-hidden">
<div className="px-4 py-2.5 bg-violet-50 border-b border-violet-200">
<p className="font-semibold text-sm text-violet-900">Example 2 — Track App Download Progress</p>
<p className="text-xs text-violet-700 mt-0.5">Category: <strong>currentPhase</strong> — only active during the current ESP phase</p>
</div>
<div className="px-4 py-4 text-xs space-y-2">
<div className="bg-gray-50 border border-gray-200 rounded px-3 py-2 font-mono space-y-1 overflow-x-auto">
<p className="text-gray-400">{`// Pattern`}</p>
<p className="whitespace-nowrap">{`\\[StatusService\\] Downloading app \\(id = {GUID}.*?\\) via (?<tech>\\w+), bytes (?<bytes>\\w+)/(?<ofbytes>\\w+) for user`}</p>
<p className="text-gray-400 pt-1">{`// Action: updateStateDownloading`}</p>
</div>
<div className="p-3 bg-green-50 border border-green-200 rounded-lg">
<p className="font-semibold text-green-900 mb-1">What happens</p>
<p className="text-green-800">Extracts the download technology (<code className="bg-green-100 px-1 rounded">tech</code>: DO or CDN),
bytes downloaded (<code className="bg-green-100 px-1 rounded">bytes</code>), and total size (<code className="bg-green-100 px-1 rounded">ofbytes</code>).
The agent updates the app state to &quot;downloading&quot; with real-time progress.</p>
</div>
</div>
</div>
{/* Example 3 */}
<div className="border border-gray-200 rounded-lg overflow-hidden">
<div className="px-4 py-2.5 bg-violet-50 border-b border-violet-200">
<p className="font-semibold text-sm text-violet-900">Example 3 — ESP Phase Transition</p>
<p className="text-xs text-violet-700 mt-0.5">Category: <strong>always</strong> — critical for tracking enrollment progress</p>
</div>
<div className="px-4 py-4 text-xs space-y-2">
<div className="bg-gray-50 border border-gray-200 rounded px-3 py-2 font-mono space-y-1">
<p className="text-gray-400">{`// Pattern`}</p>
<p>{`\\[Win32App\\] (?:In|The) EspPhase: (?<espPhase>\\w+)`}</p>
<p className="text-gray-400 pt-1">{`// Action: espPhaseDetected`}</p>
</div>
<div className="p-3 bg-green-50 border border-green-200 rounded-lg">
<p className="font-semibold text-green-900 mb-1">What happens</p>
<p className="text-green-800">Detects when the IME transitions between ESP phases (e.g.{" "}
<code className="bg-green-100 px-1 rounded">DeviceSetup</code>, <code className="bg-green-100 px-1 rounded">AccountSetup</code>).
This drives the phase-aware filtering of <code className="bg-green-100 px-1 rounded">currentPhase</code> and{" "}
<code className="bg-green-100 px-1 rounded">otherPhases</code> patterns.</p>
</div>
</div>
</div>
</div>
{/* ── Contributing Patterns ── */}
<h3 className="text-xl font-semibold text-gray-900 pt-4 border-t border-gray-200">Contributing Patterns</h3>
<div className="space-y-3 text-sm text-gray-700">
<p>Microsoft occasionally changes log formats in the Intune Management Extension. When this happens,
existing patterns may stop matching. If you notice that a pattern no longer fires for log lines it should
match, you can help by <strong>submitting a pull request</strong> on GitHub with an updated or new pattern.</p>
<div className="p-4 bg-blue-50 border border-blue-200 rounded-lg text-sm text-blue-900">
<p className="font-semibold mb-1">Debugging with the IME Pattern Match Log</p>
<p>If you suspect a pattern is no longer matching, enable the <strong>IME Pattern Match Log</strong> in the{" "}
<a href="/docs/settings" className="text-blue-700 hover:text-blue-900 underline">Settings</a> page.
When enabled, the agent writes every matched IME log line to a local file at{" "}
<code className="bg-blue-100 px-1 rounded">{`%ProgramData%\\AutopilotMonitor\\Logs\\ime_pattern_matches.log`}</code>.
This lets you see exactly which patterns are firing and which log lines are going unmatched —
making it much easier to identify what changed in the log format and adjust the regex accordingly.</p>
</div>
<div className="border border-gray-200 rounded-lg overflow-hidden">
<div className="px-4 py-3 bg-violet-50 border-b border-violet-200">
<p className="font-semibold text-sm text-violet-900">How to contribute</p>
</div>
<div className="px-4 py-4 space-y-3 text-sm text-gray-700">
<ol className="list-decimal list-inside space-y-2">
<li>Enable the <strong>IME Pattern Match Log</strong> in{" "}
<a href="/docs/settings" className="text-violet-600 hover:text-violet-800 underline">Settings</a>{" "}
and run an enrollment to capture which patterns match and which don&apos;t.</li>
<li>Open the <strong>IME Log Patterns</strong> page in the portal and find the pattern that no longer matches.</li>
<li>Use <strong>View as JSON</strong> to see the full pattern definition — this makes it easy to copy the current state.</li>
<li>Compare the regex with the actual log lines from the match log to identify what changed.</li>
<li>Submit a <strong>pull request</strong> on the{" "}
<a href="https://github.com/nickkieselbach/Autopilot-Monitor" target="_blank" rel="noopener noreferrer"
className="text-violet-600 hover:text-violet-800 underline">Autopilot Monitor GitHub repository</a>{" "}
with your updated pattern JSON. Pattern files are located in the <code className="bg-gray-100 px-1 rounded">rules/ime-log-patterns/</code> directory.</li>
<li>The team reviews the PR, validates the regex against known log samples, and merges it if it looks good.</li>
</ol>
</div>
</div>
</div>
{/* ── Portal ── */}
<div className="p-4 bg-gray-50 border border-gray-200 rounded-lg text-sm text-gray-700">
<p className="font-semibold text-gray-900 mb-1">IME Log Patterns page</p>
<p>Use the <strong>IME Log Patterns</strong> page in the portal to browse and filter all active patterns.
The page shows each pattern with its regex, action, category, and description. Use the <strong>View as JSON</strong> toggle
to see the full pattern definition — especially useful when preparing a pull request with updated or new patterns.</p>
</div>
</section>
);
}
@@ -1,286 +0,0 @@
export function SectionKnownIssues() {
return (
<section className="bg-white rounded-lg shadow-md p-8">
<div className="flex items-center space-x-3 mb-4">
<svg className="w-8 h-8 text-blue-600 shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24" strokeWidth={1.5}>
<path strokeLinecap="round" strokeLinejoin="round" d="M14.857 17.082a23.848 23.848 0 005.454-1.31A8.967 8.967 0 0118 9.75v-.7V9A6 6 0 006 9v.75a8.967 8.967 0 01-2.312 6.022c1.733.64 3.56 1.085 5.455 1.31m5.714 0a24.255 24.255 0 01-5.714 0m5.714 0a3 3 0 11-5.714 0" />
</svg>
<h2 className="text-2xl font-bold text-gray-900">Known Issues</h2>
</div>
<p className="text-gray-600 mb-8">
Documented issues caused by external changes (e.g.&nbsp;Microsoft updates) that affect Autopilot Monitor.
Each entry describes the impact, what still works, and whether a workaround exists.
</p>
<AnnouncementCard
date="2026-05-19"
title="Follow-up: Safe Deletion in Place &mdash; Cleanup Incident Resolved"
type="resolved"
>
<p>
Following the cleanup incident from 2026-04-16, the safeguards
announced at the time are now in place. There are two ways data can
be removed from Autopilot Monitor today, and both always create a
backup first and offer a way back.
</p>
<h4 className="font-semibold text-gray-900 mt-3">When sessions are deleted from the admin UI</h4>
<ul className="list-disc list-inside space-y-1">
<li>
Before anything is removed, the system collects a list of
everything that belongs to the session &mdash; events, analysis
results, software inventory, and related entries.
</li>
<li>
The deletion runs in steps and is safe to interrupt and resume.
The same session cannot accidentally be deleted twice or come
back through late agent traffic.
</li>
<li>
<strong>Recovery</strong>: a deletion can be reversed afterwards,
either completely or only for parts of the session. Counts and
summaries are corrected automatically.
</li>
</ul>
<h4 className="font-semibold text-gray-900 mt-3">When deletions happen behind the scenes (maintenance)</h4>
<ul className="list-disc list-inside space-y-1">
<li>
The original incident was a maintenance cleanup. These operations
now run through a guided procedure with several stop points along
the way.
</li>
<li>
A small sample is checked first and has to be explicitly confirmed
before anything else happens.
</li>
<li>
A full backup of all affected entries is written to disk before
any delete. If the amount is much larger than expected, the
procedure stops on its own.
</li>
<li>
The deletion then runs in two test rounds (first one entry, then
ten) before the rest follows &mdash; each round is verified
against the live data.
</li>
<li>
<strong>Recovery</strong>: the backup contains everything that was
removed and can be used to restore entries one-by-one or all at
once.
</li>
</ul>
<h4 className="font-semibold text-gray-900 mt-3">What this does and does not change</h4>
<p>
The events lost on 2026-04-16 cannot be recovered &mdash; that data
is gone. What these procedures guarantee is that any future
deletion has a backup and a way back, and that a single mistake
cannot cause the same kind of incident again.
</p>
<p>
No action needed on your side.
</p>
</AnnouncementCard>
<AnnouncementCard
date="2026-04-16"
title="Event Data Loss Due to Faulty Cleanup Operation"
type="breaking"
>
<p>
Due to an unfortunately faulty cleanup operation, a significant number of events were
deleted from the database. As a result, some sessions no longer have a complete or
correct timeline.
</p>
<p>
Affected sessions may show missing events, incomplete phases, or incorrect completion
states. There is no way to restore the deleted data retroactively.
</p>
<p>
Operational safeguards are being put in place to block and verify cleanup operations
before execution and prevent similar incidents in the future.
</p>
</AnnouncementCard>
<AnnouncementCard
date="2026-04-16"
title="Transparency Note &mdash; Root Cause of Today's Event Data Loss"
type="info"
>
<p>
I want to share a quick note with full transparency regarding an incident from today.
</p>
<p>
If you notice missing events in older session timelines, this is the reason: during a
storage migration to a new layout that improves performance, I identified some orphaned
event entries from the very early days of the platform and attempted to remove them.
Unfortunately, part of the filter logic was not applied as expected, and I did not catch
the issue quickly enough. As a result, a larger number of historical event entries were
deleted.
</p>
<p>
The impact is mainly limited to older session timelines. The platform is designed so
that events are most valuable during the enrollment itself and shortly afterwards for
troubleshooting and analysis. Over time, they become less critical and are used more
for reporting purposes. In addition, the default configuration already removes sessions
and events after 90 days. Even so, the impact is real, and I want to be open about it.
</p>
<p>
This happened while I was implementing a new table structure to address one of the root
causes identified during Private Preview: performance limitations caused by the previous
storage design. The new layout significantly improves that area, but in this case the
migration also introduced this incident.
</p>
<p>
I take this seriously. While issues like this can happen during a Private Preview,
especially in a fast-moving product, I know that does not reduce the impact. At the
moment, I also do not have a separate staging environment, so larger refactorings
currently have to be carried out on the live system. That is not ideal, and I will put
additional operational safeguards and procedures in place to reduce the risk of this
happening again.
</p>
<p>
Thank you for your understanding, your patience, and your trust. I hope this message
reflects the level of transparency I want to maintain while building the platform
together with early adopters.
</p>
</AnnouncementCard>
<AnnouncementCard
date="2026-04-16"
title="Agent Changes in Progress — Possible Detection Issues"
type="known-issue"
>
<p>
The agent is currently undergoing active changes. During this period,
detection and classification issues may occur (e.g.&nbsp;sessions not completing
correctly, events being misclassified, or sessions being falsely classified
as WhiteGlove).
</p>
<p>
This is actively being worked on. An update will follow once everything
is running correctly again.
</p>
</AnnouncementCard>
<AnnouncementCard
date="2026-04-06"
title="Delivery Optimization Data Restored via OS-Level Collection"
type="resolved"
>
<p>
Autopilot Monitor now collects Delivery Optimization data directly from the OS
using <code className="text-xs bg-gray-100 px-1 py-0.5 rounded">Get-DeliveryOptimizationStatus</code>,
bypassing the IME log entirely. This restores DO metrics
(<strong>BytesFromPeers</strong>, <strong>PeerCaching %</strong>, download progress)
for all devices &mdash; including those running IME &ge; 1.101.
</p>
<p>
The new OS-level collector works alongside existing IME log parsing. If both sources
provide data for the same app, the IME log path takes priority (dedup logic).
</p>
<p>
No action needed &mdash; devices running the latest agent version automatically
benefit from this change.
</p>
</AnnouncementCard>
<AnnouncementCard
date="2026-04-05"
title="IME 1.101.x Removes Delivery Optimization Telemetry from Logs"
type="breaking"
>
<p>
Starting with IME version <strong>1.101.x</strong>, Microsoft no longer writes Delivery Optimization (DO)
telemetry data to the IME log. This is a Microsoft-side change, not an Autopilot Monitor bug.
</p>
<h4 className="font-semibold text-gray-900 mt-3">What changed</h4>
<ul className="list-disc list-inside space-y-1">
<li>
<strong>Old IME (1.99.x)</strong>: Wrote{" "}
<code className="text-xs bg-gray-100 px-1 py-0.5 rounded">[DO TEL] = {"{"}JSON with all DO stats{"}"}</code>{" "}
after every download &mdash; full peer caching metrics were available.
</li>
<li>
<strong>New IME (1.101.x)</strong>: Only writes{" "}
<code className="text-xs bg-gray-100 px-1 py-0.5 rounded">[Win32App DO] DO download and decryption is successfully done</code>{" "}
&mdash; no DO telemetry JSON at all.
</li>
</ul>
<h4 className="font-semibold text-gray-900 mt-3">What the new IME still logs</h4>
<ul className="list-disc list-inside space-y-1">
<li>
<code className="text-xs bg-gray-100 px-1 py-0.5 rounded">[Win32App] Downloaded file size 37,187,491.00</code>{" "}
&mdash; file size only
</li>
<li>
<code className="text-xs bg-gray-100 px-1 py-0.5 rounded">[Win32App DO] start creating a new download job, FileId = ...</code>{" "}
&mdash; OriginalSize in ContentInfo JSON
</li>
<li>
<code className="text-xs bg-gray-100 px-1 py-0.5 rounded">[Win32App DO] DO Job set priority is BG_JOB_PRIORITY_FOREGROUND</code>{" "}
&mdash; download mode only
</li>
</ul>
<h4 className="font-semibold text-gray-900 mt-3">What is lost</h4>
<p>
The detailed DO stats &mdash; <strong>BytesFromPeers</strong>, <strong>PeerCaching %</strong>,{" "}
<strong>LanPeers</strong>, <strong>GroupPeers</strong>, and all other DO telemetry fields &mdash;{" "}
are no longer present in the IME logs. For IME &ge; 1.101 there is currently no way to extract
DO telemetry from the logs because the data is simply not written anymore.
</p>
<h4 className="font-semibold text-gray-900 mt-3">Impact on Autopilot Monitor</h4>
<p>
Sessions from devices running IME &ge; 1.101 will not show Delivery Optimization metrics
in the timeline. Older IME versions continue to work as before. We are monitoring whether
Microsoft re-introduces this data in a future IME release.
</p>
</AnnouncementCard>
</section>
);
}
/* ── Helpers ──────────────────────────────────────────── */
type BadgeType = "breaking" | "known-issue" | "info" | "resolved";
const BADGE_STYLES: Record<BadgeType, { bg: string; label: string }> = {
breaking: { bg: "bg-red-100 text-red-800", label: "Breaking Change" },
"known-issue": { bg: "bg-amber-100 text-amber-800", label: "Known Issue" },
info: { bg: "bg-blue-100 text-blue-800", label: "Info" },
resolved: { bg: "bg-green-100 text-green-800", label: "Resolved" },
};
function Badge({ type }: { type: BadgeType }) {
const { bg, label } = BADGE_STYLES[type];
return <span className={`inline-block text-xs font-medium px-2 py-0.5 rounded-full ${bg}`}>{label}</span>;
}
function AnnouncementCard({
date,
title,
type,
children,
}: {
date: string;
title: string;
type: BadgeType;
children: React.ReactNode;
}) {
return (
<div className="mb-6 border border-gray-200 rounded-lg p-5">
<div className="flex items-center gap-3 mb-1">
<span className="text-sm text-gray-500">{date}</span>
<Badge type={type} />
</div>
<h3 className="text-base font-semibold text-gray-900 mb-2">{title}</h3>
<div className="text-sm text-gray-700 leading-relaxed space-y-2">{children}</div>
</div>
);
}
@@ -1,432 +0,0 @@
"use client";
export function SectionMcpIntegration() {
return (
<section className="space-y-10">
{/* Header */}
<div className="bg-white rounded-lg shadow-md p-8">
<div className="flex items-center space-x-3 mb-4">
<svg className="w-8 h-8 text-blue-600 shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="m6.75 7.5 3 2.25-3 2.25m4.5 0h3m-9 8.25h13.5A2.25 2.25 0 0 0 21 18V6a2.25 2.25 0 0 0-2.25-2.25H5.25A2.25 2.25 0 0 0 3 6v12a2.25 2.25 0 0 0 2.25 2.25Z" />
</svg>
<h2 className="text-2xl font-bold text-gray-900">MCP Integration</h2>
</div>
<p className="text-gray-700 leading-relaxed mb-6">
Autopilot Monitor exposes a <strong>Model Context Protocol (MCP)</strong> server that lets AI assistants
query enrollment data, analyze sessions, and search across your fleet using natural language.
Connect your preferred MCP client &mdash; such as Claude Desktop, VS Code with Claude, or any
MCP-compatible tool &mdash; and interact with your enrollment data conversationally.
</p>
<div className="grid grid-cols-1 sm:grid-cols-3 gap-4">
<div className="bg-blue-50 rounded-lg p-4">
<p className="font-semibold text-blue-900 mb-1">Natural Language Queries</p>
<p className="text-sm text-blue-800">Ask questions about enrollments, failures, and device health in plain language.</p>
</div>
<div className="bg-indigo-50 rounded-lg p-4">
<p className="font-semibold text-indigo-900 mb-1">22 Specialized Tools</p>
<p className="text-sm text-indigo-800">Search sessions, analyze failures, query metrics, and explore device properties.</p>
</div>
<div className="bg-violet-50 rounded-lg p-4">
<p className="font-semibold text-violet-900 mb-1">Secure &amp; Scoped</p>
<p className="text-sm text-violet-800">Uses your existing auth token &mdash; data access is scoped to your tenant.</p>
</div>
</div>
</div>
{/* Architecture */}
<div className="bg-white rounded-lg shadow-md p-8">
<h3 className="text-xl font-semibold text-gray-900 mb-4">How It Works</h3>
<p className="text-gray-700 leading-relaxed mb-4">
The MCP server acts as a bridge between your AI assistant and the Autopilot Monitor backend.
Your existing authentication token is passed through &mdash; the MCP server never stores credentials.
</p>
<div className="bg-gray-50 rounded-lg p-6 font-mono text-sm text-gray-700">
<div className="flex items-center justify-center gap-3 flex-wrap">
<span className="bg-blue-100 text-blue-800 px-3 py-1.5 rounded-md">AI Client</span>
<span className="text-gray-400">&rarr;</span>
<span className="bg-indigo-100 text-indigo-800 px-3 py-1.5 rounded-md">MCP Server</span>
<span className="text-gray-400">&rarr;</span>
<span className="bg-violet-100 text-violet-800 px-3 py-1.5 rounded-md">Backend API</span>
<span className="text-gray-400">&rarr;</span>
<span className="bg-gray-200 text-gray-800 px-3 py-1.5 rounded-md">Your Data</span>
</div>
<p className="text-center text-xs text-gray-500 mt-3">Bearer token is forwarded with every request &mdash; no separate service credentials needed</p>
</div>
</div>
{/* Prerequisites */}
<div className="bg-white rounded-lg shadow-md p-8">
<h3 className="text-xl font-semibold text-gray-900 mb-4">Prerequisites</h3>
<ul className="space-y-3">
<li className="flex items-start gap-3">
<span className="mt-0.5 flex-shrink-0 w-6 h-6 bg-blue-100 text-blue-700 rounded-full flex items-center justify-center text-sm font-medium">1</span>
<div>
<p className="font-medium text-gray-900">Autopilot Monitor account with MCP access</p>
<p className="text-sm text-gray-600">Your administrator must enable MCP for your account. MCP access is managed under Settings &rarr; MCP Users.</p>
</div>
</li>
<li className="flex items-start gap-3">
<span className="mt-0.5 flex-shrink-0 w-6 h-6 bg-blue-100 text-blue-700 rounded-full flex items-center justify-center text-sm font-medium">2</span>
<div>
<p className="font-medium text-gray-900">An MCP-compatible AI client</p>
<p className="text-sm text-gray-600">Claude Desktop, VS Code with Claude extension, or any client supporting Streamable HTTP transport.</p>
</div>
</li>
</ul>
</div>
{/* Client Configuration */}
<div className="bg-white rounded-lg shadow-md p-8">
<h3 className="text-xl font-semibold text-gray-900 mb-4">Client Configuration</h3>
<p className="text-gray-700 leading-relaxed mb-4">
The MCP server uses <strong>Streamable HTTP</strong> transport with OAuth Bearer token authentication.
Add the following configuration to your MCP client:
</p>
<div className="space-y-6">
{/* Server URL */}
<div>
<h4 className="text-sm font-semibold text-gray-700 mb-2">Server URL</h4>
<div className="bg-gray-900 rounded-lg p-4 font-mono text-sm text-green-400 overflow-x-auto">
https://autopilotmonitor-mcp.kindwave-58b4b547.westeurope.azurecontainerapps.io/mcp
</div>
</div>
{/* Claude Desktop */}
<div>
<h4 className="text-sm font-semibold text-gray-700 mb-2">Claude Desktop</h4>
<p className="text-sm text-gray-600 mb-2">
In Claude Desktop, go to <strong>Settings &rarr; MCP Servers &rarr; Add</strong> and enter the server URL above.
OAuth authentication will be handled automatically via the browser.
</p>
</div>
{/* VS Code */}
<div>
<h4 className="text-sm font-semibold text-gray-700 mb-2">VS Code with Claude Extension</h4>
<p className="text-sm text-gray-600 mb-2">
Add the server to your <code className="bg-gray-100 px-1.5 py-0.5 rounded text-xs">.vscode/mcp.json</code> or user settings:
</p>
<div className="bg-gray-900 rounded-lg p-4 font-mono text-sm text-green-400 overflow-x-auto whitespace-pre">
{`{
"servers": {
"autopilot-monitor": {
"type": "http",
"url": "https://autopilotmonitor-mcp.kindwave-58b4b547.westeurope.azurecontainerapps.io/mcp"
}
}
}`}
</div>
</div>
{/* Verification */}
<div className="bg-blue-50 border border-blue-200 rounded-lg p-4">
<p className="text-sm font-medium text-blue-900 mb-1">Verify your connection</p>
<p className="text-sm text-blue-800">
After configuring the server, ask your AI assistant: <em>&quot;List all available tools from Autopilot Monitor&quot;</em>.
You should see 20+ tools listed. If authentication fails, ensure your MCP access has been enabled by an administrator.
</p>
</div>
</div>
</div>
{/* Available Tools */}
<div className="bg-white rounded-lg shadow-md p-8">
<h3 className="text-xl font-semibold text-gray-900 mb-6">Available Tools</h3>
{/* Search & Discovery */}
<div className="mb-8">
<h4 className="text-lg font-semibold text-gray-800 mb-3 flex items-center gap-2">
<span className="w-2 h-2 rounded-full bg-blue-500" />
Search &amp; Discovery
</h4>
<div className="overflow-x-auto">
<table className="min-w-full text-sm">
<thead>
<tr className="border-b border-gray-200">
<th className="text-left py-2 pr-4 font-medium text-gray-700 w-1/3">Tool</th>
<th className="text-left py-2 font-medium text-gray-700">Description</th>
</tr>
</thead>
<tbody className="divide-y divide-gray-100">
<tr>
<td className="py-2 pr-4 font-mono text-xs text-blue-700">search_sessions</td>
<td className="py-2 text-gray-600">Search enrollment sessions by status, device properties, serial number, manufacturer, model, OS build, geo location, and more. Supports dynamic device property filters with dot notation.</td>
</tr>
<tr>
<td className="py-2 pr-4 font-mono text-xs text-blue-700">search_sessions_by_event</td>
<td className="py-2 text-gray-600">Find sessions containing a specific event type (e.g. app install failure, phase transition, error). Use the <code className="bg-gray-100 px-1 rounded text-xs">event_types</code> resource for valid values.</td>
</tr>
<tr>
<td className="py-2 pr-4 font-mono text-xs text-blue-700">search_sessions_by_cve</td>
<td className="py-2 text-gray-600">Find devices affected by a specific CVE. Returns sessions where the vulnerability was detected during enrollment.</td>
</tr>
<tr>
<td className="py-2 pr-4 font-mono text-xs text-blue-700">search_events</td>
<td className="py-2 text-gray-600">Hybrid keyword + semantic event search. Maps a natural-language description to the right event types even with no literal word overlap (e.g. &quot;machine restarted unexpectedly&quot;). Use depth=&quot;deep&quot; for exhaustive recall.</td>
</tr>
<tr>
<td className="py-2 pr-4 font-mono text-xs text-blue-700">search_knowledge</td>
<td className="py-2 text-gray-600">Semantic search over analysis rules, gather rules, and IME log patterns. Helps the AI understand your configured rules and diagnostics.</td>
</tr>
</tbody>
</table>
</div>
</div>
{/* Session Analysis */}
<div className="mb-8">
<h4 className="text-lg font-semibold text-gray-800 mb-3 flex items-center gap-2">
<span className="w-2 h-2 rounded-full bg-indigo-500" />
Session Analysis
</h4>
<div className="overflow-x-auto">
<table className="min-w-full text-sm">
<thead>
<tr className="border-b border-gray-200">
<th className="text-left py-2 pr-4 font-medium text-gray-700 w-1/3">Tool</th>
<th className="text-left py-2 font-medium text-gray-700">Description</th>
</tr>
</thead>
<tbody className="divide-y divide-gray-100">
<tr>
<td className="py-2 pr-4 font-mono text-xs text-indigo-700">get_session</td>
<td className="py-2 text-gray-600">Full session details with all device metadata. Optionally includes AI rule analysis with failure explanations and remediation suggestions.</td>
</tr>
<tr>
<td className="py-2 pr-4 font-mono text-xs text-indigo-700">get_session_events</td>
<td className="py-2 text-gray-600">Event timeline for a session. Filter by event type, severity, or source (app name) for focused root cause analysis.</td>
</tr>
<tr>
<td className="py-2 pr-4 font-mono text-xs text-indigo-700">get_session_summary</td>
<td className="py-2 text-gray-600">Concise structured summary: overview, key events (noise filtered), rule analysis, and aggregate stats. Best starting point for session investigation.</td>
</tr>
</tbody>
</table>
</div>
</div>
{/* Metrics & Observability */}
<div className="mb-8">
<h4 className="text-lg font-semibold text-gray-800 mb-3 flex items-center gap-2">
<span className="w-2 h-2 rounded-full bg-emerald-500" />
Metrics &amp; Observability
</h4>
<div className="overflow-x-auto">
<table className="min-w-full text-sm">
<thead>
<tr className="border-b border-gray-200">
<th className="text-left py-2 pr-4 font-medium text-gray-700 w-1/3">Tool</th>
<th className="text-left py-2 font-medium text-gray-700">Description</th>
</tr>
</thead>
<tbody className="divide-y divide-gray-100">
<tr>
<td className="py-2 pr-4 font-mono text-xs text-emerald-700">get_metrics</td>
<td className="py-2 text-gray-600">Aggregated enrollment metrics: failure rates, slowest/most-failing apps, session counts. Supports 7, 30, or 90 day windows.</td>
</tr>
<tr>
<td className="py-2 pr-4 font-mono text-xs text-emerald-700">get_app_install_metrics</td>
<td className="py-2 text-gray-600">App-install health over a window: top failing apps with failure rates and their most common failure codes, slowest apps by average install duration, and a Delivery Optimization rollup (bytes from peers / Microsoft Connected Cache vs. CDN, plus peer-offload percentage). 1&ndash;365 day window (default 30).</td>
</tr>
<tr>
<td className="py-2 pr-4 font-mono text-xs text-emerald-700">get_geographic_metrics</td>
<td className="py-2 text-gray-600">Geographic distribution of enrollments with performance comparisons across locations.</td>
</tr>
<tr>
<td className="py-2 pr-4 font-mono text-xs text-emerald-700">get_geographic_sessions</td>
<td className="py-2 text-gray-600">Drill into a specific location by country, region, or city to see enrollment details.</td>
</tr>
<tr>
<td className="py-2 pr-4 font-mono text-xs text-emerald-700">get_vulnerability_summary</td>
<td className="py-2 text-gray-600">Vulnerability exposure summary from detected CVEs: affected device count, distinct CVE and CISA Known-Exploited (KEV) counts, severity breakdown, and the top CVEs ranked by affected devices. Use <code className="bg-gray-100 px-1 rounded text-xs">search_sessions_by_cve</code> for the device list of a single CVE.</td>
</tr>
<tr>
<td className="py-2 pr-4 font-mono text-xs text-emerald-700">get_rule_stats</td>
<td className="py-2 text-gray-600">Firing statistics for analyze and gather rules: which rules fire most often, their hit rates (fires/evaluations), and daily trends. Filter by rule type and date window to keep responses lean.</td>
</tr>
<tr>
<td className="py-2 pr-4 font-mono text-xs text-emerald-700">get_ime_version_history</td>
<td className="py-2 text-gray-600">History of all IME (Intune Management Extension) agent versions seen across enrollments &mdash; first/last seen and session counts per version. A permanent archive that survives data retention, useful for tracking Microsoft IME rollouts.</td>
</tr>
<tr>
<td className="py-2 pr-4 font-mono text-xs text-emerald-700">get_usage_metrics</td>
<td className="py-2 text-gray-600">Usage statistics for your tenant: session volumes, feature adoption, success rate, and active users. 1&ndash;365 day window (default 30).</td>
</tr>
</tbody>
</table>
</div>
</div>
{/* Device Management & Admin */}
<div className="mb-8">
<h4 className="text-lg font-semibold text-gray-800 mb-3 flex items-center gap-2">
<span className="w-2 h-2 rounded-full bg-amber-500" />
Inventory &amp; Audit
</h4>
<div className="overflow-x-auto">
<table className="min-w-full text-sm">
<thead>
<tr className="border-b border-gray-200">
<th className="text-left py-2 pr-4 font-medium text-gray-700 w-1/3">Tool</th>
<th className="text-left py-2 font-medium text-gray-700">Description</th>
</tr>
</thead>
<tbody className="divide-y divide-gray-100">
<tr>
<td className="py-2 pr-4 font-mono text-xs text-amber-700">get_software_inventory</td>
<td className="py-2 text-gray-600">Installed-software catalog discovered on enrolled devices, deduplicated by normalized vendor/name/version with publisher, registry source, CPE mapping for vulnerability correlation, session count, and last-seen. Paginated &mdash; pass the returned <span className="font-mono text-xs">nextLink</span> back as <span className="font-mono text-xs">continuation</span>.</td>
</tr>
<tr>
<td className="py-2 pr-4 font-mono text-xs text-amber-700">get_audit_logs</td>
<td className="py-2 text-gray-600">Audit trail of configuration changes, device blocks, and user management actions. Filterable by date window, action, actor (performedBy), entity type, and entity id; paginated.</td>
</tr>
</tbody>
</table>
</div>
</div>
{/* Raw Data */}
<div>
<h4 className="text-lg font-semibold text-gray-800 mb-3 flex items-center gap-2">
<span className="w-2 h-2 rounded-full bg-gray-500" />
Raw Data Queries
</h4>
<div className="overflow-x-auto">
<table className="min-w-full text-sm">
<thead>
<tr className="border-b border-gray-200">
<th className="text-left py-2 pr-4 font-medium text-gray-700 w-1/3">Tool</th>
<th className="text-left py-2 font-medium text-gray-700">Description</th>
</tr>
</thead>
<tbody className="divide-y divide-gray-100">
<tr>
<td className="py-2 pr-4 font-mono text-xs text-gray-700">query_raw_events</td>
<td className="py-2 text-gray-600">Query raw event data with flexible filters and field projection. Pass a lean <span className="font-mono text-xs">fields=</span> list to drop the heavy per-event <span className="font-mono text-xs">data</span> payload for counting/aggregation. When querying by session ID the tenant is auto-resolved from the session. Useful for custom analysis beyond the high-level tools.</td>
</tr>
<tr>
<td className="py-2 pr-4 font-mono text-xs text-gray-700">query_raw_sessions</td>
<td className="py-2 text-gray-600">Query raw session data with field projection. Select specific fields to reduce response size for bulk analysis.</td>
</tr>
<tr>
<td className="py-2 pr-4 font-mono text-xs text-gray-700">get_resource</td>
<td className="py-2 text-gray-600">Returns a named discovery catalog (<code className="bg-gray-100 px-1 rounded text-xs">event_types</code> or <code className="bg-gray-100 px-1 rounded text-xs">device_properties</code>) for clients that cannot read MCP-protocol resources directly. Consult it before filtering by event type or device property.</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
{/* Resources */}
<div className="bg-white rounded-lg shadow-md p-8">
<h3 className="text-xl font-semibold text-gray-900 mb-4">Resources</h3>
<p className="text-gray-700 leading-relaxed mb-4">
The MCP server exposes two discovery resources that help the AI assistant understand available data:
</p>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div className="border border-gray-200 rounded-lg p-4">
<p className="font-mono text-sm text-blue-700 mb-1">event_types</p>
<p className="text-sm text-gray-600">
Catalog of all enrollment event type strings, organized by category (phase events, app events,
network events, device info, errors, vulnerabilities). The AI consults this before searching by event type.
</p>
</div>
<div className="border border-gray-200 rounded-lg p-4">
<p className="font-mono text-sm text-blue-700 mb-1">device_properties</p>
<p className="text-sm text-gray-600">
Searchable device property keys using dot notation (e.g.{" "}
<code className="bg-gray-100 px-1 rounded text-xs">tpm_status.specVersion</code>,{" "}
<code className="bg-gray-100 px-1 rounded text-xs">hardware_spec.ramTotalGB</code>).
Covers TPM, Secure Boot, BitLocker, Autopilot profile, hardware specs, network, and AAD join status.
</p>
</div>
</div>
</div>
{/* Example Workflows */}
<div className="bg-white rounded-lg shadow-md p-8">
<h3 className="text-xl font-semibold text-gray-900 mb-4">Example Workflows</h3>
<p className="text-gray-700 leading-relaxed mb-6">
Here are some examples of what you can ask your AI assistant once connected. The AI will automatically
select the right tools and chain multiple queries together to answer your question.
</p>
<div className="space-y-4">
<ExampleWorkflow
prompt="Show me all failed enrollments from the last 24 hours"
description="Uses search_sessions with status=Failed and startedAfter filter. Returns device names, failure reasons, and session IDs for further investigation."
tools={["search_sessions"]}
/>
<ExampleWorkflow
prompt="Which devices are affected by CVE-2024-30078?"
description="Uses search_sessions_by_cve to find sessions where the vulnerability was detected. Shows affected device details and enrollment status."
tools={["search_sessions_by_cve"]}
/>
<ExampleWorkflow
prompt="Summarize session abc-123 and suggest fixes"
description="Uses get_session_summary for a concise overview with filtered key events, then includes rule analysis results with probable causes and remediation steps."
tools={["get_session_summary"]}
/>
<ExampleWorkflow
prompt="Compare enrollment performance between Germany and the US"
description="Uses get_geographic_metrics to retrieve per-country stats, then compares failure rates, average durations, and session counts across locations."
tools={["get_geographic_metrics"]}
/>
<ExampleWorkflow
prompt="Which apps cause the most timeouts during enrollment?"
description="Uses get_metrics to retrieve the slowest and most-failing apps, ranked by failure count and average install duration."
tools={["get_metrics"]}
/>
<ExampleWorkflow
prompt="Show me the event timeline for device DESKTOP-ABC123"
description="First uses search_sessions to find the session by device name, then get_session_events to retrieve the full event timeline with severity filtering."
tools={["search_sessions", "get_session_events"]}
/>
<ExampleWorkflow
prompt="Find enrollments with BitLocker issues"
description="Uses search_events with a natural language query to find sessions mentioning BitLocker errors, or search_sessions with deviceProperties filter on bitlocker_status."
tools={["search_events", "search_sessions"]}
/>
<ExampleWorkflow
prompt="How has the failure rate changed this week?"
description="Uses get_metrics with a 7-day window to show current failure rates, then compares with 30-day metrics to identify trends."
tools={["get_metrics"]}
/>
</div>
</div>
{/* Rate Limits */}
<div className="bg-white rounded-lg shadow-md p-8">
<h3 className="text-xl font-semibold text-gray-900 mb-4">Rate Limits</h3>
<p className="text-gray-700 leading-relaxed mb-4">
MCP requests are rate-limited per user to ensure fair usage. The limit is <strong>60 requests per minute</strong>,
enforced as a sliding 60-second window per signed-in user.
</p>
<div className="bg-amber-50 border border-amber-200 rounded-lg p-4">
<p className="text-sm text-amber-800">
If you hit the limit, the server returns HTTP 429 with <code className="bg-amber-100 px-1 rounded text-xs">retryAfterSeconds: 60</code>.
Your AI client will typically retry automatically once the window clears.
</p>
</div>
</div>
</section>
);
}
function ExampleWorkflow({ prompt, description, tools }: { prompt: string; description: string; tools: string[] }) {
return (
<div className="border border-gray-200 rounded-lg p-4 hover:border-blue-200 transition-colors">
<p className="font-medium text-gray-900 mb-1">&quot;{prompt}&quot;</p>
<p className="text-sm text-gray-600 mb-2">{description}</p>
<div className="flex flex-wrap gap-1.5">
{tools.map((tool) => (
<span key={tool} className="inline-flex items-center px-2 py-0.5 rounded text-xs font-mono bg-blue-50 text-blue-700 border border-blue-100">
{tool}
</span>
))}
</div>
</div>
);
}
@@ -1,142 +0,0 @@
import Link from "next/link";
export function SectionOverview() {
return (
<section className="bg-white rounded-lg shadow-md p-8">
<div className="flex items-center space-x-3 mb-4">
<svg className="w-8 h-8 text-blue-600 shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" />
</svg>
<h2 className="text-2xl font-bold text-gray-900">Overview</h2>
</div>
<p className="text-gray-700 leading-relaxed mb-6">
<strong>Autopilot Monitor</strong> provides real-time visibility into Windows Autopilot enrollment sessions.
A lightweight agent is deployed to devices via Intune and runs only during the enrollment process, streaming
events to the portal as they happen. You can watch enrollments progress phase by phase, see exactly where
failures occur, and review the full event history of any past session.
</p>
{/* Feature highlights */}
<div className="grid grid-cols-1 sm:grid-cols-3 gap-4 mb-8">
<div className="bg-blue-50 rounded-lg p-4">
<p className="font-semibold text-blue-900 mb-1">Live Sessions</p>
<p className="text-sm text-blue-800">Watch Autopilot enrollments unfold phase by phase, in real time.</p>
</div>
<div className="bg-indigo-50 rounded-lg p-4">
<p className="font-semibold text-indigo-900 mb-1">Diagnostics</p>
<p className="text-sm text-indigo-800">Full event timeline, app install details, and failure reasons for every session.</p>
</div>
<div className="bg-violet-50 rounded-lg p-4">
<p className="font-semibold text-violet-900 mb-1">Gather &amp; Analyze Rules</p>
<p className="text-sm text-violet-800">Run custom diagnostic commands on demand and automatically flag known failure patterns.</p>
</div>
</div>
{/* Getting started navigation */}
<div className="border-t border-gray-100 pt-6 mb-8">
<h3 className="text-lg font-semibold text-gray-900 mb-4">Where to go next</h3>
<div className="grid grid-cols-1 sm:grid-cols-2 gap-3">
<Link href="/docs/setup" className="group flex items-start gap-3 rounded-lg border border-gray-200 p-4 hover:border-blue-300 hover:bg-blue-50 transition-colors">
<svg className="w-5 h-5 text-blue-500 shrink-0 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z" />
</svg>
<div>
<p className="font-medium text-gray-900 group-hover:text-blue-700 text-sm">Setup</p>
<p className="text-xs text-gray-500 mt-0.5">First-time setup: tenant registration, certificates, and configuration.</p>
</div>
</Link>
<Link href="/docs/agent-setup" className="group flex items-start gap-3 rounded-lg border border-gray-200 p-4 hover:border-blue-300 hover:bg-blue-50 transition-colors">
<svg className="w-5 h-5 text-blue-500 shrink-0 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M13 10V3L4 14h7v7l9-11h-7z" />
</svg>
<div>
<p className="font-medium text-gray-900 group-hover:text-blue-700 text-sm">Agent Setup</p>
<p className="text-xs text-gray-500 mt-0.5">Deploy the agent to devices via Intune — step-by-step guide.</p>
</div>
</Link>
<Link href="/docs/agent" className="group flex items-start gap-3 rounded-lg border border-gray-200 p-4 hover:border-blue-300 hover:bg-blue-50 transition-colors">
<svg className="w-5 h-5 text-blue-500 shrink-0 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9.75 17L9 20l-1 1h8l-1-1-.75-3M3 13h18M5 17h14a2 2 0 002-2V5a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z" />
</svg>
<div>
<p className="font-medium text-gray-900 group-hover:text-blue-700 text-sm">Agent</p>
<p className="text-xs text-gray-500 mt-0.5">What the agent collects, how it works, and version details.</p>
</div>
</Link>
<Link href="/docs/settings" className="group flex items-start gap-3 rounded-lg border border-gray-200 p-4 hover:border-blue-300 hover:bg-blue-50 transition-colors">
<svg className="w-5 h-5 text-blue-500 shrink-0 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z" />
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
</svg>
<div>
<p className="font-medium text-gray-900 group-hover:text-blue-700 text-sm">Settings</p>
<p className="text-xs text-gray-500 mt-0.5">Tenant configuration, diagnostics, notifications, and data retention.</p>
</div>
</Link>
<Link href="/docs/gather-rules" className="group flex items-start gap-3 rounded-lg border border-gray-200 p-4 hover:border-blue-300 hover:bg-blue-50 transition-colors">
<svg className="w-5 h-5 text-blue-500 shrink-0 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2" />
</svg>
<div>
<p className="font-medium text-gray-900 group-hover:text-blue-700 text-sm">Gather Rules</p>
<p className="text-xs text-gray-500 mt-0.5">Run custom diagnostic commands on devices and collect output centrally.</p>
</div>
</Link>
<Link href="/docs/analyze-rules" className="group flex items-start gap-3 rounded-lg border border-gray-200 p-4 hover:border-blue-300 hover:bg-blue-50 transition-colors">
<svg className="w-5 h-5 text-blue-500 shrink-0 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9.663 17h4.673M12 3v1m6.364 1.636l-.707.707M21 12h-1M4 12H3m3.343-5.657l-.707-.707m2.828 9.9a5 5 0 117.072 0l-.548.547A3.374 3.374 0 0014 18.469V19a2 2 0 11-4 0v-.531c0-.895-.356-1.754-.988-2.386l-.548-.547z" />
</svg>
<div>
<p className="font-medium text-gray-900 group-hover:text-blue-700 text-sm">Analyze Rules</p>
<p className="text-xs text-gray-500 mt-0.5">Automatically flag failure patterns and misconfigurations in enrollment sessions.</p>
</div>
</Link>
</div>
</div>
{/* Community Analyze Rules */}
<div className="border-t border-gray-100 pt-6">
<h3 className="text-lg font-semibold text-gray-900 mb-3 flex items-center gap-2">
<svg className="w-5 h-5 text-amber-500 shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0zm6 3a2 2 0 11-4 0 2 2 0 014 0zM7 10a2 2 0 11-4 0 2 2 0 014 0z" />
</svg>
The real value: community-driven Analyze Rules
</h3>
<p className="text-gray-700 leading-relaxed mb-4">
Raw event data is useful — but the true power of Autopilot Monitor lies in its <strong>Analyze Rules</strong>.
These are configurable rules that run automatically against every enrollment session and flag known failure
patterns, misconfigurations, or anomalies with a clear description and suggested fix. The more rules exist,
the more reliable and actionable the analysis becomes.
</p>
<p className="text-gray-700 leading-relaxed mb-4">
No single person or team can anticipate every failure mode across all the different environments, hardware
combinations, and Intune configurations out there. That&apos;s where <strong>collective intelligence</strong> comes in:
every admin who has solved a tricky Autopilot failure has knowledge that could save hours of troubleshooting
for someone else — if it were captured as a rule.
</p>
<div className="bg-amber-50 border border-amber-200 rounded-lg p-4 text-sm text-amber-900">
<p className="font-semibold mb-2">You&apos;re invited to contribute</p>
<p className="mb-2">
If you&apos;ve encountered a failure pattern, found a reliable signal in the event data, or have ideas for
what a useful analysis rule could look like — please share it. Rules can be built directly in the portal
under <strong>Analyze Rules</strong>, and the more the community contributes, the more the tool grows in
value for everyone over time.
</p>
<p>
Even if you can&apos;t write a rule yourself, sharing hints, failure descriptions, or event patterns is
enormously helpful. The goal is a library of rules that covers as much ground as possible — built by the
people who work with Autopilot every day.
</p>
</div>
</div>
</section>
);
}
@@ -1,104 +0,0 @@
export function SectionPrivatePreview() {
return (
<section className="bg-white rounded-lg shadow-md p-8">
<div className="flex items-center space-x-3 mb-4">
<svg className="w-8 h-8 text-amber-500 shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
<h2 className="text-2xl font-bold text-gray-900">Private Preview</h2>
</div>
<p className="text-gray-700 leading-relaxed mb-6">
Autopilot Monitor is currently in <strong>Private Preview</strong>. The service is available to a limited number
of organizations while the core functionality is being refined and stabilized. Access is invite-only and managed
manually on a per-tenant basis.
</p>
{/* Warning banner */}
<div className="mb-6 p-4 bg-red-50 border border-red-200 rounded-lg text-sm text-red-900">
<p className="font-semibold mb-1 flex items-center gap-2">
<svg className="w-4 h-4 shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 9v2m0 4h.01M10.29 3.86L1.82 18a2 2 0 001.71 3h16.94a2 2 0 001.71-3L13.71 3.86a2 2 0 00-3.42 0z" />
</svg>
Expect instability during Private Preview
</p>
<ul className="space-y-1 ml-1">
<li className="flex items-start gap-2">
<span className="shrink-0 mt-0.5">•</span>
<span>Things <strong>can and will break</strong>. The backend, web frontend, and agent are all under active development and receive frequent updates.</span>
</li>
<li className="flex items-start gap-2">
<span className="shrink-0 mt-0.5">•</span>
<span><strong>Availability is not guaranteed.</strong> Deployments and maintenance may cause downtime without prior notice.</span>
</li>
<li className="flex items-start gap-2">
<span className="shrink-0 mt-0.5">•</span>
<span>Features, APIs, and data structures may change at any time. Existing session data may be cleared between major updates.</span>
</li>
</ul>
<p className="mt-2 text-red-800">
This preview is intended for testing and feedback — not for production use in critical environments.
</p>
</div>
{/* How to get access */}
<div className="mb-8">
<h3 className="text-lg font-semibold text-gray-900 mb-3">How to request access</h3>
<p className="text-gray-700 leading-relaxed mb-4">
To get started, sign in with your Microsoft Entra ID account on the Autopilot Monitor portal. If your
organization has not yet been granted access, you will see a <strong>Private Preview</strong> screen
(see below) confirming that your tenant has been placed on the waitlist. Once you are on the waitlist,
reach out via LinkedIn or open a GitHub issue to request activation — your tenant is then enabled manually
in the backend. I'll check incoming requests regularly and approve them as quickly as possible, depending
on my capacity. When you signed-up, sign in again later to view the updated approval status on your dashboard.
</p>
<div className="flex flex-wrap gap-3 mb-6">
<a
href="https://www.linkedin.com/in/oliver-kieselbach"
target="_blank"
rel="noopener noreferrer"
className="inline-flex items-center gap-2 px-4 py-2 bg-blue-700 hover:bg-blue-800 text-white text-sm font-medium rounded-lg transition-colors"
>
<svg className="w-4 h-4" fill="currentColor" viewBox="0 0 24 24">
<path d="M19 0h-14c-2.761 0-5 2.239-5 5v14c0 2.761 2.239 5 5 5h14c2.762 0 5-2.239 5-5v-14c0-2.761-2.238-5-5-5zm-11 19h-3v-11h3v11zm-1.5-12.268c-.966 0-1.75-.79-1.75-1.764s.784-1.764 1.75-1.764 1.75.79 1.75 1.764-.783 1.764-1.75 1.764zm13.5 12.268h-3v-5.604c0-3.368-4-3.113-4 0v5.604h-3v-11h3v1.765c1.396-2.586 7-2.777 7 2.476v6.759z" />
</svg>
Contact on LinkedIn
</a>
<a
href="https://github.com/okieselbach/autopilot-monitor/issues"
target="_blank"
rel="noopener noreferrer"
className="inline-flex items-center gap-2 px-4 py-2 bg-gray-800 hover:bg-gray-900 text-white text-sm font-medium rounded-lg transition-colors"
>
<svg className="w-4 h-4" fill="currentColor" viewBox="0 0 24 24">
<path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z" />
</svg>
Open a GitHub Issue
</a>
</div>
{/* Screenshot */}
<div className="rounded-lg overflow-hidden border border-gray-200 shadow-sm max-w-sm">
<img
src="/private-preview.png"
alt="Private Preview waitlist screen"
className="w-full"
/>
</div>
<p className="text-xs text-gray-500 mt-2">
The Private Preview screen you will see when your tenant is on the waitlist.
</p>
</div>
{/* After approval */}
<div className="p-4 bg-green-50 border border-green-200 rounded-lg text-sm text-green-900">
<p className="font-semibold mb-1">After your tenant is approved</p>
<p>
Once access is granted, you can sign back in and will be taken directly to the portal. Continue with
the <strong>Setup</strong> and <strong>Agent Setup</strong> sections of this documentation to get
your first Autopilot enrollment sessions flowing in.
</p>
</div>
</section>
);
}
@@ -1,402 +0,0 @@
"use client";
import React, { useState } from "react";
function SettingsGroup({ title, color, borderColor, children }: { title: string; color: string; borderColor: string; children: React.ReactNode }) {
return (
<div className={`border ${borderColor} rounded-lg overflow-hidden mb-6`}>
<div className={`px-4 py-2.5 ${color}`}>
<p className="font-semibold text-sm">{title}</p>
</div>
<div className="divide-y divide-gray-100 bg-white">
{children}
</div>
</div>
);
}
function SettingsRow({ name, defaultVal, children }: { name: string; defaultVal?: string; children: React.ReactNode }) {
return (
<div className="px-4 py-3 grid grid-cols-1 sm:grid-cols-3 gap-1 sm:gap-4 text-sm bg-white">
<div className="sm:col-span-1">
<p className="font-medium text-gray-900">{name}</p>
{defaultVal && <p className="text-xs text-gray-500 mt-0.5">Default: {defaultVal}</p>}
</div>
<div className="sm:col-span-2 text-gray-600 leading-relaxed">{children}</div>
</div>
);
}
export function SectionSettings() {
const [showDiagGuards, setShowDiagGuards] = useState(false);
return (
<section className="bg-white rounded-lg shadow-md p-8">
<div className="flex items-center space-x-3 mb-4">
<svg className="w-8 h-8 text-blue-600 shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z" />
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
</svg>
<h2 className="text-2xl font-bold text-gray-900">Settings Reference</h2>
</div>
<p className="text-gray-700 leading-relaxed mb-8">
The <strong>Settings</strong> page (accessible to Tenant Admins) controls all aspects of how Autopilot Monitor
behaves for your tenant — from security and device filtering, to agent behavior, notifications, and data retention.
Below is a reference for every available option.
</p>
{/* ═══════════════════════════════════════════════════════
TENANT GROUP
═══════════════════════════════════════════════════════ */}
{/* Access Management */}
<SettingsGroup title="Access Management" color="bg-gray-100 text-gray-800" borderColor="border-gray-200">
<SettingsRow name="Team Members &amp; Roles">
Manage who has access to the portal and at what level. New members are added by entering their UPN
(e.g. <span className="font-mono text-xs bg-gray-100 px-1 py-0.5 rounded">user@contoso.com</span>).
The first user to sign in for a tenant is automatically granted Admin rights. Each member is assigned
one of three roles:
<ul className="mt-2 space-y-1 list-disc list-inside text-sm">
<li><strong>Admin</strong> — Full access to all tenant configuration, sessions, diagnostics, and settings.</li>
<li><strong>Operator</strong> — Can view sessions, manage settings, and execute actions on devices.</li>
</ul>
<span className="block mt-2 text-xs text-gray-500">
Admins can enable or disable individual members, update roles, and grant bootstrap token management permissions.
</span>
</SettingsRow>
</SettingsGroup>
{/* Enrollment Device Validation */}
<SettingsGroup title="Enrollment Device Validation" color="bg-purple-50 text-purple-900" borderColor="border-purple-200">
<SettingsRow name="Autopilot Device Validation" defaultVal="Disabled">
Validates that only devices registered in your Intune tenant as Windows Autopilot devices can register sessions.
When enabled, the backend checks each incoming agent request against the Intune Autopilot device list — unauthorized
devices are rejected. Enabling this setting requires granting admin consent for the{" "}
<span className="font-mono text-xs bg-gray-100 px-1.5 py-0.5 rounded">DeviceManagementServiceConfig.Read.All</span>{" "}
Microsoft Graph permission.
</SettingsRow>
<SettingsRow name="Corporate Identifier Validation" defaultVal="Disabled">
Validates devices against Intune Corporate Device Identifiers (manufacturer, model, and serial number).
When enabled, the backend checks each incoming agent request against the corporate identifier list in Intune.
Uses the same{" "}
<span className="font-mono text-xs bg-gray-100 px-1.5 py-0.5 rounded">DeviceManagementServiceConfig.Read.All</span>{" "}
permission as Autopilot Device Validation. At least one validation method must be enabled — disabling all causes the
backend to reject all agent requests.
</SettingsRow>
</SettingsGroup>
{/* Hardware Whitelist */}
<SettingsGroup title="Hardware Whitelist" color="bg-sky-50 text-sky-900" borderColor="border-sky-200">
<SettingsRow name="Allowed Manufacturers" defaultVal="Dell*, HP*, Lenovo*, Microsoft Corporation">
Comma-separated list of manufacturer names that are permitted to register sessions. Wildcards (<span className="font-mono text-xs bg-gray-100 px-1 py-0.5 rounded">*</span>) are
supported — e.g. <span className="font-mono text-xs bg-gray-100 px-1 py-0.5 rounded">Dell*</span> matches any string starting with &quot;Dell&quot;.
Devices with a manufacturer not on this list will have their session registration rejected by the backend.
Set to <span className="font-mono text-xs bg-gray-100 px-1 py-0.5 rounded">*</span> to allow all manufacturers.
</SettingsRow>
<SettingsRow name="Allowed Models" defaultVal="* (all models)">
Comma-separated list of device model names to allow. Works the same as the manufacturer filter with wildcard support.
Use this to restrict telemetry to specific hardware lines, e.g. <span className="font-mono text-xs bg-gray-100 px-1 py-0.5 rounded">Latitude*,EliteBook*</span>.
</SettingsRow>
</SettingsGroup>
{/* Notifications */}
<SettingsGroup title="Notifications" color="bg-indigo-50 text-indigo-900" borderColor="border-indigo-200">
<SettingsRow name="Notification Provider">
Select how you want to receive enrollment notifications. Available providers:
<ul className="list-disc ml-6 mt-1 space-y-1">
<li>
<strong>Microsoft Teams (Workflow Webhook)</strong> <span className="text-green-700 text-xs font-medium">(Recommended)</span> &mdash;
In Teams, go to the target channel &rarr; <em>Manage channel</em> &rarr; <em>Workflows</em> &rarr;
add <em>&quot;Post to a channel when a webhook request is received&quot;</em> &rarr; copy the generated URL.
Workflow webhooks are free and do not require a Power Automate Premium license.
</li>
<li>
<strong>Microsoft Teams (Legacy Connector)</strong> <span className="text-amber-700 text-xs font-medium">(Deprecated)</span> &mdash;
Uses the legacy Office 365 Connector webhook format (MessageCard). Microsoft has deprecated this method.
Existing configurations will continue to work, but switching to Workflow Webhooks is recommended.
</li>
<li>
<strong>Slack</strong> &mdash;
In Slack, go to your workspace &rarr; <em>Apps</em> &rarr; <em>Incoming Webhooks</em> &rarr;
create a new webhook for the target channel &rarr; copy the webhook URL.
</li>
</ul>
</SettingsRow>
<SettingsRow name="Webhook URL">
The webhook URL for your selected notification provider. Paste the URL generated during the provider setup.
</SettingsRow>
<SettingsRow name="Notify on Success" defaultVal="Enabled (if webhook configured)">
Send a notification when an enrollment session completes successfully.
</SettingsRow>
<SettingsRow name="Notify on Failure" defaultVal="Enabled (if webhook configured)">
Send a notification when an enrollment session ends in failure. Recommended to keep enabled so
failed enrollments are surfaced immediately without having to check the portal manually.
</SettingsRow>
<SettingsRow name="Send Test Notification">
Sends a sample notification to your configured webhook to verify the connection is working correctly.
</SettingsRow>
</SettingsGroup>
{/* Bootstrap Sessions */}
<div className="mb-2 flex items-start gap-2 rounded-md border border-cyan-300 bg-cyan-50 px-4 py-2.5 text-sm text-cyan-900">
<svg className="mt-0.5 h-5 w-5 shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M13 16h-1v-4h-1m1-4h.01M12 2a10 10 0 100 20 10 10 0 000-20z" />
</svg>
<span>
Bootstrap Sessions is an optional feature that is enabled on request only.
To get access, open a{" "}
<a href="https://github.com/okieselbach/Autopilot-Monitor/issues" target="_blank" rel="noopener noreferrer" className="font-medium underline hover:text-cyan-700">
GitHub issue
</a>{" "}
to request activation for your tenant.
</span>
</div>
<SettingsGroup title="Bootstrap Sessions" color="bg-cyan-50 text-cyan-900" borderColor="border-cyan-200">
<SettingsRow name="Bootstrap Tokens">
Bootstrap tokens allow new devices to register with Autopilot Monitor before device validation is fully
configured. Each token generates a unique short code and URL that can be shared with technicians or
included in provisioning scripts. Tokens have a configurable validity duration
(1 h, 4 h, 8 h, 24 h, 48 h, or 7 days) and can be revoked at any time. The token list shows status
(Active, Expired, Revoked), creation date, expiry, creator, and usage count. A copy button provides
both the URL and a ready-to-use PowerShell command.
</SettingsRow>
</SettingsGroup>
{/* ═══════════════════════════════════════════════════════
AGENT GROUP
═══════════════════════════════════════════════════════ */}
{/* Agent Parameters */}
<SettingsGroup title="Agent Parameters" color="bg-violet-50 text-violet-900" borderColor="border-violet-200">
<SettingsRow name="Self-Destruct on Complete" defaultVal="Enabled">
After enrollment finishes, the agent removes its scheduled task and all agent files from the device.
This is the recommended mode — the agent is temporary by design and should not remain on enrolled devices.
</SettingsRow>
<SettingsRow name="Keep Log File" defaultVal="Disabled">
Only available when Self-Destruct is enabled. If turned on, the agent&apos;s local log file is preserved on
the device even after self-destruct. Useful for troubleshooting when you need a local record of what happened.
</SettingsRow>
<SettingsRow name="Reboot on Complete" defaultVal="Disabled">
Triggers an automatic reboot of the device once the Autopilot enrollment is detected as complete.
When enabled, a configurable <strong>Reboot Delay</strong> (0–3600 seconds, default 10 s) gives the user
a brief window to see the result before the reboot happens.
</SettingsRow>
<SettingsRow name="Geo-Location Detection" defaultVal="Enabled">
The agent queries an external IP geolocation service to capture the device&apos;s public IP address,
approximate location, and ISP at enrollment time. This data appears in the session detail view and can
help identify where devices are being enrolled. Disable this if your security policy prohibits outbound
requests to third-party services.
</SettingsRow>
<SettingsRow name="Set Timezone Automatically" defaultVal="Disabled">
Only available when Geo-Location Detection is enabled. Automatically sets the device timezone based on
the IP geolocation result using <span className="font-mono text-xs bg-gray-100 px-1.5 py-0.5 rounded">tzutil /s</span>.
Useful for shared device scenarios where devices may be enrolled in different time zones.
</SettingsRow>
<SettingsRow name="IME Pattern Match Log" defaultVal="Disabled">
When enabled, the agent writes matched Intune Management Extension (IME) log lines to a local file at{" "}
<span className="font-mono text-xs bg-gray-100 px-1 py-0.5 rounded">%ProgramData%\AutopilotMonitor\Logs\ime_pattern_matches.log</span>.
Useful for offline analysis of app deployment patterns captured during enrollment.
</SettingsRow>
<SettingsRow name="Show Script Output (stdout)" defaultVal="Enabled">
When enabled, standard output from PowerShell scripts (platform and remediation scripts tracked by IME) is
shown in the session timeline. Disable this if scripts may output sensitive data. Note: error output (stderr)
is always shown regardless of this setting.
</SettingsRow>
<SettingsRow name="Log Level" defaultVal="Info">
Controls the verbosity of the agent&apos;s own log file.{" "}
<strong>Info</strong> covers normal operation, <strong>Debug</strong> adds detailed step tracing for
troubleshooting, <strong>Verbose</strong> produces a full trace of every internal operation, and{" "}
<strong>Trace</strong> enables full diagnostic output including low-level details.
Only change this if actively diagnosing an agent issue — Verbose and Trace can produce large log files.
</SettingsRow>
<SettingsRow name="Show Enrollment Summary" defaultVal="Disabled">
Displays a visual enrollment summary dialog to the end user after enrollment completes (on both success and failure).
Requires the SummaryDialog companion to be deployed alongside the agent. When enabled, the following
sub-settings become available:
</SettingsRow>
<SettingsRow name="Auto-Close Timeout" defaultVal="60 seconds">
How long the summary dialog remains open before closing automatically (range: 0–3600 seconds).
Set to 0 to disable auto-close — the user must close the dialog manually. Only available when
Show Enrollment Summary is enabled.
</SettingsRow>
<SettingsRow name="Launch Retry Timeout" defaultVal="120 seconds">
How long the agent retries launching the summary dialog when the desktop is locked by credential UI
(e.g. Windows Hello setup). Set to 0 to disable retries (range: 0–3600 seconds). Only available when
Show Enrollment Summary is enabled.
</SettingsRow>
<SettingsRow name="Branding Image URL" defaultVal="None">
Optional URL to a banner image displayed at the top of the summary dialog. Recommended size: 540 &times; 80 px.
Larger images will be center-cropped to fit. Only available when Show Enrollment Summary is enabled.
</SettingsRow>
</SettingsGroup>
{/* Agent Collectors */}
<SettingsGroup title="Agent Collectors" color="bg-emerald-50 text-emerald-900" borderColor="border-emerald-200">
<SettingsRow name="Performance Collector" defaultVal="Enabled, 30 s interval">
When enabled, the agent periodically collects CPU, memory, disk, and network metrics during enrollment and
streams them to the portal. The interval (30–300 seconds) controls how often samples are taken. Disabling
this reduces network traffic but removes the performance timeline from session diagnostics.
Core collectors (enrollment event tracking, Windows Hello detector) are always active and cannot be disabled.
</SettingsRow>
<SettingsRow name="Hello Wait Timeout" defaultVal="30 seconds">
How long the agent waits for the Windows Hello wizard to appear after ESP exit (range: 30–300 seconds).
If Hello does not appear within this window, the agent proceeds with enrollment completion. Increase this
value if your devices consistently take longer to reach the Hello screen.
</SettingsRow>
</SettingsGroup>
{/* Agent Analyzers */}
<SettingsGroup title="Agent Analyzers" color="bg-orange-50 text-orange-900" borderColor="border-orange-200">
<SettingsRow name="Local Admin Analyzer" defaultVal="Enabled">
Detects pre-enrollment local admin account creation — a known Autopilot bypass technique. The analyzer
runs at enrollment start and completion, comparing local accounts against an expected baseline.
Unexpected accounts trigger an alert visible in the session detail view.
</SettingsRow>
<SettingsRow name="Allowed Local Accounts">
Accounts considered expected on enrolled devices (will not trigger alerts). Built-in Windows accounts
(Administrator, Guest, DefaultAccount, WDAGUtilityAccount, defaultuser0–2, etc.) are always allowed and
shown as read-only. Use this list to add custom service accounts or local accounts that are expected
in your environment. Only available when Local Admin Analyzer is enabled.
</SettingsRow>
<SettingsRow name="Software Inventory &amp; Vulnerability Analyzer" defaultVal="Disabled">
<span className="inline-flex items-center px-1.5 py-0.5 rounded text-xs font-semibold bg-emerald-100 text-emerald-700 border border-emerald-200 mr-1">Experimental</span>
<span className="inline-flex items-center px-1.5 py-0.5 rounded text-xs font-semibold bg-amber-100 text-amber-700 border border-amber-200 mr-1">Pre-Release</span>
{" "}Collects installed software from the Windows registry at enrollment start and completion.
Produces a normalized inventory snapshot, detects software installed during enrollment (delta detection),
and correlates findings against known vulnerabilities (NVD CVEs, CISA KEV, MSRC).
</SettingsRow>
</SettingsGroup>
{/* Diagnostics Package */}
<SettingsGroup title="Diagnostics Package" color="bg-amber-50 text-amber-900" borderColor="border-amber-200">
<SettingsRow name="Upload destination" defaultVal="Your own Azure Blob Storage">
Where diagnostics packages are uploaded:{" "}
<strong>Your own Azure Blob Storage</strong> (default) — agents upload to a container in your tenant via a Container SAS URL you provide; data never leaves your Azure tenant.{" "}
<strong>Hosted storage</strong> (opt-in) — agents upload to the AutopilotMonitor backend's Azure Storage under a per-tenant prefix, using short-lived (15 min), blob-scoped, write-only tokens minted per upload. No long-lived credentials are stored. Switching destinations requires an explicit admin click and a Save — never silent.
</SettingsRow>
<SettingsRow name="Blob Storage Container SAS URL">
Used only when the destination is <strong>Your own Azure Blob Storage</strong>. An Azure Blob Storage Container SAS URL used for diagnostics package uploads. The SAS URL must grant
at minimum <strong>Read</strong>, <strong>Write</strong>, and <strong>Create</strong> permissions at the
container level. The SAS URL is stored securely in the backend and never sent to devices — the agent
requests a short-lived upload URL from the backend just before uploading. The portal shows an expiry
indicator (green, amber, or red) based on the remaining validity of the SAS URL.
</SettingsRow>
<SettingsRow name="Upload Mode" defaultVal="Off">
Controls when diagnostics packages are uploaded:{" "}
<strong>Off</strong> — never upload,{" "}
<strong>Always</strong> — upload after every session,{" "}
<strong>On Failure Only</strong> — upload only when the session ends in failure (recommended if storage costs
are a concern). For the customer-SAS destination, a SAS URL must be configured before Upload Mode can be enabled.
</SettingsRow>
<SettingsRow name="Additional Log Paths">
<span>
Extra log files or wildcard patterns added to the diagnostics ZIP package. Global paths are defined
platform-wide by the Global Admin and always included. Tenant Admins can add their own paths in addition
to the global ones (e.g. custom app logs or third-party agent logs).
</span>
<span className="block mt-2 text-xs text-gray-500">
Environment variables (e.g. <span className="font-mono bg-gray-100 px-1 rounded">%ProgramData%</span>) are expanded by the agent.
Wildcards are only supported in the <strong>last path segment</strong> (e.g.{" "}
<span className="font-mono bg-gray-100 px-1 rounded">C:\Windows\Panther\*.log</span>).
</span>
<span className="block mt-2 text-xs text-gray-500">
To collect logs from the logged-on user&apos;s profile, use the{" "}
<span className="font-mono bg-gray-100 px-1 rounded">%LOGGED_ON_USER_PROFILE%</span> token.
Only <span className="font-mono bg-gray-100 px-1 rounded">AppData\Local</span> and{" "}
<span className="font-mono bg-gray-100 px-1 rounded">AppData\Roaming</span> subdirectories are allowed.
Example: <span className="font-mono bg-gray-100 px-1 rounded">%LOGGED_ON_USER_PROFILE%\AppData\Local\RealmJoin\Logs\*.log</span>.
During SYSTEM-context phases (before user logon), paths with this token are skipped automatically.
</span>
<span className="block mt-2 text-xs text-gray-500">
Enable <strong>Include Subfolders</strong> to recursively collect matching log files from all subdirectories.
The subfolder structure is preserved in the diagnostics ZIP package.
</span>
<span className="block mt-2">
<button
onClick={() => setShowDiagGuards(v => !v)}
className="flex items-center gap-1 text-xs text-gray-500 hover:text-gray-700 select-none"
>
<span>{showDiagGuards ? "▾" : "▸"}</span>
<span>Allowed path prefixes (agent guard)</span>
</button>
{showDiagGuards && (
<div className="mt-1 bg-gray-50 border border-gray-200 rounded px-3 py-2 text-xs font-mono space-y-0.5">
<p>C:\ProgramData\AutopilotMonitor</p>
<p>C:\ProgramData\Microsoft\IntuneManagementExtension\Logs</p>
<p>C:\Windows\Panther</p>
<p>C:\Windows\Logs</p>
<p>C:\Windows\SetupDiag</p>
<p>C:\Windows\SoftwareDistribution\ReportingEvents.log</p>
<p>C:\Windows\System32\winevt\Logs</p>
<p>C:\Windows\CCM\Logs</p>
<p>C:\ProgramData\Microsoft\DiagnosticLogCSP</p>
<p>C:\ProgramData\Microsoft\Windows\WER</p>
<p>C:\Windows\Logs\CBS</p>
<p>C:\Install\Log</p>
</div>
)}
</span>
</SettingsRow>
</SettingsGroup>
{/* Unrestricted Mode */}
<div className="mb-2 flex items-start gap-2 rounded-md border border-amber-300 bg-amber-50 px-4 py-2.5 text-sm text-amber-900">
<svg className="mt-0.5 h-5 w-5 shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M13 16h-1v-4h-1m1-4h.01M12 2a10 10 0 100 20 10 10 0 000-20z" />
</svg>
<span>
Unrestricted Mode is an optional feature that is enabled on request only.
To get access, open a{" "}
<a href="https://github.com/okieselbach/Autopilot-Monitor/issues" target="_blank" rel="noopener noreferrer" className="font-medium underline hover:text-amber-700">
GitHub issue
</a>{" "}
to request activation for your tenant.
</span>
</div>
<SettingsGroup title="Unrestricted Mode" color="bg-amber-50 text-amber-900" borderColor="border-amber-200">
<SettingsRow name="Unrestricted Mode">
When enabled, agent guardrails are relaxed: GatherRules can access any registry path, WMI query,
and PowerShell/system command. File and diagnostics paths are allowed except C:\Users (always blocked
for privacy). Certain dangerous operations (downloads, user creation, boot manipulation, persistence
mechanisms) remain hard-blocked even in Unrestricted Mode. This feature requires explicit activation
by the platform administrator before it becomes visible in tenant settings.
</SettingsRow>
</SettingsGroup>
{/* ═══════════════════════════════════════════════════════
MAINTENANCE GROUP
═══════════════════════════════════════════════════════ */}
{/* Data Management */}
<SettingsGroup title="Data Management" color="bg-rose-50 text-rose-900" borderColor="border-rose-200">
<SettingsRow name="Data Retention Period" defaultVal="90 days (range: 7–180)">
Sessions and their associated events are automatically deleted after this many days. Deletion runs as part
of a periodic maintenance job. Reduce this value to limit storage usage; increase it if you need a longer
history for auditing or trend analysis.
</SettingsRow>
<SettingsRow name="Session Timeout" defaultVal="5 hours (range: 1–12)">
Sessions that remain in <em>In Progress</em> state beyond this threshold are automatically marked as{" "}
<em>Failed – Timed Out</em> by the maintenance job. Set this to match (or slightly exceed) your
Enrollment Status Page (ESP) timeout so stalled sessions don&apos;t permanently inflate your in-progress count.
</SettingsRow>
</SettingsGroup>
{/* Danger Zone */}
<div className="border border-red-200 rounded-lg overflow-hidden">
<div className="px-4 py-2.5 bg-red-50 text-red-900">
<p className="font-semibold text-sm">Danger Zone</p>
</div>
<div className="px-4 py-3 text-sm text-gray-700 bg-white">
<p className="font-medium text-gray-900 mb-1">Offboard Tenant</p>
<p>
Permanently and irreversibly deletes <strong>all tenant data</strong>: sessions, events, analyze rules,
audit logs, configuration, and all admin accounts. You will be signed out immediately. This action
requires typing <span className="font-mono text-xs bg-red-50 text-red-700 px-1.5 py-0.5 rounded border border-red-200">OFFBOARD</span>{" "}
as a confirmation step and <strong>cannot be undone</strong>.
</p>
</div>
</div>
</section>
);
}
@@ -1,110 +0,0 @@
export function SectionSetup() {
return (
<section className="bg-white rounded-lg shadow-md p-8">
<div className="flex items-center space-x-3 mb-4">
<svg className="w-8 h-8 text-blue-600 shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z" />
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
</svg>
<h2 className="text-2xl font-bold text-gray-900">Setup</h2>
</div>
<p className="text-gray-700 mb-6">
Before the agent can send any data to the portal, a few one-time steps are required in the portal itself.
Follow these steps when setting up Autopilot Monitor for a new tenant.
</p>
<ol className="space-y-6">
<li className="flex gap-4">
<span className="flex-shrink-0 w-7 h-7 rounded-full bg-blue-600 text-white text-sm font-bold flex items-center justify-center">1</span>
<div className="flex-1">
<p className="font-semibold text-gray-900">Sign in — first user becomes Tenant Admin</p>
<p className="text-sm text-gray-600 mt-1">
Open the portal and sign in with your Microsoft Entra ID (Azure AD) account. The very first user to log
in for your organization is automatically granted <strong>Tenant Admin</strong> rights for your tenant.
</p>
<div className="mt-2 p-3 bg-blue-50 border border-blue-100 rounded-lg text-sm text-blue-800">
The Tenant Admin can later promote other users to admin via the <strong>Settings</strong> page.
Users who are not admins can only access the <strong>Progress</strong> portal — a simplified view
for tracking a specific device by serial number — and have no access to session details, diagnostics,
or configuration.
</div>
</div>
</li>
<li className="flex gap-4">
<span className="flex-shrink-0 w-7 h-7 rounded-full bg-blue-600 text-white text-sm font-bold flex items-center justify-center">2</span>
<div className="flex-1">
<p className="font-semibold text-gray-900">Enable Autopilot Device Validation in Configuration</p>
<p className="text-sm text-gray-600 mt-1 mb-2">
Navigate to{" "}
<span className="font-mono text-xs bg-gray-100 px-1.5 py-0.5 rounded">Settings → Configuration</span>{" "}
and enable the <strong>Autopilot Device Validation</strong> setting. This is required before the agent
is permitted to send any session data to the backend — without it, all agent uploads will be rejected.
</p>
<div className="p-3 bg-amber-50 border border-amber-200 rounded-lg text-sm text-amber-900">
<strong>Why is this required?</strong> The Autopilot device check ensures that only devices registered
in your Intune tenant can register sessions, preventing unintended data from reaching your tenant.
Consenting to this setting is your confirmation that the agent may collect and transmit enrollment
telemetry on behalf of your organization.
</div>
</div>
</li>
<li className="flex gap-4">
<span className="flex-shrink-0 w-7 h-7 rounded-full bg-green-600 text-white text-sm font-bold flex items-center justify-center">✓</span>
<div>
<p className="font-semibold text-gray-900">Ready</p>
<p className="text-sm text-gray-600 mt-1">
Once Autopilot Device Validation is enabled, the portal is ready to receive data. Deploy the agent via
Intune (see <strong>Agent Setup</strong>) and sessions will start appearing in the dashboard as soon
as devices begin enrolling.
</p>
</div>
</li>
</ol>
<div className="mt-8 p-5 bg-gradient-to-r from-indigo-50 to-blue-50 border border-indigo-100 rounded-lg">
<div className="flex items-center space-x-2 mb-3">
<svg className="w-5 h-5 text-indigo-600 shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
<p className="font-semibold text-indigo-900">Recommended Configuration</p>
</div>
<p className="text-sm text-gray-700 mb-3">
After the basic setup is complete, consider enabling these features to get the most out of Autopilot Monitor:
</p>
<ul className="space-y-3 text-sm text-gray-700">
<li className="flex gap-2">
<span className="text-indigo-500 font-bold mt-0.5">1.</span>
<div>
<strong>Agent Settings</strong> — Enable{" "}
<span className="font-mono text-xs bg-white/70 px-1.5 py-0.5 rounded">Geo Location Detection</span> and{" "}
<span className="font-mono text-xs bg-white/70 px-1.5 py-0.5 rounded">Set Timezone Automatically</span>{" "}
so that the device timezone is set correctly during enrollment — without a location sensor, Windows
defaults to Pacific Standard Time (PST).
</div>
</li>
<li className="flex gap-2">
<span className="text-indigo-500 font-bold mt-0.5">2.</span>
<div>
<strong>Agent Analyzers</strong> — Enable the{" "}
<span className="font-mono text-xs bg-white/70 px-1.5 py-0.5 rounded">Local Admin Analyzer</span> (configure
your allowed admin accounts to detect unauthorized local admins),{" "}
<span className="font-mono text-xs bg-white/70 px-1.5 py-0.5 rounded">Software Inventory</span>, and the{" "}
<span className="font-mono text-xs bg-white/70 px-1.5 py-0.5 rounded">Vulnerability Analyzer</span> for
security insights during enrollment.
</div>
</li>
<li className="flex gap-2">
<span className="text-indigo-500 font-bold mt-0.5">3.</span>
<div>
<strong>Diagnostics Package</strong> — Enable diagnostics collection to automatically gather log files
from devices for troubleshooting. This requires your own Azure Blob Storage account to store the
uploaded packages.
</div>
</li>
</ul>
</div>
</section>
);
}
@@ -477,7 +477,7 @@ export default function GatherRulesPage() {
</svg>
<div>
<h2 className="text-xl font-semibold text-gray-900">Create Custom Rule</h2>
<p className="text-sm text-gray-500 mt-1">Define a new data collection rule for enrolled devices — <Link href="/docs/gather-rules" className="text-indigo-600 hover:text-indigo-800 underline">see documentation</Link></p>
<p className="text-sm text-gray-500 mt-1">Define a new data collection rule for enrolled devices — <a href="https://docs.autopilotmonitor.com/rules/gather-rules" target="_blank" rel="noopener noreferrer" className="text-indigo-600 hover:text-indigo-800 underline">see documentation</a></p>
</div>
</div>
<JsonModeToggleButtons
+1 -1
View File
@@ -818,7 +818,7 @@ export default function LandingPage() {
<div>
<h4 className="text-[11px] font-semibold text-gray-900 uppercase tracking-wider mb-2.5">Resources</h4>
<ul className="space-y-1.5">
<li><a href="/docs" className="text-xs text-gray-500 hover:text-blue-600 transition-colors">Documentation</a></li>
<li><a href="https://docs.autopilotmonitor.com" target="_blank" rel="noopener noreferrer" className="text-xs text-gray-500 hover:text-blue-600 transition-colors">Documentation</a></li>
<li><a href="https://github.com/okieselbach/Autopilot-Monitor/issues" target="_blank" rel="noopener noreferrer" className="text-xs text-gray-500 hover:text-blue-600 transition-colors">Feedback</a></li>
<li><a href="https://github.com/okieselbach/Autopilot-Monitor" target="_blank" rel="noopener noreferrer" className="text-xs text-gray-500 hover:text-blue-600 transition-colors">GitHub</a></li>
</ul>
@@ -157,7 +157,7 @@ export default function PreviewPage() {
Please sign out and contact me on LinkedIn or open a GitHub issue to request access to the Private Preview. I check incoming requests regularly and will approve them as quickly as possible if I have enough capacity left.
</p>
<p className="text-sm text-amber-800 mt-2">
In the meantime, you can already review the setup and configuration in the <a href="/docs" className="underline hover:no-underline">documentation</a>.
In the meantime, you can already review the setup and configuration in the <a href="https://docs.autopilotmonitor.com" target="_blank" rel="noopener noreferrer" className="underline hover:no-underline">documentation</a>.
</p>
<p className="text-sm text-amber-800 mt-2">
When you signed-up, sign in again later to view the updated approval status on your dashboard.
+1 -1
View File
@@ -5,7 +5,7 @@ export default function robots(): MetadataRoute.Robots {
rules: [
{
userAgent: "*",
allow: ["/", "/about", "/docs", "/roadmap", "/changelog", "/privacy", "/terms"],
allow: ["/", "/about", "/roadmap", "/privacy", "/terms"],
disallow: [
"/dashboard",
"/fleet-health",
+2 -15
View File
@@ -1,5 +1,4 @@
import type { MetadataRoute } from "next";
import { NAV_SECTIONS } from "./docs/docsNavSections";
import { PAGE_LASTMOD } from "@/utils/page-lastmod.generated";
const BASE_URL = "https://www.autopilotmonitor.com";
@@ -9,14 +8,9 @@ function lastmod(urlPath: string): Date {
return iso ? new Date(iso) : new Date();
}
// Documentation lives at docs.autopilotmonitor.com (GitBook) and is indexed
// there; the old /docs/* URLs permanently redirect (see next.config.ts).
export default function sitemap(): MetadataRoute.Sitemap {
const docsSections: MetadataRoute.Sitemap = NAV_SECTIONS.map((section) => ({
url: `${BASE_URL}/docs/${section.id}`,
lastModified: lastmod(`/docs/${section.id}`),
changeFrequency: "weekly",
priority: 0.8,
}));
return [
{
url: `${BASE_URL}/`,
@@ -24,7 +18,6 @@ export default function sitemap(): MetadataRoute.Sitemap {
changeFrequency: "monthly",
priority: 1,
},
...docsSections,
{
url: `${BASE_URL}/about`,
lastModified: lastmod("/about"),
@@ -37,12 +30,6 @@ export default function sitemap(): MetadataRoute.Sitemap {
changeFrequency: "weekly",
priority: 0.7,
},
{
url: `${BASE_URL}/changelog`,
lastModified: lastmod("/changelog"),
changeFrequency: "monthly",
priority: 0.5,
},
{
url: `${BASE_URL}/privacy`,
lastModified: lastmod("/privacy"),
@@ -261,11 +261,9 @@ export function GlobalSidebar({ children }: { children: ReactNode }) {
}
}, [pathname]); // eslint-disable-line react-hooks/exhaustive-deps
// Docs pages are always accessible (public + authenticated)
const isDocsPage = pathname.startsWith("/docs");
// All public pages that should show sidebar + navbar
const PUBLIC_PATHS = ["/docs", "/terms", "/privacy", "/roadmap", "/about", "/changelog"];
// (docs + changelog moved to docs.autopilotmonitor.com)
const PUBLIC_PATHS = ["/terms", "/privacy", "/roadmap", "/about"];
const isPublicPage = PUBLIC_PATHS.some((p) => pathname === p || pathname.startsWith(p + "/"));
// Landing page: never show sidebar
@@ -598,7 +596,7 @@ export function GlobalSidebar({ children }: { children: ReactNode }) {
</ul>
<div className={`${collapseState === "full" || isMobile ? "mt-3" : "mt-1"}`}>
<ul className="space-y-0.5">
{renderGlobalItem({ id: "docs", label: "Docs", href: "/docs", icon: <BookOpenIcon /> })}
{renderGlobalItem({ id: "docs", label: "Docs", href: "https://docs.autopilotmonitor.com", icon: <BookOpenIcon /> })}
{renderGlobalItem({ id: "roadmap", label: "Roadmap", href: "/roadmap", icon: <RocketLaunchIcon /> })}
{renderGlobalItem({ id: "about", label: "About", href: "/about", icon: <InformationCircleIcon /> })}
{renderGlobalItem({ id: "terms", label: "Terms", href: "/terms", icon: <DocumentTextIcon /> })}
@@ -486,8 +486,10 @@ export default function Navbar() {
{showHelp && (
<div className="absolute right-0 mt-2 w-48 bg-white rounded-lg shadow-lg border border-gray-200 z-50 py-1">
<Link
href="/docs"
<a
href="https://docs.autopilotmonitor.com"
target="_blank"
rel="noopener noreferrer"
className="w-full flex items-center gap-2.5 px-3 py-2 text-sm text-gray-700 hover:bg-gray-50 transition-colors"
onClick={() => setShowHelp(false)}
>
@@ -495,7 +497,7 @@ export default function Navbar() {
<path strokeLinecap="round" strokeLinejoin="round" d="M12 6.253v13m0-13C10.832 5.477 9.246 5 7.5 5S4.168 5.477 3 6.253v13C4.168 18.477 5.754 18 7.5 18s3.332.477 4.5 1.253m0-13C13.168 5.477 14.754 5 16.5 5c1.747 0 3.332.477 4.5 1.253v13C19.832 18.477 18.247 18 16.5 18c-1.746 0-3.332.477-4.5 1.253" />
</svg>
<span>Documentation</span>
</Link>
</a>
<Link
href="/roadmap"
@@ -508,8 +510,10 @@ export default function Navbar() {
<span>Roadmap</span>
</Link>
<Link
href="/changelog"
<a
href="https://docs.autopilotmonitor.com/changelog/platform-changelog"
target="_blank"
rel="noopener noreferrer"
className="w-full flex items-center gap-2.5 px-3 py-2 text-sm text-gray-700 hover:bg-gray-50 transition-colors"
onClick={() => setShowHelp(false)}
>
@@ -517,10 +521,12 @@ export default function Navbar() {
<path strokeLinecap="round" strokeLinejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2" />
</svg>
<span>Changelog</span>
</Link>
</a>
<Link
href="/docs/known-issues"
<a
href="https://docs.autopilotmonitor.com/troubleshooting/service-announcements"
target="_blank"
rel="noopener noreferrer"
className="w-full flex items-center gap-2.5 px-3 py-2 text-sm text-gray-700 hover:bg-gray-50 transition-colors"
onClick={() => setShowHelp(false)}
>
@@ -528,7 +534,7 @@ export default function Navbar() {
<path strokeLinecap="round" strokeLinejoin="round" d="M12 9v2m0 4h.01M10.29 3.86L1.82 18a2 2 0 001.71 3h16.94a2 2 0 001.71-3L13.71 3.86a2 2 0 00-3.42 0z" />
</svg>
<span>Known Issues</span>
</Link>
</a>
<div className="border-t border-gray-100 my-1"></div>
@@ -696,22 +702,22 @@ export default function Navbar() {
Help
</button>
<div className="border-t border-gray-100 dark:border-gray-700 my-1"></div>
<Link href="/docs" className="w-full flex items-center gap-2.5 px-3 py-2 text-sm text-gray-700 dark:text-gray-200 hover:bg-gray-50 dark:hover:bg-gray-700 transition-colors" onClick={() => { setShowOverflow(false); setOverflowSubmenu(null); }}>
<a href="https://docs.autopilotmonitor.com" target="_blank" rel="noopener noreferrer" className="w-full flex items-center gap-2.5 px-3 py-2 text-sm text-gray-700 dark:text-gray-200 hover:bg-gray-50 dark:hover:bg-gray-700 transition-colors" onClick={() => { setShowOverflow(false); setOverflowSubmenu(null); }}>
<svg className="w-4 h-4 text-gray-400" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}><path strokeLinecap="round" strokeLinejoin="round" d="M12 6.253v13m0-13C10.832 5.477 9.246 5 7.5 5S4.168 5.477 3 6.253v13C4.168 18.477 5.754 18 7.5 18s3.332.477 4.5 1.253m0-13C13.168 5.477 14.754 5 16.5 5c1.747 0 3.332.477 4.5 1.253v13C19.832 18.477 18.247 18 16.5 18c-1.746 0-3.332.477-4.5 1.253" /></svg>
<span>Documentation</span>
</Link>
</a>
<Link href="/roadmap" className="w-full flex items-center gap-2.5 px-3 py-2 text-sm text-gray-700 dark:text-gray-200 hover:bg-gray-50 dark:hover:bg-gray-700 transition-colors" onClick={() => { setShowOverflow(false); setOverflowSubmenu(null); }}>
<svg className="w-4 h-4 text-gray-400" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}><path strokeLinecap="round" strokeLinejoin="round" d="M9 20l-5.447-2.724A1 1 0 013 16.382V5.618a1 1 0 01.553-.894L9 2m0 18l6-3m-6 3V2m6 15l5.447-2.724A1 1 0 0021 13.382V2.618a1 1 0 00-.553-.894L15 2m0 15V2" /></svg>
<span>Roadmap</span>
</Link>
<Link href="/changelog" className="w-full flex items-center gap-2.5 px-3 py-2 text-sm text-gray-700 dark:text-gray-200 hover:bg-gray-50 dark:hover:bg-gray-700 transition-colors" onClick={() => { setShowOverflow(false); setOverflowSubmenu(null); }}>
<a href="https://docs.autopilotmonitor.com/changelog/platform-changelog" target="_blank" rel="noopener noreferrer" className="w-full flex items-center gap-2.5 px-3 py-2 text-sm text-gray-700 dark:text-gray-200 hover:bg-gray-50 dark:hover:bg-gray-700 transition-colors" onClick={() => { setShowOverflow(false); setOverflowSubmenu(null); }}>
<svg className="w-4 h-4 text-gray-400" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}><path strokeLinecap="round" strokeLinejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2" /></svg>
<span>Changelog</span>
</Link>
<Link href="/docs/known-issues" className="w-full flex items-center gap-2.5 px-3 py-2 text-sm text-gray-700 dark:text-gray-200 hover:bg-gray-50 dark:hover:bg-gray-700 transition-colors" onClick={() => { setShowOverflow(false); setOverflowSubmenu(null); }}>
</a>
<a href="https://docs.autopilotmonitor.com/troubleshooting/service-announcements" target="_blank" rel="noopener noreferrer" className="w-full flex items-center gap-2.5 px-3 py-2 text-sm text-gray-700 dark:text-gray-200 hover:bg-gray-50 dark:hover:bg-gray-700 transition-colors" onClick={() => { setShowOverflow(false); setOverflowSubmenu(null); }}>
<svg className="w-4 h-4 text-gray-400" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}><path strokeLinecap="round" strokeLinejoin="round" d="M12 9v2m0 4h.01M10.29 3.86L1.82 18a2 2 0 001.71 3h16.94a2 2 0 001.71-3L13.71 3.86a2 2 0 00-3.42 0z" /></svg>
<span>Known Issues</span>
</Link>
</a>
<div className="border-t border-gray-100 dark:border-gray-700 my-1"></div>
<Link href="/privacy" className="w-full flex items-center gap-2.5 px-3 py-2 text-sm text-gray-700 dark:text-gray-200 hover:bg-gray-50 dark:hover:bg-gray-700 transition-colors" onClick={() => { setShowOverflow(false); setOverflowSubmenu(null); }}>
<svg className="w-4 h-4 text-gray-400" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}><path strokeLinecap="round" strokeLinejoin="round" d="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z" /></svg>
@@ -80,8 +80,10 @@ export function PublicSiteNavbar({ showSectionLinks, fullWidth = false }: { show
>
Comparison
</a>
<Link
href="/docs"
<a
href="https://docs.autopilotmonitor.com"
target="_blank"
rel="noopener noreferrer"
className={`px-3 py-1.5 text-sm font-medium rounded-md transition-colors ${
isDark
? "bg-transparent text-gray-300 hover:text-gray-100 hover:bg-white/5"
@@ -89,7 +91,7 @@ export function PublicSiteNavbar({ showSectionLinks, fullWidth = false }: { show
}`}
>
Docs
</Link>
</a>
</div>
) : (
<div />
@@ -113,8 +115,10 @@ export function PublicSiteNavbar({ showSectionLinks, fullWidth = false }: { show
</svg>
)}
</button>
<Link
href="/docs"
<a
href="https://docs.autopilotmonitor.com"
target="_blank"
rel="noopener noreferrer"
className={`sm:hidden p-1.5 rounded-lg transition-colors ${
isDark ? "text-gray-300 hover:bg-white/10" : "text-gray-500 hover:bg-gray-100"
}`}
@@ -123,7 +127,7 @@ export function PublicSiteNavbar({ showSectionLinks, fullWidth = false }: { show
<svg className="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
<path strokeLinecap="round" strokeLinejoin="round" d="M12 6.253v13m0-13C10.832 5.477 9.246 5 7.5 5S4.168 5.477 3 6.253v13C4.168 18.477 5.754 18 7.5 18s3.332.477 4.5 1.253m0-13C13.168 5.477 14.754 5 16.5 5c1.747 0 3.332.477 4.5 1.253v13C19.832 18.477 18.247 18 16.5 18c-1.746 0-3.332.477-4.5 1.253" />
</svg>
</Link>
</a>
<a
href="https://github.com/okieselbach/Autopilot-Monitor"
target="_blank"
+30 -2
View File
@@ -14,11 +14,39 @@ const nextConfig: NextConfig = {
],
},
async redirects() {
// Documentation moved to GitBook (docs.autopilotmonitor.com). Specific
// per-section mappings first (Next.js uses the first matching redirect),
// then a catch-all so no old deep link ever 404s.
const DOCS = "https://docs.autopilotmonitor.com";
const docsMoves: Array<[string, string]> = [
["/docs/private-preview", "/getting-started/requirements-and-access"],
["/docs/overview", "/"],
["/docs/general", "/concepts/roles-and-permissions"],
["/docs/setup", "/getting-started/portal-setup"],
["/docs/agent", "/concepts/agent-lifecycle-and-security"],
["/docs/agent-setup", "/getting-started/deploy-the-agent"],
["/docs/settings", "/reference/settings"],
["/docs/gather-rules", "/rules/gather-rules"],
["/docs/analyze-rules", "/rules/analyze-rules"],
["/docs/ime-log-patterns", "/rules/ime-log-patterns"],
["/docs/faq", "/troubleshooting/faq"],
["/docs/known-issues", "/troubleshooting/service-announcements"],
["/docs/mcp-integration", "/integrations/ai-integration-mcp"],
["/docs/agent-changelog", "/changelog/agent-changelog"],
];
return [
// Permanent redirect for old /landing URL — all SEO equity flows to /
{ source: "/landing", destination: "/", permanent: true },
// Docs index redirects to default section
{ source: "/docs", destination: "/docs/overview", permanent: false },
...docsMoves.map(([source, dest]) => ({
source,
destination: `${DOCS}${dest === "/" ? "" : dest}`,
permanent: true,
})),
// Everything else under /docs (incl. retired sections like agent-internals)
{ source: "/docs", destination: DOCS, permanent: true },
{ source: "/docs/:path*", destination: DOCS, permanent: true },
// Platform changelog moved into the GitBook docs as well
{ source: "/changelog", destination: `${DOCS}/changelog/platform-changelog`, permanent: true },
];
},
async headers() {
Binary file not shown.

Before

Width:  |  Height:  |  Size: 83 KiB