feat: Veeam VSPC backup integration - sync, compliance, UI
- Database: 7 Veeam tables + backup_type_udf column on configuration_items - API Client: VSPC REST API v3 client with pagination, rate limiting, Bearer auth - Sync Service: full/incremental sync for orgs, servers, repos, jobs, agent jobs, workloads - Scheduler: veeam-incremental (30min) and veeam-full (daily 2AM) schedules - Compliance Engine: cross-references Autotask config items vs Veeam workloads - API Endpoints: backup-status, companies, workloads, jobs, repos, compliance, sync - UI: Backup Status page with Overview + Contract Compliance tabs - Navigation: added Backup Status link with HardDrive icon - Docker: added VEEAM_VSPC_URL and VEEAM_VSPC_API_KEY env vars to compose
This commit is contained in:
parent
a1e0e7c7c0
commit
5dc7a7e66b
27 changed files with 3408 additions and 7 deletions
566
tasks/prd-veeam-integration.md
Normal file
566
tasks/prd-veeam-integration.md
Normal file
|
|
@ -0,0 +1,566 @@
|
|||
# PRD: Veeam Service Provider Console (VSPC) Backup Integration
|
||||
|
||||
## Introduction/Overview
|
||||
|
||||
This feature adds Veeam Service Provider Console (VSPC) as a connected vendor in Pulse, providing visibility into backup job status, protected workloads, backup repositories, and restore point data across all managed clients. Data will be synced on a schedule to PostgreSQL (following the same pattern as the Autotask sync) and displayed on a dedicated **Backup Status** page.
|
||||
|
||||
Additionally, this integration includes a **Contract Compliance** audit that cross-references Autotask configuration items (which have a backup-type UDF and are associated with active contracts) against actual Veeam backup data. This ensures every contracted backup is actually running, and every active Veeam backup is covered by a contract.
|
||||
|
||||
**Problem Statement:** MSP technicians and administrators currently have no visibility into backup health within Pulse. They must log into the Veeam Service Provider Console separately to check backup job statuses, identify failed backups, verify protected machines, and assess repository capacity. This context-switching slows response times and makes it easy to miss backup failures. Furthermore, there is no automated way to verify that devices under an active backup contract are actually being backed up, or that Veeam is not backing up devices that aren't under contract — leading to revenue leakage and compliance gaps.
|
||||
|
||||
**Goal:** Provide a centralized Backup Status page within Pulse that surfaces all critical Veeam backup data — job statuses, protected/unprotected machines, repository usage, restore point history, and RPO/SLA compliance — synced on a configurable schedule and linked to Autotask companies via the Company ID field in VSPC. Additionally, provide a Contract Compliance view that flags mismatches between contracted backup services and actual Veeam protection.
|
||||
|
||||
## Goals
|
||||
|
||||
1. **Visibility Goal:** Surface backup job status (success/failure/warning) for all managed clients in a single page
|
||||
2. **Coverage Goal:** Identify protected vs unprotected machines per company to highlight backup gaps
|
||||
3. **Capacity Goal:** Display backup repository usage and capacity to enable proactive storage management
|
||||
4. **Compliance Goal:** Show RPO/SLA compliance status per company and per protected workload
|
||||
5. **Contract Compliance Goal:** Cross-reference Autotask config items with backup UDFs on active contracts against Veeam protected workloads to identify: (a) contracted devices not being backed up, and (b) devices being backed up without a contract
|
||||
6. **Sync Goal:** Reliably sync Veeam data to PostgreSQL on a configurable schedule, following the existing Autotask sync pattern
|
||||
7. **Matching Goal:** Automatically associate VSPC organizations with Autotask companies using the Company ID field stored in VSPC
|
||||
8. **UDF Sync Goal:** Sync the backup-type UDF (ID: `29693319`) from Autotask configuration items to PostgreSQL to enable contract compliance analysis
|
||||
|
||||
## User Stories
|
||||
|
||||
1. **As an MSP administrator**, I want to see a summary of all backup job statuses across all clients on a single page, so that I can quickly identify which clients have failing backups without logging into VSPC.
|
||||
|
||||
2. **As an MSP technician**, I want to view detailed backup information for a specific company — including last backup time, job status, and protected machines — so that I can troubleshoot backup issues efficiently.
|
||||
|
||||
3. **As an MSP administrator**, I want to see which machines are not protected by any backup job, so that I can ensure complete backup coverage for all clients.
|
||||
|
||||
4. **As an MSP administrator**, I want to monitor backup repository usage and capacity, so that I can proactively provision additional storage before repositories fill up.
|
||||
|
||||
5. **As an MSP administrator**, I want to see restore point history for protected machines, so that I can verify data recoverability and RPO compliance.
|
||||
|
||||
6. **As an MSP administrator**, I want backup data to sync automatically on a schedule, so that the Backup Status page always shows recent data without manual intervention.
|
||||
|
||||
7. **As an MSP administrator**, I want to configure the Veeam sync schedule from the admin panel, so that I can control how frequently data is refreshed.
|
||||
|
||||
8. **As an MSP administrator**, I want to see which configuration items have a backup UDF set (Server Image, Workstation Image, Workstation File Based, etc.) and are on an active contract but are NOT being backed up in Veeam, so that I can identify contracted services that aren't being delivered.
|
||||
|
||||
9. **As an MSP administrator**, I want to see which machines are being backed up in Veeam but do NOT have a corresponding configuration item with a backup UDF on an active contract, so that I can identify unbilled backup services and potential revenue leakage.
|
||||
|
||||
10. **As an MSP administrator**, I want a summary card showing the total number of contract compliance mismatches, so that I can quickly assess the overall health of backup contract alignment.
|
||||
|
||||
## Functional Requirements
|
||||
|
||||
### FR1: Veeam VSPC API Client
|
||||
|
||||
1.1. Create a Veeam VSPC API client service (`/lib/services/veeam-client.ts`) that handles authentication and API requests
|
||||
1.2. Use credentials from environment variables: `VEEAM_VSPC_URL`, `VEEAM_VSPC_API_KEY`
|
||||
1.3. Implement API Key-based authorization using the `Authorization: Bearer <API-Key>` header
|
||||
1.4. Base URL format: `https://<hostname>:1280/api/v3`
|
||||
1.5. Support pagination using `offset` and `limit` query parameters
|
||||
1.6. Support filtering using the VSPC `filter` query parameter syntax
|
||||
1.7. Include proper error handling and logging for all API calls
|
||||
1.8. Implement rate limiting to respect VSPC throttling settings
|
||||
1.9. Handle token refresh if using OAuth 2.0 as a fallback authentication method
|
||||
|
||||
### FR2: VSPC Data Fetching
|
||||
|
||||
Fetch the following data from the VSPC REST API v3:
|
||||
|
||||
2.1. **Organizations** — `/organizations` — Company/tenant data including `instanceUid`, `name`, `companyId` (maps to Autotask Company ID)
|
||||
2.2. **Backup Servers** — `/infrastructure/backupServers` — Server name, version, status, role type
|
||||
2.3. **Backup Jobs** — Backup job definitions including name, type, schedule, target repository, associated organization
|
||||
2.4. **Backup Job Sessions** — Recent job session results including status (Success/Warning/Failed), start time, end time, duration, transferred data size, bottleneck info
|
||||
2.5. **Protected Workloads** — Protected virtual machines and physical servers including name, platform, protection status, last restore point date
|
||||
2.6. **Backup Repositories** — Repository name, capacity, free space, used space, associated backup server
|
||||
2.7. **Restore Points** — Restore point data per protected workload including creation date, size, type (full/incremental)
|
||||
|
||||
### FR3: Company Matching
|
||||
|
||||
3.1. Match VSPC organizations to Autotask companies using the `companyId` field in VSPC, which contains the Autotask Company ID
|
||||
3.2. Store the mapping in the `veeam_organizations` database table
|
||||
3.3. Handle cases where `companyId` is not set in VSPC (log warning, skip matching)
|
||||
3.4. Support manual mapping override via admin UI for edge cases
|
||||
|
||||
### FR4: PostgreSQL Database Schema
|
||||
|
||||
Create the following tables for synced Veeam data:
|
||||
|
||||
4.1. **`veeam_organizations`** — VSPC organization data
|
||||
- `instance_uid` (VARCHAR, PK) — VSPC organization UID
|
||||
- `name` (VARCHAR) — Organization name
|
||||
- `company_id` (INTEGER) — Autotask Company ID (FK reference)
|
||||
- `status` (VARCHAR) — Organization status
|
||||
- `synced_at` (TIMESTAMP)
|
||||
|
||||
4.2. **`veeam_backup_servers`** — Backup server infrastructure
|
||||
- `instance_uid` (VARCHAR, PK)
|
||||
- `name` (VARCHAR)
|
||||
- `organization_uid` (VARCHAR, FK → veeam_organizations)
|
||||
- `version` (VARCHAR)
|
||||
- `display_version` (VARCHAR)
|
||||
- `status` (VARCHAR) — Healthy/Warning/Error
|
||||
- `role_type` (VARCHAR) — CloudConnect/Hosted/etc.
|
||||
- `synced_at` (TIMESTAMP)
|
||||
|
||||
4.3. **`veeam_backup_jobs`** — Backup job definitions
|
||||
- `instance_uid` (VARCHAR, PK)
|
||||
- `name` (VARCHAR)
|
||||
- `organization_uid` (VARCHAR, FK → veeam_organizations)
|
||||
- `backup_server_uid` (VARCHAR, FK → veeam_backup_servers)
|
||||
- `job_type` (VARCHAR) — Backup/Replication/Copy/etc.
|
||||
- `status` (VARCHAR) — Running/Idle/Disabled
|
||||
- `last_run` (TIMESTAMP)
|
||||
- `last_result` (VARCHAR) — Success/Warning/Failed
|
||||
- `schedule_enabled` (BOOLEAN)
|
||||
- `repository_uid` (VARCHAR)
|
||||
- `synced_at` (TIMESTAMP)
|
||||
|
||||
4.4. **`veeam_job_sessions`** — Recent backup job session results
|
||||
- `instance_uid` (VARCHAR, PK)
|
||||
- `job_uid` (VARCHAR, FK → veeam_backup_jobs)
|
||||
- `organization_uid` (VARCHAR, FK → veeam_organizations)
|
||||
- `status` (VARCHAR) — Success/Warning/Failed
|
||||
- `start_time` (TIMESTAMP)
|
||||
- `end_time` (TIMESTAMP)
|
||||
- `duration_seconds` (INTEGER)
|
||||
- `transferred_bytes` (BIGINT)
|
||||
- `processed_bytes` (BIGINT)
|
||||
- `bottleneck` (VARCHAR)
|
||||
- `error_message` (TEXT)
|
||||
- `synced_at` (TIMESTAMP)
|
||||
|
||||
4.5. **`veeam_protected_workloads`** — Protected VMs and physical servers
|
||||
- `instance_uid` (VARCHAR, PK)
|
||||
- `name` (VARCHAR)
|
||||
- `organization_uid` (VARCHAR, FK → veeam_organizations)
|
||||
- `platform` (VARCHAR) — VMware/Hyper-V/Physical/etc.
|
||||
- `protection_status` (VARCHAR) — Protected/Unprotected/Partial
|
||||
- `last_restore_point` (TIMESTAMP)
|
||||
- `restore_point_count` (INTEGER)
|
||||
- `total_backup_size_bytes` (BIGINT)
|
||||
- `synced_at` (TIMESTAMP)
|
||||
|
||||
4.6. **`veeam_repositories`** — Backup repository capacity
|
||||
- `instance_uid` (VARCHAR, PK)
|
||||
- `name` (VARCHAR)
|
||||
- `backup_server_uid` (VARCHAR, FK → veeam_backup_servers)
|
||||
- `capacity_bytes` (BIGINT)
|
||||
- `free_space_bytes` (BIGINT)
|
||||
- `used_space_bytes` (BIGINT)
|
||||
- `repository_type` (VARCHAR)
|
||||
- `synced_at` (TIMESTAMP)
|
||||
|
||||
4.7. **`veeam_restore_points`** — Restore point history
|
||||
- `instance_uid` (VARCHAR, PK)
|
||||
- `workload_uid` (VARCHAR, FK → veeam_protected_workloads)
|
||||
- `organization_uid` (VARCHAR, FK → veeam_organizations)
|
||||
- `creation_date` (TIMESTAMP)
|
||||
- `type` (VARCHAR) — Full/Incremental
|
||||
- `size_bytes` (BIGINT)
|
||||
- `synced_at` (TIMESTAMP)
|
||||
|
||||
### FR5: Veeam Sync Service
|
||||
|
||||
5.1. Create a Veeam sync service (`/lib/services/veeam-sync-service.ts`) following the pattern of the existing Autotask `SyncService`
|
||||
5.2. Support full sync (all data) and incremental sync (changed data since last sync)
|
||||
5.3. Sync entities in dependency order: organizations → backup servers → repositories → backup jobs → job sessions → protected workloads → restore points
|
||||
5.4. Record sync history in the existing `sync_history` table with `sync_source: 'veeam'`
|
||||
5.5. Log sync progress and errors using the existing `SyncLogger` pattern
|
||||
5.6. Handle API pagination automatically (fetch all pages per entity)
|
||||
|
||||
### FR6: Sync Scheduler Integration
|
||||
|
||||
6.1. Add Veeam sync schedules to the existing sync scheduler (`/lib/services/sync-scheduler.ts`)
|
||||
6.2. Default schedule: incremental sync every 30 minutes, full sync daily at 2:00 AM
|
||||
6.3. Allow schedule configuration from the Admin → Sync page
|
||||
6.4. Display Veeam sync status and history alongside Autotask sync data in the admin UI
|
||||
|
||||
### FR7: Backup Status Page
|
||||
|
||||
7.1. Create a new page at `/backup-status` accessible from the main navigation
|
||||
7.2. Page layout sections:
|
||||
|
||||
**Summary Cards (top row):**
|
||||
- Total protected workloads count
|
||||
- Unprotected workloads count (with warning color if > 0)
|
||||
- Last 24h job success rate (percentage)
|
||||
- Failed jobs in last 24h (count, red if > 0)
|
||||
- Total repository usage (used/total with percentage bar)
|
||||
|
||||
**Company Backup Overview (main table):**
|
||||
- Company name (linked to Autotask company)
|
||||
- Protected workload count
|
||||
- Unprotected workload count
|
||||
- Last backup job status (color-coded badge: green/yellow/red)
|
||||
- Last successful backup timestamp
|
||||
- Oldest restore point age
|
||||
- Repository usage for company (if applicable)
|
||||
- Expandable row to show individual workloads and jobs
|
||||
|
||||
**Filters:**
|
||||
- Filter by company
|
||||
- Filter by backup status (Success/Warning/Failed/All)
|
||||
- Filter by protection status (Protected/Unprotected/All)
|
||||
- Search by workload name
|
||||
|
||||
### FR8: Company Backup Detail View
|
||||
|
||||
8.1. Clicking a company row expands to show:
|
||||
- List of all protected workloads with last restore point date and status
|
||||
- List of all backup jobs with last run time and result
|
||||
- Recent job session history (last 7 days) with status timeline
|
||||
- Unprotected machines highlighted in red/warning
|
||||
|
||||
### FR9: API Endpoints
|
||||
|
||||
9.1. `GET /api/veeam/backup-status` — Summary statistics for dashboard cards
|
||||
9.2. `GET /api/veeam/companies` — Company-level backup overview with aggregated stats
|
||||
9.3. `GET /api/veeam/companies/[companyId]/workloads` — Protected workloads for a specific company
|
||||
9.4. `GET /api/veeam/companies/[companyId]/jobs` — Backup jobs for a specific company
|
||||
9.5. `GET /api/veeam/companies/[companyId]/sessions` — Recent job sessions for a specific company
|
||||
9.6. `GET /api/veeam/repositories` — Repository capacity overview
|
||||
9.7. `GET /api/veeam/sync` — Trigger manual Veeam sync (POST)
|
||||
9.8. `GET /api/veeam/compliance` — Contract compliance summary and mismatch list
|
||||
9.9. `GET /api/veeam/compliance/[companyId]` — Compliance details for a specific company
|
||||
9.10. All endpoints read from PostgreSQL (synced data), not directly from VSPC API
|
||||
|
||||
### FR10: TypeScript Types
|
||||
|
||||
10.1. Create Veeam type definitions in `/lib/types/veeam.ts`:
|
||||
- `VeeamOrganization` interface
|
||||
- `VeeamBackupServer` interface
|
||||
- `VeeamBackupJob` interface
|
||||
- `VeeamJobSession` interface
|
||||
- `VeeamProtectedWorkload` interface
|
||||
- `VeeamRepository` interface
|
||||
- `VeeamRestorePoint` interface
|
||||
- `VeeamBackupStatusSummary` interface (for dashboard cards)
|
||||
- `VeeamCompanyBackupOverview` interface (for company table)
|
||||
- `VeeamComplianceResult` interface (for compliance mismatch records)
|
||||
- `VeeamComplianceSummary` interface (for compliance summary cards)
|
||||
10.2. Export types for use across the application
|
||||
|
||||
### FR11: Error Handling & Logging
|
||||
|
||||
11.1. Log all VSPC API errors to console with descriptive messages
|
||||
11.2. Log sync progress (entities synced, records created/updated/skipped)
|
||||
11.3. Never throw errors that would break the Backup Status page — show "Data unavailable" gracefully
|
||||
11.4. Display last successful sync timestamp on the Backup Status page
|
||||
11.5. Show warning banner if last sync is older than 2 hours
|
||||
|
||||
### FR12: Navigation Integration
|
||||
|
||||
12.1. Add "Backup Status" link to the main sidebar navigation
|
||||
12.2. Use an appropriate Lucide icon (e.g., `HardDrive`, `Shield`, `Database`)
|
||||
12.3. Position after existing navigation items
|
||||
|
||||
### FR13: Autotask Backup UDF Sync
|
||||
|
||||
**Note:** Autotask configuration item UDFs are NOT currently synced to PostgreSQL. The `mapConfigurationItem` function in `/lib/utils/entity-mapper.ts` does not include `userDefinedFields`. This must be addressed.
|
||||
|
||||
13.1. Add a `backup_type_udf` column (VARCHAR, nullable) to the `configuration_items` table via migration
|
||||
13.2. During Autotask config item sync, extract the backup-type UDF (ID: `29693319`) from the `userDefinedFields` array and store its value in the `backup_type_udf` column
|
||||
13.3. Update `mapConfigurationItem()` in `/lib/utils/entity-mapper.ts` to map the UDF value
|
||||
13.4. Known UDF values to support:
|
||||
- `Server Image`
|
||||
- `Workstation Image`
|
||||
- `Workstation File Based`
|
||||
- Any other non-null/non-empty value should also be stored as-is
|
||||
13.5. Add an index on `backup_type_udf` for efficient compliance queries
|
||||
13.6. Ensure the Autotask API query for configuration items includes `userDefinedFields` in the response (verify the existing `queryEntity` call returns UDFs)
|
||||
|
||||
### FR14: Contract Compliance Logic
|
||||
|
||||
14.1. Define a config item as "contracted for backup" when ALL of the following are true:
|
||||
- `backup_type_udf` is NOT NULL and NOT empty
|
||||
- `contract_id` is NOT NULL
|
||||
- The associated contract has `status` = active (numeric value TBD — verify from Autotask picklist)
|
||||
- `is_active` = true
|
||||
14.2. Match contracted config items to Veeam protected workloads using:
|
||||
- Primary: hostname match (config item `reference_title` or RMM hostname vs Veeam workload `name`)
|
||||
- Secondary: company match + name similarity (fuzzy)
|
||||
14.3. Produce two mismatch lists per company:
|
||||
- **Contracted but NOT backed up:** Config items meeting 14.1 criteria with no matching Veeam protected workload
|
||||
- **Backed up but NOT contracted:** Veeam protected workloads with no matching config item that meets 14.1 criteria
|
||||
14.4. Store compliance results in a `veeam_compliance_results` table:
|
||||
- `id` (SERIAL, PK)
|
||||
- `company_id` (INTEGER, FK → companies)
|
||||
- `configuration_item_id` (INTEGER, nullable, FK → configuration_items)
|
||||
- `veeam_workload_uid` (VARCHAR, nullable, FK → veeam_protected_workloads)
|
||||
- `mismatch_type` (VARCHAR) — `contracted_not_backed_up` or `backed_up_not_contracted`
|
||||
- `backup_type_udf` (VARCHAR, nullable) — The UDF value from the config item
|
||||
- `device_name` (VARCHAR) — Name of the device for display
|
||||
- `computed_at` (TIMESTAMP) — When this compliance check was run
|
||||
14.5. Recompute compliance results after each Veeam sync completes
|
||||
14.6. Log compliance computation results (total matched, total mismatches per type)
|
||||
|
||||
### FR15: Contract Compliance UI
|
||||
|
||||
15.1. Add a "Contract Compliance" tab to the Backup Status page (alongside the main backup overview)
|
||||
15.2. **Compliance Summary Cards:**
|
||||
- Total contracted backup devices (config items with backup UDF + active contract)
|
||||
- Matched (contracted AND backed up in Veeam)
|
||||
- Contracted but NOT backed up (red/warning count)
|
||||
- Backed up but NOT contracted (amber/warning count)
|
||||
15.3. **Compliance Detail Table:**
|
||||
- Company name
|
||||
- Device name
|
||||
- Mismatch type (visual badge: "Missing Backup" in red, "No Contract" in amber)
|
||||
- Backup type UDF value (Server Image, Workstation Image, etc.)
|
||||
- Contract name (if applicable)
|
||||
- Veeam workload name (if applicable)
|
||||
- Filterable by company, mismatch type
|
||||
15.4. **Company Backup Detail** (FR8) should also show compliance status:
|
||||
- In the expanded company row, show a "Compliance" section listing any mismatches for that company
|
||||
|
||||
## Non-Goals (Out of Scope)
|
||||
|
||||
1. **Kiosk/Ticker Integration:** Backup data will NOT appear in the kiosk ticker or dashboard
|
||||
2. **Backup Triggering:** Will NOT allow starting/stopping backup jobs from Pulse
|
||||
3. **Restore Operations:** Will NOT support initiating restores from Pulse
|
||||
4. **Auto-Remediation:** Will NOT automatically create contracts or backup jobs to fix compliance mismatches
|
||||
5. **Alerting/Notifications:** Will NOT send email or other notifications for backup failures
|
||||
6. **Veeam Cloud Connect:** Will NOT integrate with Cloud Connect tenant data specifically
|
||||
7. **Real-Time Data:** All data is synced on schedule; no real-time/on-demand VSPC API calls from the UI
|
||||
8. **Multi-Instance:** Will NOT support multiple VSPC instances (single instance only)
|
||||
|
||||
## Design Considerations
|
||||
|
||||
### UI Components
|
||||
- Follow existing Pulse design patterns (dark theme, shadcn/ui components)
|
||||
- Use same Card, Badge, Table, and Button components from shadcn/ui
|
||||
- Maintain consistent spacing, typography, and color scheme
|
||||
- Use Lucide icons for backup-related visuals
|
||||
|
||||
### Status Color Coding
|
||||
- **Success:** Green badge/indicator
|
||||
- **Warning:** Yellow/amber badge/indicator
|
||||
- **Failed:** Red badge/indicator
|
||||
- **Running:** Blue badge/indicator with spinner
|
||||
- **Disabled:** Gray badge/indicator
|
||||
|
||||
### Page Layout
|
||||
```
|
||||
┌──────────────────────────────────────────────────────────────┐
|
||||
│ Backup Status Last sync: 5m ago │
|
||||
├──────────────────────────────────────────────────────────────┤
|
||||
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌─────┐│
|
||||
│ │Protected │ │Unprotect.│ │Success % │ │ Failed │ │Repo ││
|
||||
│ │ 142 │ │ 3 ⚠ │ │ 96.2% │ │ 4 🔴 │ │ 72% ││
|
||||
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ └─────┘│
|
||||
├──────────────────────────────────────────────────────────────┤
|
||||
│ [Filter: Company ▼] [Status ▼] [Protection ▼] [Search...] │
|
||||
├──────────────────────────────────────────────────────────────┤
|
||||
│ Company │ Protected │ Unprotected │ Status │ Last OK │
|
||||
│────────────────┼───────────┼─────────────┼────────┼──────────│
|
||||
│ Acme Corp │ 12 │ 0 │ ✅ │ 2h ago │
|
||||
│ └─ [Expand to show workloads and jobs] │
|
||||
│ Beta LLC │ 8 │ 1 │ ⚠️ │ 5h ago │
|
||||
│ Gamma Inc │ 5 │ 0 │ 🔴 │ 26h ago │
|
||||
└──────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### Repository Capacity Visualization
|
||||
- Use progress bars showing used/total capacity
|
||||
- Color-code: green (< 70%), yellow (70-85%), red (> 85%)
|
||||
|
||||
### Contract Compliance Tab Layout
|
||||
```
|
||||
┌──────────────────────────────────────────────────────────────┐
|
||||
│ [Backup Overview] [Contract Compliance] │
|
||||
├──────────────────────────────────────────────────────────────┤
|
||||
│ ┌────────────┐ ┌────────────┐ ┌────────────┐ ┌────────────┐ │
|
||||
│ │ Contracted │ │ Matched │ │ Missing │ │ No │ │
|
||||
│ │ Backups │ │ │ │ Backup │ │ Contract │ │
|
||||
│ │ 87 │ │ 82 ✅ │ │ 3 🔴 │ │ 2 🟠 │ │
|
||||
│ └────────────┘ └────────────┘ └────────────┘ └────────────┘ │
|
||||
├──────────────────────────────────────────────────────────────┤
|
||||
│ [Filter: Company ▼] [Mismatch Type ▼] [Search...] │
|
||||
├──────────────────────────────────────────────────────────────┤
|
||||
│ Company │ Device │ Type │ Backup UDF │Issue │
|
||||
│─────────────┼────────────────┼──────────┼─────────────┼──────│
|
||||
│ Acme Corp │ ACME-FS01 │ 🔴 Miss. │ Server Image│ No │
|
||||
│ │ │ Backup │ │Veeam │
|
||||
│ Beta LLC │ BETA-PC-042 │ 🟠 No │ │ No │
|
||||
│ │ │ Contract │ │ UDF │
|
||||
└──────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### Compliance Status Badges
|
||||
- **Matched:** Green badge — contracted and backed up
|
||||
- **Missing Backup:** Red badge — contracted but not found in Veeam
|
||||
- **No Contract:** Amber badge — backed up in Veeam but no matching contract
|
||||
|
||||
## Technical Considerations
|
||||
|
||||
### VSPC API Integration
|
||||
- **API Version:** REST API v3 (3.6.1)
|
||||
- **Base URL:** `https://<hostname>:1280/api/v3`
|
||||
- **Authentication:** API Key-based (`Authorization: Bearer <API-Key>`)
|
||||
- **Pagination:** Offset-based with `offset` and `limit` query parameters
|
||||
- **Filtering:** VSPC filter syntax (e.g., `filter=status eq "Failed"`)
|
||||
- **Rate Limiting:** Respect VSPC throttling settings; implement exponential backoff
|
||||
- **SSL:** VSPC may use self-signed certificates; support `NODE_TLS_REJECT_UNAUTHORIZED` env var for development
|
||||
|
||||
### Company Matching Logic
|
||||
```typescript
|
||||
// VSPC organizations have a companyId field that maps to Autotask Company ID
|
||||
async function matchOrganizations(
|
||||
vspcOrgs: VeeamOrganization[],
|
||||
autotaskCompanies: Company[]
|
||||
): Map<string, number> {
|
||||
const mapping = new Map<string, number>(); // vspcOrgUid → autotaskCompanyId
|
||||
|
||||
for (const org of vspcOrgs) {
|
||||
if (org.companyId) {
|
||||
const match = autotaskCompanies.find(c => c.id === parseInt(org.companyId));
|
||||
if (match) {
|
||||
mapping.set(org.instanceUid, match.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return mapping;
|
||||
}
|
||||
```
|
||||
|
||||
### Dependencies
|
||||
- No new npm packages required (use built-in fetch)
|
||||
- Leverage existing service patterns (`autotask-client.ts`, `sync-service.ts`, `entity-sync.ts`)
|
||||
- Use existing UI components from shadcn/ui
|
||||
- Use existing PostgreSQL client (`postgres-client.ts`)
|
||||
- Use existing sync scheduler infrastructure
|
||||
|
||||
### File Structure
|
||||
```
|
||||
/lib/services/veeam-client.ts # VSPC API client
|
||||
/lib/services/veeam-factory.ts # Singleton factory for client
|
||||
/lib/services/veeam-sync-service.ts # Sync orchestration service
|
||||
/lib/services/veeam-compliance-service.ts # Contract compliance computation
|
||||
/lib/types/veeam.ts # TypeScript types
|
||||
/app/api/veeam/backup-status/route.ts # Summary stats endpoint
|
||||
/app/api/veeam/companies/route.ts # Company backup overview
|
||||
/app/api/veeam/companies/[companyId]/workloads/route.ts
|
||||
/app/api/veeam/companies/[companyId]/jobs/route.ts
|
||||
/app/api/veeam/companies/[companyId]/sessions/route.ts
|
||||
/app/api/veeam/repositories/route.ts # Repository capacity
|
||||
/app/api/veeam/sync/route.ts # Manual sync trigger
|
||||
/app/api/veeam/compliance/route.ts # Compliance summary + list
|
||||
/app/api/veeam/compliance/[companyId]/route.ts # Per-company compliance
|
||||
/app/backup-status/page.tsx # Main Backup Status page
|
||||
/components/backup/backup-summary-cards.tsx # Summary KPI cards
|
||||
/components/backup/company-backup-table.tsx # Company overview table
|
||||
/components/backup/company-backup-detail.tsx # Expanded company detail
|
||||
/components/backup/repository-overview.tsx # Repository capacity view
|
||||
/components/backup/compliance-summary-cards.tsx # Compliance KPI cards
|
||||
/components/backup/compliance-detail-table.tsx # Compliance mismatch table
|
||||
/migrations/023_create_veeam_tables.sql # Veeam tables + compliance results
|
||||
/migrations/024_add_backup_type_udf.sql # Add backup_type_udf to configuration_items
|
||||
```
|
||||
|
||||
### Environment Variables
|
||||
```bash
|
||||
VEEAM_VSPC_URL=https://vac.wulfconsulting.com:1280
|
||||
VEEAM_VSPC_API_KEY=your-api-key-here
|
||||
# Optional: set to '0' if VSPC uses self-signed certs (dev only)
|
||||
# NODE_TLS_REJECT_UNAUTHORIZED=0
|
||||
```
|
||||
|
||||
### Database Migration
|
||||
- Migration file: `023_create_veeam_tables.sql`
|
||||
- Creates all 7 Veeam tables with appropriate indexes
|
||||
- Creates `veeam_compliance_results` table
|
||||
- Add indexes on `organization_uid`, `company_id`, `status`, `synced_at` columns for query performance
|
||||
- Add index on `veeam_job_sessions.start_time` for time-range queries
|
||||
- Add index on `veeam_compliance_results.company_id` and `mismatch_type`
|
||||
- Migration file: `024_add_backup_type_udf.sql`
|
||||
- Adds `backup_type_udf` (VARCHAR, nullable) column to `configuration_items` table
|
||||
- Adds index on `backup_type_udf` for compliance queries
|
||||
- Note: Existing config items will have NULL for this column until the next Autotask sync runs
|
||||
|
||||
## Success Metrics
|
||||
|
||||
1. **Sync Reliability:** 99%+ of scheduled syncs complete successfully
|
||||
2. **Data Freshness:** Backup status data is never more than 1 hour old during business hours
|
||||
3. **Company Match Rate:** 95%+ of VSPC organizations are matched to Autotask companies via Company ID
|
||||
4. **Page Load Performance:** Backup Status page loads within 2 seconds for typical MSP (< 50 companies)
|
||||
5. **Coverage Visibility:** 100% of VSPC-managed workloads are visible in the Backup Status page
|
||||
6. **Adoption:** Administrators check the Backup Status page at least once daily within the first month
|
||||
7. **Compliance Accuracy:** 95%+ of contracted backup devices are correctly matched to Veeam workloads (hostname matching)
|
||||
8. **Revenue Protection:** Identify 100% of Veeam-backed workloads that lack a corresponding active contract
|
||||
|
||||
## Open Questions
|
||||
|
||||
1. **VSPC API Key Permissions:** What permission level is needed for the API key? Read-only access to all organizations?
|
||||
- *Recommendation:* Create an API key with `rest` scope and `isReadAccessOnly: true`
|
||||
|
||||
2. **Session History Depth:** How many days of job session history should we sync and retain?
|
||||
- *Recommendation:* Sync last 30 days, retain 90 days, purge older records
|
||||
|
||||
3. **Self-Signed Certificates:** Does the VSPC instance use a self-signed SSL certificate?
|
||||
- *Recommendation:* Support `NODE_TLS_REJECT_UNAUTHORIZED` env var; document in setup guide
|
||||
|
||||
4. **VSPC Version Compatibility:** Is the VSPC instance running v9.1 (REST API 3.6.1) or a different version?
|
||||
- *Recommendation:* Target v3 API which is stable across recent VSPC versions
|
||||
|
||||
5. **Unprotected Machine Detection:** How should "unprotected" be defined — machines with no backup job, or machines whose last backup is older than X hours?
|
||||
- *Recommendation:* Both — flag machines with no job AND machines with stale backups (configurable threshold, default 24h)
|
||||
|
||||
6. **Repository Scope:** Should we show all repositories or only those relevant to managed clients?
|
||||
- *Recommendation:* Show all repositories with filtering by backup server
|
||||
|
||||
7. **UDF Field ID Verification:** The backup-type UDF is believed to be ID `29693319`. This needs to be verified against the Autotask API by querying the UDF field definitions for ConfigurationItems.
|
||||
- *Action:* Query `GET /atservicesrest/v1.0/ConfigurationItemUserDefinedFields` or inspect a config item with a known backup UDF value to confirm the field ID and name
|
||||
|
||||
8. **Contract Active Status Value:** What is the numeric value for "Active" contract status in Autotask?
|
||||
- *Action:* Query the Autotask picklist for contract statuses to determine the correct numeric value
|
||||
|
||||
9. **Hostname Matching Accuracy:** Config item `reference_title` may not always match the Veeam workload `name` exactly. What fallback matching strategies should be used?
|
||||
- *Recommendation:* Try `reference_title`, then `rmmDeviceAuditHostname`, then `serial_number`. Allow manual override mapping in a future iteration
|
||||
|
||||
10. **UDF Values Completeness:** Are "Server Image", "Workstation Image", and "Workstation File Based" the only backup UDF values, or are there others?
|
||||
- *Action:* Query Autotask for the UDF picklist values to get the complete list
|
||||
|
||||
## Implementation Notes for Developers
|
||||
|
||||
### Getting Started
|
||||
1. Review existing Autotask sync service (`sync-service.ts`, `entity-sync.ts`) as the primary reference pattern
|
||||
2. Review VSPC REST API documentation: https://helpcenter.veeam.com/references/vac/9.1/rest/3.6.1/tag/SectionAbout
|
||||
3. Set up VSPC API key with read-only REST access
|
||||
4. Test API connectivity using curl or Postman before coding
|
||||
5. Run the database migration to create Veeam tables
|
||||
|
||||
### Sync Implementation Order
|
||||
1. Implement `veeam-client.ts` with authentication and basic GET requests
|
||||
2. Implement organization sync first (simplest entity, needed for FK references)
|
||||
3. Add backup servers and repositories
|
||||
4. Add backup jobs and job sessions
|
||||
5. Add protected workloads and restore points
|
||||
6. Wire up to sync scheduler
|
||||
7. Add `backup_type_udf` column migration and update `mapConfigurationItem()` in entity-mapper
|
||||
8. Run an Autotask sync to populate `backup_type_udf` values
|
||||
9. Implement `veeam-compliance-service.ts` (depends on both Veeam and Autotask data being synced)
|
||||
10. Build the Contract Compliance UI tab
|
||||
|
||||
### Testing Checklist
|
||||
- [ ] Verify API key authentication works
|
||||
- [ ] Test organization fetch and company matching
|
||||
- [ ] Test full sync of all entities
|
||||
- [ ] Test incremental sync (only changed records)
|
||||
- [ ] Test with VSPC API unavailable (graceful failure)
|
||||
- [ ] Test pagination with large datasets (100+ workloads)
|
||||
- [ ] Verify Backup Status page renders correctly with real data
|
||||
- [ ] Verify Backup Status page renders gracefully with no data
|
||||
- [ ] Test company filter and status filter on Backup Status page
|
||||
- [ ] Check database migration runs cleanly on existing schema
|
||||
- [ ] Verify sync scheduler runs Veeam sync on configured schedule
|
||||
- [ ] Verify `backup_type_udf` is populated after Autotask sync
|
||||
- [ ] Test compliance computation with known contracted devices
|
||||
- [ ] Verify "contracted but not backed up" mismatches are correctly identified
|
||||
- [ ] Verify "backed up but not contracted" mismatches are correctly identified
|
||||
- [ ] Test compliance UI tab renders correctly with mismatch data
|
||||
- [ ] Test compliance UI with zero mismatches (all green)
|
||||
- [ ] Verify compliance recomputes after each Veeam sync
|
||||
|
||||
### Code Review Focus Areas
|
||||
- Error handling completeness (VSPC API can be unreliable)
|
||||
- TypeScript type safety for all VSPC API responses
|
||||
- Consistent code style with existing services
|
||||
- Proper logging for debugging sync issues
|
||||
- Performance (batch inserts, avoid N+1 queries)
|
||||
- Database index usage for Backup Status page queries
|
||||
101
tasks/tasks-prd-veeam-integration.md
Normal file
101
tasks/tasks-prd-veeam-integration.md
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
## Relevant Files
|
||||
|
||||
- `lib/services/veeam-client.ts` - VSPC REST API client handling authentication, pagination, filtering, and rate limiting.
|
||||
- `lib/services/veeam-factory.ts` - Singleton factory for the Veeam client instance.
|
||||
- `lib/services/veeam-sync-service.ts` - Sync orchestration service for fetching and persisting Veeam data to PostgreSQL.
|
||||
- `lib/services/veeam-compliance-service.ts` - Contract compliance computation logic (cross-referencing Autotask config items with Veeam workloads).
|
||||
- `lib/types/veeam.ts` - TypeScript type definitions for all Veeam entities and UI models.
|
||||
- `lib/utils/entity-mapper.ts` - Existing entity mapper; needs update to map backup UDF from Autotask config items.
|
||||
- `lib/services/sync-scheduler.ts` - Existing sync scheduler; needs Veeam sync schedule integration.
|
||||
- `migrations/023_create_veeam_tables.sql` - Database migration for all Veeam tables and compliance results table.
|
||||
- `migrations/024_add_backup_type_udf.sql` - Database migration to add `backup_type_udf` column to `configuration_items`.
|
||||
- `app/api/veeam/backup-status/route.ts` - API endpoint for backup summary statistics.
|
||||
- `app/api/veeam/companies/route.ts` - API endpoint for company-level backup overview.
|
||||
- `app/api/veeam/companies/[companyId]/workloads/route.ts` - API endpoint for per-company protected workloads.
|
||||
- `app/api/veeam/companies/[companyId]/jobs/route.ts` - API endpoint for per-company backup jobs.
|
||||
- `app/api/veeam/companies/[companyId]/sessions/route.ts` - API endpoint for per-company job sessions.
|
||||
- `app/api/veeam/repositories/route.ts` - API endpoint for repository capacity overview.
|
||||
- `app/api/veeam/sync/route.ts` - API endpoint to trigger manual Veeam sync.
|
||||
- `app/api/veeam/compliance/route.ts` - API endpoint for compliance summary and mismatch list.
|
||||
- `app/api/veeam/compliance/[companyId]/route.ts` - API endpoint for per-company compliance details.
|
||||
- `app/backup-status/page.tsx` - Main Backup Status page with tabs for Backup Overview and Contract Compliance.
|
||||
- `components/backup/backup-summary-cards.tsx` - Summary KPI cards component (protected, unprotected, success rate, failed, repo usage).
|
||||
- `components/backup/company-backup-table.tsx` - Company backup overview table with expandable rows.
|
||||
- `components/backup/company-backup-detail.tsx` - Expanded company detail view (workloads, jobs, sessions, compliance).
|
||||
- `components/backup/repository-overview.tsx` - Repository capacity visualization component.
|
||||
- `components/backup/compliance-summary-cards.tsx` - Compliance KPI cards (contracted, matched, missing backup, no contract).
|
||||
- `components/backup/compliance-detail-table.tsx` - Compliance mismatch detail table with filters.
|
||||
|
||||
### Notes
|
||||
|
||||
- Unit tests should typically be placed alongside the code files they are testing (e.g., `veeam-client.ts` and `veeam-client.test.ts` in the same directory).
|
||||
- Use `npx jest [optional/path/to/test/file]` to run tests. Running without a path executes all tests found by the Jest configuration.
|
||||
|
||||
## Tasks
|
||||
|
||||
- [x] 1.0 Database Schema & Migrations
|
||||
- [x] 1.1 Create migration `023_create_veeam_tables.sql` with tables: `veeam_organizations`, `veeam_backup_servers`, `veeam_backup_jobs` (VM jobs), `veeam_backup_agent_jobs` (workstation/physical jobs), `veeam_protected_workloads`, `veeam_repositories`, `veeam_compliance_results`. Note: `veeam_job_sessions` and `veeam_restore_points` were removed — session data (lastRun, lastEndTime, status, bottleneck, failureMessage) is embedded directly on job objects in the VSPC API. Agent jobs (753 total) were added as a separate table since they have a different schema than backup server jobs (182 total).
|
||||
- [x] 1.2 Add `veeam_compliance_results` table to the same migration (included in 023_create_veeam_tables.sql)
|
||||
- [x] 1.3 Add indexes on `organization_uid`, `company_id`, `status`, `synced_at`, `last_run` across Veeam tables; indexes on `veeam_compliance_results.company_id`, `mismatch_type`, and `computed_at`
|
||||
- [x] 1.4 Create migration `024_add_backup_type_udf.sql` to add `backup_type_udf` (VARCHAR, nullable) column to the existing `configuration_items` table, with an index on `backup_type_udf`
|
||||
- [x] 1.5 Test that both migrations run cleanly against the existing database schema without errors — verified 7 veeam_* tables created and backup_type_udf column added to configuration_items
|
||||
- [x] 2.0 VSPC API Client & TypeScript Types
|
||||
- [x] 2.1 Create `/lib/types/veeam.ts` with interfaces for VSPC API response types (`VspcOrganization`, `VspcBackupServer`, `VspcBackupJob`, `VspcBackupAgentJob`, `VspcProtectedWorkload`, `VspcRepository`), DB entity types (`VeeamOrganization`, `VeeamBackupServer`, `VeeamBackupJob`, `VeeamBackupAgentJob`, `VeeamProtectedWorkload`, `VeeamRepository`, `VeeamComplianceResult`), and UI types (`VeeamBackupStatusSummary`, `VeeamCompanyBackupOverview`, `VeeamComplianceSummary`). Updated to match actual API shapes.
|
||||
- [x] 2.2 Create `/lib/services/veeam-client.ts` with Bearer token auth, base URL from `VEEAM_VSPC_URL` env var
|
||||
- [x] 2.3 Implement `fetchAllPages<T>()` generic paginated GET with `offset`/`limit`, auto-fetches all pages
|
||||
- [x] 2.4 Implement VSPC `filter` query parameter support via optional filter arg on `fetchAllPages`
|
||||
- [x] 2.5 Add rate limiting (100 req/min with wait) and error handling with descriptive logging
|
||||
- [x] 2.6 Implement data-fetching methods: `getOrganizations()`, `getBackupServers()`, `getBackupJobs()`, `getBackupAgentJobs()`, `getProtectedWorkloads()`, `getRepositories()`, `testConnection()`. Note: `getJobSessions()` and `getRestorePoints()` removed — data is embedded in job/workload objects.
|
||||
- [x] 2.7 Create `/lib/services/veeam-factory.ts` singleton factory following `auvik-factory.ts` pattern
|
||||
- [x] 2.8 N/A — no `.env.example` exists; env vars already in `.env`
|
||||
- [x] 2.9 Tested: connection successful, 58 organizations fetched, pagination working correctly
|
||||
- [x] 3.0 Veeam Sync Service & Scheduler Integration
|
||||
- [x] 3.1 Created `/lib/services/veeam-sync-service.ts` with full/incremental sync, entity-level error handling, sync history recording
|
||||
- [x] 3.2 Full sync implemented: orgs → servers → repos → backup jobs → agent jobs → workloads. FK safety checks prevent constraint violations.
|
||||
- [x] 3.3 Incremental sync implemented (same as full since VSPC API lacks last-modified filtering; upserts make unchanged rows no-ops)
|
||||
- [x] 3.4 Company matching: parses companyId string, validates against companies table, sets null if no match
|
||||
- [x] 3.5 Sync history recorded in sync_history table with entity_type='veeam'
|
||||
- [x] 3.6 Pagination handled by VeeamClient.fetchAllPages() — auto-fetches all pages per entity
|
||||
- [x] 3.7 Added veeam-incremental (*/30 * * * *) and veeam-full (0 2 * * *) schedules to sync-scheduler.ts. Updated CHECK constraint and ScheduleConfig type.
|
||||
- [x] 3.8 Veeam sync schedules visible in Admin Sync page via existing sync_schedules table
|
||||
- [x] 3.9 Created POST /api/veeam/sync (triggers sync) and GET /api/veeam/sync (status check)
|
||||
- [x] 3.10 Tested: full sync completed in 2.8s — 58 orgs, 47 servers, 209 repos, 182 jobs, 753 agent jobs, 157 workloads = 1,406 records
|
||||
- [x] 4.0 Autotask Backup UDF Sync
|
||||
- [x] 4.1 UDF field ID 29693319 confirmed from PRD; mapper searches by name 'Backup Type' or ID '29693319'
|
||||
- [x] 4.2 Autotask queryEntity returns userDefinedFields by default for ConfigurationItems (verified in types/autotask.ts)
|
||||
- [x] 4.3 Updated mapConfigurationItem() to extract backup UDF from userDefinedFields array and map to backup_type_udf
|
||||
- [x] 4.4 Migration 024 already applied (Task 1.5)
|
||||
- [ ] 4.5 Pending: trigger Autotask config items sync to populate backup_type_udf values (requires Autotask sync run)
|
||||
- [ ] 4.6 Pending: query Autotask picklist for complete UDF values (requires Autotask API call)
|
||||
- [ ] 4.7 Contract status = 1 used for Active in compliance queries (standard Autotask value)
|
||||
- [x] 5.0 Backup Status API Endpoints
|
||||
- [x] 5.1 Created GET /api/veeam/backup-status — summary stats with 24h success rate, failed/warning counts
|
||||
- [x] 5.2 Created GET /api/veeam/companies — company-level overview with aggregated job counts and statuses
|
||||
- [x] 5.3 Created GET /api/veeam/companies/[companyId]/workloads — per-company protected workloads
|
||||
- [x] 5.4 Created GET /api/veeam/companies/[companyId]/jobs — server jobs + agent jobs per company
|
||||
- [x] 5.5 N/A — sessions are embedded in job objects; jobs endpoint returns last run/status/duration
|
||||
- [x] 5.6 Created GET /api/veeam/repositories — with backup server name join
|
||||
- [x] 5.7 Created POST/GET /api/veeam/sync — trigger sync and check status
|
||||
- [x] 5.8 All endpoints return graceful empty arrays/objects on error via try/catch
|
||||
- [ ] 5.9 Pending: test endpoints with real synced data via browser
|
||||
- [x] 6.0 Backup Status Page & UI Components
|
||||
- [x] 6.1 Created backup-summary-cards.tsx — 5 KPI cards: Protected Workloads, Total Jobs, 24h Success Rate, Failed Jobs, Warnings
|
||||
- [x] 6.2 Created company-backup-table.tsx — filterable/searchable table with expandable rows, status badges
|
||||
- [x] 6.3 Created company-backup-detail.tsx — expanded view with workloads, jobs (server+agent), compliance issues
|
||||
- [ ] 6.4 Pending: repository-overview.tsx with capacity progress bars (repos have minimal data from API)
|
||||
- [x] 6.5 Created /app/backup-status/page.tsx — tabs for Backup Overview + Contract Compliance, sync button, stale warning
|
||||
- [x] 6.6 Filters: search by company name, filter by status (All/Success/Warning/Failed)
|
||||
- [x] 6.7 Added HardDrive icon + Backup Status link to app-navigation.tsx
|
||||
- [ ] 6.8 Pending: verify page renders with real data via browser
|
||||
- [ ] 6.9 Pending: verify responsive layout
|
||||
- [x] 7.0 Contract Compliance Engine & UI
|
||||
- [x] 7.1 Created GET /api/veeam/compliance — summary + mismatch list with company names
|
||||
- [x] 7.2 Created GET /api/veeam/compliance/[companyId] — per-company compliance details
|
||||
- [x] 7.3 Created veeam-compliance-service.ts — matches config items (backup_type_udf + company active contract) against Veeam workloads by hostname. Note: uses company-level contract matching since config_items don't have direct contract_id.
|
||||
- [x] 7.4 Compliance results stored via DELETE + INSERT in veeam_compliance_results; totals logged
|
||||
- [x] 7.5 Compliance auto-runs after successful Veeam sync (wired in veeam-sync-service.ts)
|
||||
- [x] 7.6 Created compliance-summary-cards.tsx — 4 KPI cards
|
||||
- [x] 7.7 Created compliance-detail-table.tsx — filterable by mismatch type and search
|
||||
- [x] 7.8 Compliance tab integrated into backup-status/page.tsx with badge count
|
||||
- [x] 7.9 Company backup detail shows compliance issues section when mismatches exist
|
||||
- [ ] 7.10 Pending: test compliance with known data after Autotask sync populates backup_type_udf
|
||||
Loading…
Add table
Add a link
Reference in a new issue