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:
lorentz 2026-02-11 21:04:28 -05:00
parent a1e0e7c7c0
commit 5dc7a7e66b
27 changed files with 3408 additions and 7 deletions

369
lib/types/veeam.ts Normal file
View file

@ -0,0 +1,369 @@
/**
* Veeam Service Provider Console (VSPC) Type Definitions
* Based on VSPC REST API v3 response shapes
*/
// ============================================================================
// VSPC API Response Types (raw API shapes)
// ============================================================================
export interface VspcPagingInfo {
total: number;
count: number;
offset: number;
}
export interface VspcMeta {
pagingInfo: VspcPagingInfo;
}
export interface VspcListResponse<T> {
meta: VspcMeta;
data: T[];
}
export interface VspcSingleResponse<T> {
data: T;
}
// ============================================================================
// VSPC Entity Types (API response shapes)
// ============================================================================
export interface VspcOrganization {
instanceUid: string;
name: string;
alias: string | null;
type: string; // 'Provider' | 'Company'
taxId: string;
email: string | null;
phone: string;
country: number | null;
state: number | null;
countryName: string;
regionName: string;
city: string;
street: string;
locationAdmin0Code: string;
locationAdmin1Code: string;
locationAdmin2Code: string;
notes: string;
zipCode: string;
website: string;
veeamTenantId: string;
companyId: string; // Autotask Company ID (string, needs parseInt)
}
export interface VspcBackupServer {
instanceUid: string;
name: string;
organizationUid: string;
locationUid: string;
managementAgentUid: string;
version: string;
displayVersion: string;
installationUid: string;
backupServerRoleType: string; // 'Client' | 'Hosted' | etc.
status: string; // 'Healthy' | 'Warning' | 'Error'
inHighAvailabilityCluster: boolean;
}
export interface VspcBackupJobSchedule {
startDateTime: string;
startDateTimeUtc: string;
dailyScheduleOptions: unknown | null;
monthlyScheduleOptions: unknown | null;
periodicallyScheduleOptions: unknown | null;
backupWindowOptions: unknown | null;
continuousScheduleEnabled: boolean;
chainingOptions: unknown | null;
}
export interface VspcBackupJob {
instanceUid: string;
uniqueUid: string;
name: string;
description: string;
createdBy: string;
creationTime: string;
backupServerUid: string;
locationUid: string;
siteUid: string;
organizationUid: string;
mappedOrganizationUid: string;
status: string; // 'Success' | 'Warning' | 'Failed' | 'Running' | 'Idle' | 'None'
type: string; // 'BackupVm' | 'SimpleBackupCopy' | 'Replica' | etc.
lastRun: string | null;
lastEndTime: string | null;
lastDuration: number; // seconds
processingRate: number;
avgDuration: number;
transferredData: number; // bytes
backupChainSize: number; // bytes
bottleneck: string; // 'None' | 'Source' | 'Target' | 'Network' | 'Proxy'
isEnabled: boolean;
scheduleType: string; // 'Continuously' | 'Periodically' | 'Daily' | etc.
schedule: VspcBackupJobSchedule;
failureMessage: string | null;
targetType: string; // 'Local' | 'Cloud'
destination: string;
retentionLimit: number;
retentionLimitType: string; // 'Days' | 'RestorePoints'
isGfsOptionEnabled: boolean;
lastSessionTasks: unknown[];
}
export interface VspcBackupAgentJob {
instanceUid: string;
originalUid: string;
backupAgentUid: string;
organizationUid: string;
name: string;
description: string;
configUid: string;
systemType: string; // 'Windows' | 'Linux' | 'Mac'
backupPolicyUid: string;
backupPolicyName: string;
backupPolicyAssignStatus: string; // 'Success' | 'Warning' | 'Failed'
backupPolicyFailureMessage: string | null;
status: string; // 'Success' | 'Warning' | 'Failed' | 'Running' | 'None'
operationMode: string; // 'Workstation' | 'Server'
destination: string;
restorePoints: number;
lastRun: string | null;
lastEndTime: string | null;
lastDuration: number; // seconds
nextRun: string | null;
avgDuration: number;
backupMode: string; // 'File' | 'EntireComputer' | 'Volume'
targetType: string; // 'CloudRepository' | 'Local'
isEnabled: boolean;
scheduleType: string; // 'Daily' | 'Periodically' | etc.
scheduleDisplayName: string;
lastModifiedDate: string | null;
lastModifiedBy: string | null;
failureMessage: string | null;
backedUpSize: number; // bytes
freeSpace: number; // bytes
}
export interface VspcProtectedWorkload {
instanceUid: string;
backupServerUid: string;
organizationUid: string;
name: string;
hierarchyRef: string;
parentHostRef: string;
objectUid: string;
ipAddresses: string[];
provisionedSourceSize: number; // bytes
usedSourceSize: number; // bytes
totalRestorePointSize: number; // bytes
latestRestorePointSize: number; // bytes
restorePoints: number;
latestRestorePointDate: string | null;
jobUid: string;
malwareState: string; // 'Unverified' | 'Clean' | 'Suspicious' | 'Infected'
immutable: boolean;
}
export interface VspcRepository {
instanceUid: string;
name: string;
backupServerUid: string;
capacityBytes?: number;
freeSpaceBytes?: number;
usedSpaceBytes?: number;
repositoryType?: string;
_embedded: unknown | null;
}
// ============================================================================
// Database Entity Types (PostgreSQL row shapes)
// ============================================================================
export interface VeeamOrganization {
instance_uid: string;
name: string;
type: string | null;
company_id: number | null;
tax_id: string | null;
email: string | null;
phone: string | null;
country: string | null;
state: string | null;
city: string | null;
street: string | null;
zip_code: string | null;
website: string | null;
notes: string | null;
synced_at: Date;
created_at: Date;
updated_at: Date;
}
export interface VeeamBackupServer {
instance_uid: string;
name: string;
organization_uid: string | null;
version: string | null;
display_version: string | null;
status: string | null;
backup_server_role_type: string | null;
installation_uid: string | null;
location_uid: string | null;
management_agent_uid: string | null;
synced_at: Date;
created_at: Date;
updated_at: Date;
}
export interface VeeamBackupJob {
instance_uid: string;
unique_uid: string | null;
name: string;
description: string | null;
backup_server_uid: string | null;
organization_uid: string | null;
status: string | null;
type: string | null;
last_run: Date | null;
last_end_time: Date | null;
last_duration: number | null;
processing_rate: number | null;
avg_duration: number | null;
transferred_data: number | null;
backup_chain_size: number | null;
bottleneck: string | null;
is_enabled: boolean;
schedule_type: string | null;
failure_message: string | null;
target_type: string | null;
destination: string | null;
retention_limit: number | null;
retention_limit_type: string | null;
is_gfs_option_enabled: boolean;
synced_at: Date;
created_at: Date;
updated_at: Date;
}
export interface VeeamBackupAgentJob {
instance_uid: string;
original_uid: string | null;
backup_agent_uid: string | null;
organization_uid: string | null;
name: string;
description: string | null;
config_uid: string | null;
system_type: string | null;
backup_policy_uid: string | null;
backup_policy_name: string | null;
backup_policy_assign_status: string | null;
backup_policy_failure_message: string | null;
status: string | null;
operation_mode: string | null;
destination: string | null;
restore_points: number | null;
last_run: Date | null;
last_end_time: Date | null;
last_duration: number | null;
next_run: Date | null;
avg_duration: number | null;
backup_mode: string | null;
target_type: string | null;
is_enabled: boolean;
schedule_type: string | null;
failure_message: string | null;
backed_up_size: number | null;
free_space: number | null;
synced_at: Date;
created_at: Date;
updated_at: Date;
}
export interface VeeamProtectedWorkload {
instance_uid: string;
name: string;
backup_server_uid: string | null;
organization_uid: string | null;
job_uid: string | null;
ip_addresses: string | null; // JSON string of IP array
provisioned_source_size: number | null;
used_source_size: number | null;
total_restore_point_size: number | null;
latest_restore_point_size: number | null;
restore_points: number | null;
latest_restore_point_date: Date | null;
malware_state: string | null;
immutable: boolean;
synced_at: Date;
created_at: Date;
updated_at: Date;
}
export interface VeeamRepository {
instance_uid: string;
name: string;
backup_server_uid: string | null;
capacity_bytes: number | null;
free_space_bytes: number | null;
used_space_bytes: number | null;
repository_type: string | null;
synced_at: Date;
created_at: Date;
updated_at: Date;
}
export interface VeeamComplianceResult {
id: number;
company_id: number | null;
configuration_item_id: number | null;
veeam_workload_uid: string | null;
mismatch_type: 'contracted_not_backed_up' | 'backed_up_not_contracted';
backup_type_udf: string | null;
device_name: string;
contract_name: string | null;
veeam_workload_name: string | null;
computed_at: Date;
}
// ============================================================================
// UI / Aggregation Types
// ============================================================================
export interface VeeamBackupStatusSummary {
totalProtectedWorkloads: number;
unprotectedWorkloads: number;
successRate24h: number; // percentage 0-100
failedJobs24h: number;
totalRepositoryCapacityBytes: number;
totalRepositoryUsedBytes: number;
repositoryUsagePercent: number;
lastSyncAt: Date | null;
totalBackupServerJobs: number;
totalBackupAgentJobs: number;
}
export interface VeeamCompanyBackupOverview {
companyId: number;
companyName: string;
organizationUid: string;
protectedWorkloadCount: number;
unprotectedWorkloadCount: number;
lastJobStatus: string | null; // 'Success' | 'Warning' | 'Failed'
lastSuccessfulBackup: Date | null;
oldestRestorePointAge: number | null; // hours
backupServerJobCount: number;
backupAgentJobCount: number;
failedJobCount: number;
warningJobCount: number;
}
export interface VeeamComplianceSummary {
totalContractedDevices: number;
matchedDevices: number;
contractedNotBackedUp: number;
backedUpNotContracted: number;
computedAt: Date | null;
}