wulf-pulse/tasks/prd-veeam-integration.md
lorentz 5dc7a7e66b 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
2026-02-11 21:04:28 -05:00

33 KiB

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

// 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

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