diff --git a/apps/docs/src/content/docs/deploy/environment.mdx b/apps/docs/src/content/docs/deploy/environment.mdx
index 977d1996dd..2bfe101a46 100644
--- a/apps/docs/src/content/docs/deploy/environment.mdx
+++ b/apps/docs/src/content/docs/deploy/environment.mdx
@@ -262,6 +262,20 @@ Two rate-limit tiers protect the API. The generic per-user limit covers logged-i
These variables are optional. When unset, the C2C connection wizard falls back to manual credential entry (Client ID, Secret, Tenant ID). Setting both enables a streamlined "Grant Access" button that redirects to Microsoft's admin consent flow.
+## Ticket Mailbox (M365 email-to-ticket)
+
+These enable partners to connect a Microsoft 365 shared support mailbox so customer email becomes tickets and replies are sent from that mailbox. This is a **separate** Azure app registration from the Cloud-to-Cloud Backup app above.
+
+| Variable | Default | Description |
+|---|---|---|
+| `TICKET_MAILBOX_M365_CLIENT_ID` | — | Azure AD app (client) ID for the **Breeze Ticketing** app. When set with the secret, the Microsoft 365 mailbox card appears under Settings → Ticketing → Inbound Email. |
+| `TICKET_MAILBOX_M365_CLIENT_SECRET` | — | Client secret for the Breeze Ticketing Azure app. |
+| `PUBLIC_TICKET_MAILBOX_APP_ID` | — | Build-time, browser-exposed app id shown in the Application Access Policy PowerShell snippet on the settings card. Safe to publish -- it is the app's public client id. |
+
+
+
## Docker Deployment
| Variable | Default | Description |
diff --git a/apps/docs/src/content/docs/features/configuration-policies.mdx b/apps/docs/src/content/docs/features/configuration-policies.mdx
index fa93dbcfca..fdb7600afb 100644
--- a/apps/docs/src/content/docs/features/configuration-policies.mdx
+++ b/apps/docs/src/content/docs/features/configuration-policies.mdx
@@ -42,6 +42,7 @@ A policy can bundle multiple feature types:
| **Monitoring** | Check configuration |
| **Automation** | Event triggers, cron schedules, bulk actions |
| **Privileged Access** | Windows UAC elevation prompt capture for [privileged access management](/features/pam/) |
+| **Vulnerability Scanning** | Turns on daily CVE correlation for the scope (off by default) -- see [vulnerability management](/features/vulnerability-management/) |
Each feature can be configured in one of two modes:
@@ -154,6 +155,12 @@ When a backup feature is linked to a configuration policy, the schedule, retenti
Configure security policy settings for **Security**; check intervals and targets for **Monitoring**; and event triggers, cron schedules, and action chains for **Automation**.
+### Vulnerability Scanning
+
+The **Vulnerability** feature is a single on/off toggle that controls whether the devices in the policy's scope are scanned for CVEs. It is configured **inline** (the on/off state lives in the policy) and is **off by default** -- a device with no vulnerability policy is never scanned, and its Vulnerabilities tab stays empty.
+
+Open the policy's **Vulnerability** tab, switch **Enable vulnerability scanning** on, save, and assign the policy. Because resolution is closest-wins, a device- or group-level setting of *off* overrides an organization-wide *on*. Once a scope is enabled, Breeze correlates its software and OS inventory against the CVE feeds once a day. If a policy exists but no device resolves to *on*, the daily job is simply a no-op -- it never falls back to scanning everything. The findings themselves are reviewed and acted on in [Vulnerability Management](/features/vulnerability-management/), not on this tab.
+
## Assigning a policy
@@ -196,6 +203,7 @@ Examples of shipped defaults:
|---------|---------------|
| Remote Access | Active (on) |
| PAM / UAC capture | Not enforced (off by default) |
+| Vulnerability Scanning | Not enforced (off by default) |
Each row on the Defaults page includes a **Create override policy** shortcut that opens the policy editor pre-configured for that feature, so you can add a partner- or org-level override without navigating away.
@@ -279,7 +287,7 @@ All paths are relative to `/api/v1`.
When creating a policy, set `ownerScope` to `organization` (the default) or `partner`. With `ownerScope: "partner"` the policy is owned partner-wide and any supplied `orgId` is ignored — the partner is always derived from the caller's own token, never trusted from the request body. Creating a partner-wide policy requires partner scope (a `403` is returned otherwise). When assigning a partner-wide policy, use `level: "partner"`; the target is resolved from the caller's own partner, so no `targetId` is required.
-When calling the features endpoints, the `featureType` value must be one of: `patch`, `alert_rule`, `maintenance`, `compliance`, `backup`, `security`, `monitoring`, `automation`, `pam`.
+When calling the features endpoints, the `featureType` value must be one of: `patch`, `alert_rule`, `maintenance`, `compliance`, `backup`, `security`, `monitoring`, `automation`, `pam`, `vulnerability`.
## Troubleshooting
diff --git a/apps/docs/src/content/docs/features/integrations.mdx b/apps/docs/src/content/docs/features/integrations.mdx
index 17181424cc..862bf72cde 100644
--- a/apps/docs/src/content/docs/features/integrations.mdx
+++ b/apps/docs/src/content/docs/features/integrations.mdx
@@ -24,6 +24,7 @@ Breeze supports three categories of integrations, each served by a dedicated set
| **Monitoring** | External monitoring endpoints | Forward device telemetry and health data to third-party observability platforms |
| **Accounting** | QuickBooks Online | Connect your accounting platform (see [Accounting](#accounting-integrations)) |
| **Distributors** | Pax8, TD SYNNEX | Sync licenses and pull live distributor pricing into your [Product Catalog](/features/product-catalog/) |
+| **Network** | UniFi (Ubiquiti Site Manager) | Discover UniFi fleet inventory and WAN health, with optional agent-collected deep telemetry (see [UniFi Network](#unifi-network)) |
-
+#### Importing customers
+
+Once QuickBooks is connected, you can bring your existing QuickBooks customers into Breeze as organizations -- no re-typing. Each imported customer becomes one Breeze **organization** (customer type) with a default **site**, carrying over the billing contact and address.
+
+
+
+1. On the connected **QuickBooks Online** panel, open the **Import customers** section and click **Load customers**.
+2. Tick the customers you want to import. Customers you've already imported show an **Already imported** badge and are skipped automatically (select-all excludes them).
+3. Click **Import selected**. Breeze reports how many were imported, skipped, and failed, with an inline list of any failures.
+
+
+
+The import is idempotent -- it keys off the QuickBooks customer id, so re-running it never creates duplicates. It requires partner scope, and one QuickBooks company (realm) is connected per partner.
+### Pax8
+
+If your Pax8 account is connected, you can search the Pax8 catalog and import individual products as recurring-software catalog items.
+
+
+
+1. From the catalog, click **Import from Pax8** (visible when you have catalog edit access and Pax8 is connected) to open the import drawer.
+2. Search for a product and select it, then choose the **commitment / billing term** -- this determines the pricing. Pax8's partner buy rate fills in as your cost basis, and the term's suggested retail pre-fills your sell price (editable).
+3. Click **Import & add**. The item is created as a recurring-software catalog item with its Pax8 source details retained, and re-importing the same product won't create a duplicate.
+
+
+
+Importing requires MFA confirmation. This is distinct from Pax8 **subscription linking** (mapping a customer's existing subscriptions to contract lines), which is covered under [Integrations → Pax8](/features/integrations/#pax8).
+
### Searching distributor products from a quote
While editing a quote, the line-item picker includes a **Search distributor** tab (visible only when TD SYNNEX EC Express credentials are configured). Enter a TD SYNNEX SKU or manufacturer part number, see live cost, MSRP, and availability, enter your sell price, and click **Import & add**. The product is imported to your catalog and added to the quote as a line item in one step.
diff --git a/apps/docs/src/content/docs/features/reports.mdx b/apps/docs/src/content/docs/features/reports.mdx
index afbc1b5a1a..fa998268d8 100644
--- a/apps/docs/src/content/docs/features/reports.mdx
+++ b/apps/docs/src/content/docs/features/reports.mdx
@@ -26,6 +26,7 @@ Every report has a `type` that determines which data is queried and how the outp
| `compliance` | Device health and compliance posture | hostname, OS, status, last seen, compliance flag, identified issues |
| `performance` | Aggregated CPU, RAM, and disk metrics per device | avg/max CPU %, avg/max RAM %, avg/max disk % |
| `executive_summary` | High-level fleet overview with device counts, alert stats, OS distribution, and site breakdown | online/offline totals, health %, critical/high alert counts, resolution rate |
+| `security_compliance_posture` | Per-control security and compliance evidence for one organization, built for cyber-insurance applications and vendor security questionnaires | EDR/AV coverage, disk encryption %, firewall %, patch currency %, password policy, local-admin exposure, MFA/PAM posture, backup, DNS filtering, optional CIS pass-rate (see [Security & Compliance Posture Report](#security--compliance-posture-report)) |
---
@@ -111,13 +112,12 @@ The response includes:
### Saved Report Generation
-For saved reports, trigger generation with `POST /reports/:id/generate`. This creates a **report run** that is processed asynchronously.
+For saved reports, trigger generation with `POST /reports/:id/generate`. This creates a **report run**, computes the data, and stores the result as a point-in-time snapshot -- all in the same request, so the response comes back already `completed` (or `failed`). The snapshot is what you download later, so the file always reflects the data as of when the run executed rather than re-querying live.
1. Create a saved report definition with `POST /reports` (see the API reference below).
-2. Trigger generation with `POST /reports/:id/generate`.
-3. Poll the run status with `GET /reports/runs/:runId`.
-4. When the run status is `completed`, use the `outputUrl` field to download the file.
+2. Trigger generation with `POST /reports/:id/generate`. The response returns the new `runId` with `status: "completed"` once the snapshot is stored.
+3. Download the result with `GET /reports/runs/:runId/download?format=csv` (or `pdf` / `excel`).
```bash
@@ -199,20 +199,29 @@ The run record stores:
---
+## Security & Compliance Posture Report
+
+The **Security & Compliance Posture** report (`security_compliance_posture`) packages your security evidence for one organization into a single document -- purpose-built for filling out **cyber-insurance applications** and answering **vendor security questionnaires**. It joins the security data Breeze already collects into per-control answers with percent-implemented rollups: EDR/MDR and native antivirus coverage, the list of unprotected devices, disk-encryption and host-firewall coverage, patch currency, antivirus-definition freshness, password-complexity posture, local-admin exposure, MFA and privileged-access posture, backup coverage, DNS filtering, identity-provider connection, and an optional CIS hardening pass-rate.
+
+It is scoped to a single organization (with an optional site filter) and is honest about gaps: a control that hasn't been assessed is reported as **N/A**, never as a misleading 0% or a falsely favorable score. The PDF renders as a branded scorecard (overall score out of 100 with a STRONG / GOOD / FAIR / AT RISK band and a per-control grid) and carries point-in-time, not-a-certification disclaimers.
+
+
+
+---
+
## Downloading and Exporting
-When a report run reaches the `completed` status, the `outputUrl` field contains the download path. The format of the file matches the `format` field of the parent report definition (`csv`, `pdf`, or `excel`).
+When a report run reaches the `completed` status, download its stored snapshot from `GET /reports/runs/:id/download`. Pass the desired format as a query parameter -- `?format=csv`, `?format=pdf`, or `?format=excel`. Because the run captured the data at generation time, the download is stable: re-downloading the same run always yields the same data. Downloading a run that hasn't completed returns `409 Conflict`.
```bash
-# Check run status
-curl /api/v1/reports/runs/RUN_UUID \
- -H "Authorization: Bearer $TOKEN"
-
-# Response includes outputUrl when completed:
-# "outputUrl": "/api/v1/reports/runs/RUN_UUID/download"
+# Download a completed run as CSV
+curl "/api/v1/reports/runs/RUN_UUID/download?format=csv" \
+ -H "Authorization: Bearer $TOKEN" -OJ
```
-When retrieving a single report via `GET /reports/:id`, the response includes the five most recent runs, making it easy to find the latest completed download.
+CSV and Excel files are produced on the server; PDF is rendered in the browser from the same snapshot. When retrieving a single report via `GET /reports/:id`, the response includes the five most recent runs, making it easy to find the latest completed download.
---
@@ -369,6 +378,7 @@ All data endpoints accept these common query parameters:
|--------|----------|-------------|
| `GET` | `/reports/runs` | List runs. Filter by `reportId`, `status`. Paginated. |
| `GET` | `/reports/runs/:id` | Get a single run with parent report metadata and download URL. |
+| `GET` | `/reports/runs/:id/download` | Download the run's stored snapshot. Requires `?format=csv\|pdf\|excel`. Returns `409` if the run is not `completed`. |
### Report Data
@@ -408,9 +418,9 @@ All data endpoints accept these common query parameters:
## Troubleshooting
-### Report run stuck in `pending` status
+### Report run returns `failed`
-Report generation is processed asynchronously after `POST /reports/:id/generate`. If a run remains in `pending` for an extended period, check that the background job processor is running and connected to the database. Query `GET /reports/runs/:id` to inspect the run record -- if `startedAt` is `null`, the job was never picked up.
+`POST /reports/:id/generate` computes the report and stores its snapshot in the same request, so a run normally comes back `completed` immediately. If it comes back `failed`, inspect the run's `errorMessage` field (via `GET /reports/runs/:id`) for the cause -- most often a configuration problem such as an invalid date range or a scope the caller can't access.
### "Organization context required" (403) on report endpoints
diff --git a/apps/docs/src/content/docs/features/ticketing.mdx b/apps/docs/src/content/docs/features/ticketing.mdx
index 34e35c00e6..21f22d9162 100644
--- a/apps/docs/src/content/docs/features/ticketing.mdx
+++ b/apps/docs/src/content/docs/features/ticketing.mdx
@@ -153,6 +153,24 @@ Emails from **unknown senders** and any that failed to process land in a **revie
An email with no usable sender address can't become a ticket. Those appear in the review queue to be dismissed or followed up out-of-band.
+### Connecting a Microsoft 365 support mailbox
+
+Instead of forwarding to your Breeze inbound address, you can connect a Microsoft 365 **shared support mailbox** (for example `support@yourmsp.com`) directly. Customer email to that mailbox becomes tickets, and your public replies are sent back **from that same mailbox** -- with no MX record or forwarding-rule changes. Breeze uses an app-only connection your Microsoft Global Administrator consents to once, so it survives staff turnover (there's no personal login tied to the mailbox). Set it up on the **Microsoft 365 support mailbox** card under **Settings → Ticketing → Inbound Email**.
+
+
+
+1. Enter the shared mailbox address and an optional display name, then click **Connect**. Breeze redirects you to Microsoft, where a **Global Administrator** grants one-time admin consent.
+2. Scope Breeze's access to **only** this mailbox. The card shows an exact **Application Access Policy** snippet (a `New-DistributionGroup` plus `New-ApplicationAccessPolicy` pair) to run in Exchange Online PowerShell as a tenant admin. Until you do this, the connection shows **Needs attention**, because the underlying mail permission is tenant-wide by default.
+3. Click **Re-test**. Once Breeze can read the mailbox, the status flips to **Connected**.
+
+
+
+Once connected, Breeze polls the mailbox every minute or two, turns new messages into tickets (threading and the review queue work exactly as above), and marks each handled message as read so your team can see what's been picked up. Only mail that arrives after you connect is ticketed -- existing inbox history is not imported. Public replies go out **from the support address** and thread natively in the customer's mailbox; internal notes and technician notifications are unaffected. You can connect more than one mailbox (for example `support@` and `billing@`). **Disconnect** stops polling immediately; to fully remove access, also revoke the app's consent in your Microsoft Entra admin center.
+
+
+
## Categories and SLAs
Go to **Settings > Ticketing** to manage ticket categories.
diff --git a/apps/docs/src/content/docs/features/vulnerability-management.mdx b/apps/docs/src/content/docs/features/vulnerability-management.mdx
index fc6863a124..ea591a0e32 100644
--- a/apps/docs/src/content/docs/features/vulnerability-management.mdx
+++ b/apps/docs/src/content/docs/features/vulnerability-management.mdx
@@ -7,12 +7,30 @@ sidebar:
import { Aside, Steps } from '@astrojs/starlight/components';
-Vulnerability Management finds the known security flaws (CVEs) affecting the devices you manage, ranks them by how much they actually matter, and gives you a clear path to act on each one -- deploy a patch, formally accept the risk for a set period, or record a compensating control. It cross-references the software and operating-system versions Breeze already inventories against authoritative vulnerability feeds, so there is nothing to install or scan separately: enrolled devices start producing findings automatically.
+Vulnerability Management finds the known security flaws (CVEs) affecting the devices you manage, ranks them by how much they actually matter, and gives you a clear path to act on each one -- deploy a patch, formally accept the risk for a set period, or record a compensating control. It cross-references the software and operating-system versions Breeze already inventories against authoritative vulnerability feeds, so there is nothing to install or scan separately -- but scanning is **opt-in per scope and off by default**, so you turn it on for the organizations you want covered (see [Enabling vulnerability scanning](#enabling-vulnerability-scanning)).
This page is the operator's guide. Fixes are usually deployed through [Patch Management](/features/patch-management/), and vulnerability posture also feeds the [Security overview](/security/overview/) and the [AI agent](/features/ai/).
Open **Vulnerabilities** from the Security section of the left sidebar for the fleet-wide view, or open any device and select its **Vulnerabilities** tab for a single machine.
+## Enabling vulnerability scanning
+
+Vulnerability scanning is **off by default**. A device only produces findings once it's covered by a configuration policy that turns scanning on, so you can roll the feature out organization by organization instead of flooding every customer at once.
+
+
+
+1. Go to **Configuration → Policies** and open (or create) a policy.
+2. On the **Vulnerability** feature tab, switch **Enable vulnerability scanning** on, and save.
+3. Assign the policy to the scope you want covered -- a partner, organization, site, device group, or individual device.
+
+
+
+Coverage follows the same closest-wins inheritance as every other policy feature: a device- or group-level setting of *off* overrides an organization-wide *on*, so you can enable scanning broadly and carve out exceptions. Once a scope is enabled, Breeze correlates its inventory against the CVE feeds **once a day** (around 13:00 UTC, after the feeds refresh) and populates the findings below. Platform administrators can also trigger a correlation pass on demand.
+
+
+
## What you can do
- See every open CVE across your fleet, ranked by risk, with the number of affected devices.
@@ -62,7 +80,7 @@ Both keep a finding off your open list, but they mean different things:
## Where the data comes from
-Breeze pulls vulnerability intelligence from several authoritative feeds and refreshes them on a schedule -- no configuration required:
+Breeze pulls vulnerability intelligence from several authoritative feeds and refreshes them on a schedule. The feeds themselves need no setup -- they are always kept current; you only choose which scopes to scan against them (see [Enabling vulnerability scanning](#enabling-vulnerability-scanning)). The sources:
| Source | Used for |
|---|---|
diff --git a/scripts/docs-review/last-reviewed.json b/scripts/docs-review/last-reviewed.json
index 780b860632..7933c9e817 100644
--- a/scripts/docs-review/last-reviewed.json
+++ b/scripts/docs-review/last-reviewed.json
@@ -1,5 +1,5 @@
{
- "lastReviewedRef": "v0.86.0",
- "reviewedAt": "2026-06-28",
- "notes": "Bumped after v0.85.0..v0.86.0 sweep (release 0.86.0). Single doc edit: features/reliability.mdx — added v0.86.0 macOS/Linux server-side classification de-junk notes (isGenuineHardwareError gate + downweighted app_crash, #2005) to the macOS and Linux TabItems and extended the re-baseline Aside to note macOS/Linux scores shift on SERVER upgrade regardless of agent version. mapping.json +2 entries: agent/internal/collectors/reliability*.go -> reliability.mdx, DeviceEffectiveConfigTab.tsx -> configuration-policies.mdx. No-change (verified with reasoning): configuration-policies (Effective Config warranty/all-types fix #2003 already matches generic doc wording), deploy/production+upgrades+agents/building (Astro7/TW4/Vite8 frontend toolchain swap #2008/#1995/#1991 is GHCR-image-invisible; self-hosters pull prebuilt images), product-catalog/contracts (quotes/invoices computeQuoteTotals refactor #2011 no admin-visible change), organizations-and-sites (site address/contact persistence #2001 restores documented behavior), enrollment-keys/installation (Windows short-link 500 #2002 internal fix). No migrations, no new env vars, no breaking changes in 0.86.0. STILL DEFERRED from prior sweeps: PR #1725 Breeze Defaults baseline doc review; net-new features/quotes.mdx (quotes/proposals undocumented)."
+ "lastReviewedRef": "v0.87.0",
+ "reviewedAt": "2026-06-29",
+ "notes": "Bumped after v0.86.0..v0.87.0 sweep (release 0.87.0). NOTE: working tree was checked out behind the tag (at #2025/c29a228fb); fast-forwarded main to v0.87.0 (8b7a2e0d1) before editing so docs/source reflected the release. 7 doc files edited + mapping.json (+18 entries, 254 total). Edits: (1) features/integrations.mdx — new ## UniFi Network section (partner-scoped cloud Site Manager API-key connection + site mapping + sync history; optional per-console agent deep-telemetry collector, firmware >=9.3, read-only; #2040/#2051), Integration Types Network row, new #### Importing customers under QuickBooks (QB customers -> Orgs+default Sites, idempotent, partial-success; #2048) + rewrote stale 'later releases' Aside, Pax8 pointer to catalog import. (2) features/ticketing.mdx — new ### Connecting a Microsoft 365 support mailbox (app-only Graph admin-consent flow + ApplicationAccessPolicy least-privilege step, delta-poll, replies from mailbox; #2045). Editable inbound alias (#2060) was ALREADY documented at line 134 — left as-is. (3) deploy/environment.mdx — new ## Ticket Mailbox (M365 email-to-ticket): TICKET_MAILBOX_M365_CLIENT_ID/_SECRET + PUBLIC_TICKET_MAILBOX_APP_ID, redirect URI /api/v1/tickets/mailbox/callback, Graph Mail.ReadWrite+Mail.Send, separate Azure app from C2C. (4) features/reports.mdx — new security_compliance_posture type row + ## Security & Compliance Posture Report section (insurance/questionnaire evidence; created via report API today, builder UI entry point not yet wired — ReportTemplates unmounted + builder maps type down to compliance; documented honestly), FIXED stale async/polling generation prose+Steps (#2058 made generation synchronous w/ persisted snapshot), rewrote Downloading section to GET /reports/runs/:id/download?format=, added API table row, rewrote stale 'stuck in pending' troubleshooting. (5) features/vulnerability-management.mdx — corrected line 10 'findings automatically' (now opt-in OFF-by-default), new ## Enabling vulnerability scanning (per-scope config-policy gate, closest-wins, daily ~13:00 UTC correlation, [] deviceIds = no-op not all-devices; #2050), clarified feeds-need-no-config framing. (6) features/configuration-policies.mdx — Vulnerability Scanning feature row + ### Vulnerability Scanning subsection (inline on/off, DEFAULT OFF) + Breeze Defaults example row + featureType enum +vulnerability. (7) features/product-catalog.mdx — new ### Pax8 catalog-import subsection (search Pax8 catalog -> import as recurring item, MFA; distinct from subscription linking; #2025/#2048 Pax8 search). Skipped per audience filter: webhooks per-route auth (#2054 internal), MCP owning-partner resolution + SSE PUBLIC_API_URL (#2019 internal correctness; PUBLIC_API_URL pre-existing env var), reliability v0.86.0 notes (already in tree). No docsMapping.ts / docsIndex change (all edits were sections in existing pages, no new routes/pages). BUILD VERIFY: `astro build` content-collection step passes with edits (no MDX/frontmatter errors); full build FAILS at SSR bundling with @astrojs/mdx@7.0.0 vs astro@6.4.7 ('chunkToString not exported') — pre-existing v0.87.0 toolchain/lockfile breakage, REPRODUCED on pristine stashed docs, NOT caused by these edits (known Astro7/TW4 transition). STILL DEFERRED: PR #1725 Breeze Defaults baseline review; net-new features/quotes.mdx (quotes/proposals undocumented)."
}
diff --git a/scripts/docs-review/mapping.json b/scripts/docs-review/mapping.json
index ad8e6e2b01..464a08cf38 100644
--- a/scripts/docs-review/mapping.json
+++ b/scripts/docs-review/mapping.json
@@ -1514,6 +1514,118 @@
"docs": [
"features/product-catalog.mdx"
]
+ },
+ {
+ "pattern": "apps/api/src/services/unifi/**",
+ "docs": [
+ "features/integrations.mdx"
+ ]
+ },
+ {
+ "pattern": "apps/api/src/routes/unifi/**",
+ "docs": [
+ "features/integrations.mdx"
+ ]
+ },
+ {
+ "pattern": "apps/api/src/routes/agents/unifiTelemetry.ts",
+ "docs": [
+ "features/integrations.mdx"
+ ]
+ },
+ {
+ "pattern": "apps/web/src/components/integrations/UnifiIntegration.tsx",
+ "docs": [
+ "features/integrations.mdx"
+ ]
+ },
+ {
+ "pattern": "agent/internal/unifi/**",
+ "docs": [
+ "features/integrations.mdx"
+ ]
+ },
+ {
+ "pattern": "apps/api/src/services/ticketMailbox/**",
+ "docs": [
+ "features/ticketing.mdx",
+ "deploy/environment.mdx"
+ ]
+ },
+ {
+ "pattern": "apps/api/src/routes/tickets/mailboxConnect.ts",
+ "docs": [
+ "features/ticketing.mdx",
+ "deploy/environment.mdx"
+ ]
+ },
+ {
+ "pattern": "apps/web/src/components/settings/M365MailboxCard.tsx",
+ "docs": [
+ "features/ticketing.mdx"
+ ]
+ },
+ {
+ "pattern": "apps/api/src/services/securityComplianceReport.ts",
+ "docs": [
+ "features/reports.mdx"
+ ]
+ },
+ {
+ "pattern": "apps/api/src/services/reportGenerationService.ts",
+ "docs": [
+ "features/reports.mdx"
+ ]
+ },
+ {
+ "pattern": "apps/api/src/routes/reports/**",
+ "docs": [
+ "features/reports.mdx"
+ ]
+ },
+ {
+ "pattern": "apps/web/src/components/reports/reportPdf.ts",
+ "docs": [
+ "features/reports.mdx"
+ ]
+ },
+ {
+ "pattern": "apps/api/src/services/vulnerabilityCorrelation.ts",
+ "docs": [
+ "features/vulnerability-management.mdx",
+ "features/configuration-policies.mdx"
+ ]
+ },
+ {
+ "pattern": "apps/web/src/components/configurationPolicies/featureTabs/VulnerabilityTab.tsx",
+ "docs": [
+ "features/configuration-policies.mdx",
+ "features/vulnerability-management.mdx"
+ ]
+ },
+ {
+ "pattern": "apps/api/src/services/accounting/quickbooksCustomerImport.ts",
+ "docs": [
+ "features/integrations.mdx"
+ ]
+ },
+ {
+ "pattern": "apps/web/src/components/integrations/QuickbooksCustomerImport.tsx",
+ "docs": [
+ "features/integrations.mdx"
+ ]
+ },
+ {
+ "pattern": "apps/web/src/components/settings/Pax8CatalogDrawer.tsx",
+ "docs": [
+ "features/product-catalog.mdx"
+ ]
+ },
+ {
+ "pattern": "apps/api/src/services/pax8CatalogService.ts",
+ "docs": [
+ "features/product-catalog.mdx"
+ ]
}
]
}