2025-11-19 14:18:16 -05:00
|
|
|
/**
|
|
|
|
|
* Entity Sync Service
|
|
|
|
|
* Handles syncing individual entity types from Autotask to PostgreSQL
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
import { AutotaskClient } from './autotask-client';
|
|
|
|
|
import { autotaskRateLimiter } from './rate-limiter';
|
|
|
|
|
import postgresClient from './postgres-client';
|
|
|
|
|
import { EntityType } from '../types/sync';
|
|
|
|
|
import { mapAutotaskToDatabase, mapAutotaskBatch } from '../utils/entity-mapper';
|
|
|
|
|
import { bulkUpsertRecords, getLastSyncTime, softDeleteMissingRecords } from '../utils/db-helpers';
|
|
|
|
|
import { syncProgressTracker } from './sync-progress-tracker';
|
|
|
|
|
import {
|
|
|
|
|
getAutotaskEntityName,
|
|
|
|
|
buildIncrementalFilter,
|
|
|
|
|
buildActiveFilter,
|
|
|
|
|
buildDateRangeFilter,
|
|
|
|
|
buildContractsFilter,
|
2026-03-11 09:34:51 -04:00
|
|
|
buildContractServicesFilter,
|
2025-11-19 14:18:16 -05:00
|
|
|
buildProjectsFilter,
|
feat: add project_phases entity sync with task project_id backfill
The Autotask Tasks bulk API does not return projectID in its response,
causing all tasks.project_id to be NULL. This fixes it by:
- Adding project_phases as a synced entity (Autotask endpoint: /Phases)
- Migration 059: project_phases table with project_id, phase_number,
estimated_hours, start/due dates, parent_phase_id, is_scheduled
- EntityType.PROJECT_PHASES added to all sync maps and dependency graph
(depends on PROJECTS, runs before TASKS in sync order)
- buildProjectPhasesFilter: Phases endpoint requires a filter (id > 0)
- mapProjectPhase: maps Autotask field names to DB columns
- Post-sync backfill in syncEntity: after each project_phases sync,
UPDATE tasks SET project_id = pp.project_id FROM project_phases pp
JOIN projects p WHERE tasks.phase_id = pp.id
Only backfills where the project exists in our DB (FK constraint on
tasks.project_id; archived projects are skipped gracefully)
Result: 2,455 of 4,966 tasks now have project_id populated. Tasks
belonging to archived/completed projects have phase_id resolvable via
project_phases even when project_id remains NULL.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-24 13:57:33 -04:00
|
|
|
buildProjectPhasesFilter,
|
2025-11-19 14:18:16 -05:00
|
|
|
buildTimeEntriesFilter,
|
2026-01-24 08:09:10 -05:00
|
|
|
buildBillingItemsFilter,
|
2025-11-19 14:18:16 -05:00
|
|
|
getTableName
|
|
|
|
|
} from '../utils/sync-helpers';
|
feat: implement structured logging for sync operations
- Add comprehensive structured logging utility (lib/utils/sync-logger.ts)
- Log levels: DEBUG, INFO, WARN, ERROR
- Automatic error categorization (NETWORK_ERROR, AUTH_ERROR, DATABASE_ERROR, etc.)
- Phase tracking (INITIALIZING, FETCHING, MAPPING, VALIDATING, UPSERTING, DELETING, COMPLETING)
- Contextual metadata (syncId, entityType, phase, duration, record counts)
- Timing helpers for operations
- Update sync-service.ts with structured logging
- Replace console.log/error with structured logger
- Consistent error categorization across all error paths
- Fix swallowed errors in sync history updates
- Add child loggers for entity-specific operations
- Update entity-sync.ts with structured logging
- Complete phase tracking throughout sync lifecycle
- Detailed context for warnings and errors
- Update chunked sync methods with structured logging
- Update picklist sync methods (issue types, sub-issue types)
- Better debugging info with timing and sample data
- Add sync failure analysis script (scripts/analyze-sync-failures.ts)
- Query sync history by date range, entity type, or status
- Generate failure summaries by entity
- Automatic error categorization
- Calculate success rates and statistics
- Display detailed sync records with timing
- Add comprehensive documentation (docs/SYNC_LOGGING_IMPROVEMENTS.md)
- Usage guide and examples
- Migration guide for developers
- Before/after comparisons
This addresses inconsistent logging and improves debugging capabilities for sync operations.
2026-01-23 08:02:02 -05:00
|
|
|
import { createSyncLogger, SyncPhase, categorizeError } from '../utils/sync-logger';
|
2025-11-19 14:18:16 -05:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Entity Sync Result
|
|
|
|
|
*/
|
|
|
|
|
export interface EntitySyncStats {
|
|
|
|
|
recordsAdded: number;
|
|
|
|
|
recordsUpdated: number;
|
|
|
|
|
recordsDeleted: number;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Entity Sync Service Class
|
|
|
|
|
*/
|
|
|
|
|
export class EntitySyncService {
|
|
|
|
|
private autotaskClient: AutotaskClient;
|
|
|
|
|
private cachedValidResourceIds?: Set<number>;
|
|
|
|
|
private cachedValidContactIds?: Set<number>;
|
feat: implement structured logging for sync operations
- Add comprehensive structured logging utility (lib/utils/sync-logger.ts)
- Log levels: DEBUG, INFO, WARN, ERROR
- Automatic error categorization (NETWORK_ERROR, AUTH_ERROR, DATABASE_ERROR, etc.)
- Phase tracking (INITIALIZING, FETCHING, MAPPING, VALIDATING, UPSERTING, DELETING, COMPLETING)
- Contextual metadata (syncId, entityType, phase, duration, record counts)
- Timing helpers for operations
- Update sync-service.ts with structured logging
- Replace console.log/error with structured logger
- Consistent error categorization across all error paths
- Fix swallowed errors in sync history updates
- Add child loggers for entity-specific operations
- Update entity-sync.ts with structured logging
- Complete phase tracking throughout sync lifecycle
- Detailed context for warnings and errors
- Update chunked sync methods with structured logging
- Update picklist sync methods (issue types, sub-issue types)
- Better debugging info with timing and sample data
- Add sync failure analysis script (scripts/analyze-sync-failures.ts)
- Query sync history by date range, entity type, or status
- Generate failure summaries by entity
- Automatic error categorization
- Calculate success rates and statistics
- Display detailed sync records with timing
- Add comprehensive documentation (docs/SYNC_LOGGING_IMPROVEMENTS.md)
- Usage guide and examples
- Migration guide for developers
- Before/after comparisons
This addresses inconsistent logging and improves debugging capabilities for sync operations.
2026-01-23 08:02:02 -05:00
|
|
|
private logger = createSyncLogger({ component: 'EntitySyncService' });
|
2025-11-19 14:18:16 -05:00
|
|
|
|
|
|
|
|
constructor(autotaskClient: AutotaskClient) {
|
|
|
|
|
this.autotaskClient = autotaskClient;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Sync a single entity type
|
|
|
|
|
* @param entity Entity type to sync
|
|
|
|
|
* @param isIncremental Whether to perform incremental sync
|
|
|
|
|
* @param yearsBack Number of years to look back for time-based entities (default: 2)
|
|
|
|
|
* @returns Sync statistics
|
|
|
|
|
*/
|
|
|
|
|
async syncEntity(
|
|
|
|
|
entity: EntityType,
|
|
|
|
|
isIncremental: boolean = false,
|
|
|
|
|
yearsBack: number = 2,
|
|
|
|
|
syncId?: string
|
|
|
|
|
): Promise<EntitySyncStats> {
|
|
|
|
|
// Route picklist entities to their specific sync methods
|
2026-01-23 17:16:19 -05:00
|
|
|
if (entity === EntityType.STATUSES) {
|
|
|
|
|
return await this.syncStatuses(isIncremental);
|
|
|
|
|
}
|
|
|
|
|
if (entity === EntityType.WORK_TYPES) {
|
|
|
|
|
return await this.syncWorkTypes(isIncremental);
|
|
|
|
|
}
|
2025-11-19 14:18:16 -05:00
|
|
|
if (entity === EntityType.ISSUE_TYPES) {
|
|
|
|
|
return await this.syncIssueTypes(isIncremental);
|
|
|
|
|
}
|
|
|
|
|
if (entity === EntityType.SUB_ISSUE_TYPES) {
|
|
|
|
|
return await this.syncSubIssueTypes(isIncremental);
|
|
|
|
|
}
|
2026-02-20 10:28:15 -05:00
|
|
|
if (entity === EntityType.QUEUES) {
|
|
|
|
|
return await this.syncQueues(isIncremental);
|
|
|
|
|
}
|
|
|
|
|
if (entity === EntityType.PRIORITIES) {
|
|
|
|
|
return await this.syncPriorities(isIncremental);
|
|
|
|
|
}
|
|
|
|
|
if (entity === EntityType.TICKET_CATEGORIES) {
|
|
|
|
|
return await this.syncTicketCategories(isIncremental);
|
|
|
|
|
}
|
feat: Display Settings UI + Company Category/Type sync
- Add /admin/display-settings page with Kiosk and Mobile sections
- Company category checkbox filter + excluded companies searchable multi-select
- New DB tables: company_categories, company_types (migration 064)
- Sync COMPANY_CATEGORIES via CompanyCategories entity (id/name/isActive)
- Sync COMPANY_TYPES via Companies.companyType picklist
- Add to EntityType, ENTITY_DEPENDENCIES, sync-helpers, entity-mapper, entity-sync
- New API routes: /api/admin/display-settings (GET/POST), /api/data/company-categories, /api/data/companies-list
- Update all 4 routes (kiosk/stats, kiosk/activity, mobile/tickets, mobile/dashboard)
to filter by kiosk_settings company_category_ids + excluded_company_ids
- Add Display Settings nav link (SlidersHorizontal icon) to Admin menu
- Seed kiosk_settings: kiosk_company_category_ids=1, mobile_company_category_ids=1
2026-04-06 09:03:19 -04:00
|
|
|
if (entity === EntityType.COMPANY_CATEGORIES) {
|
|
|
|
|
return await this.syncCompanyCategories(isIncremental);
|
|
|
|
|
}
|
|
|
|
|
if (entity === EntityType.COMPANY_TYPES) {
|
|
|
|
|
return await this.syncCompanyTypes(isIncremental);
|
|
|
|
|
}
|
2025-11-19 14:18:16 -05:00
|
|
|
|
|
|
|
|
const trackingId = syncId || `${entity}_${Date.now()}`;
|
feat: implement structured logging for sync operations
- Add comprehensive structured logging utility (lib/utils/sync-logger.ts)
- Log levels: DEBUG, INFO, WARN, ERROR
- Automatic error categorization (NETWORK_ERROR, AUTH_ERROR, DATABASE_ERROR, etc.)
- Phase tracking (INITIALIZING, FETCHING, MAPPING, VALIDATING, UPSERTING, DELETING, COMPLETING)
- Contextual metadata (syncId, entityType, phase, duration, record counts)
- Timing helpers for operations
- Update sync-service.ts with structured logging
- Replace console.log/error with structured logger
- Consistent error categorization across all error paths
- Fix swallowed errors in sync history updates
- Add child loggers for entity-specific operations
- Update entity-sync.ts with structured logging
- Complete phase tracking throughout sync lifecycle
- Detailed context for warnings and errors
- Update chunked sync methods with structured logging
- Update picklist sync methods (issue types, sub-issue types)
- Better debugging info with timing and sample data
- Add sync failure analysis script (scripts/analyze-sync-failures.ts)
- Query sync history by date range, entity type, or status
- Generate failure summaries by entity
- Automatic error categorization
- Calculate success rates and statistics
- Display detailed sync records with timing
- Add comprehensive documentation (docs/SYNC_LOGGING_IMPROVEMENTS.md)
- Usage guide and examples
- Migration guide for developers
- Before/after comparisons
This addresses inconsistent logging and improves debugging capabilities for sync operations.
2026-01-23 08:02:02 -05:00
|
|
|
const entityLogger = this.logger.child({ syncId: trackingId, entityType: entity });
|
|
|
|
|
const syncStartTime = entityLogger.start(`${entity} sync (${isIncremental ? 'incremental' : 'full'})`);
|
2025-11-19 14:18:16 -05:00
|
|
|
|
|
|
|
|
// Start progress tracking
|
|
|
|
|
syncProgressTracker.startSync(trackingId, entity);
|
feat: implement structured logging for sync operations
- Add comprehensive structured logging utility (lib/utils/sync-logger.ts)
- Log levels: DEBUG, INFO, WARN, ERROR
- Automatic error categorization (NETWORK_ERROR, AUTH_ERROR, DATABASE_ERROR, etc.)
- Phase tracking (INITIALIZING, FETCHING, MAPPING, VALIDATING, UPSERTING, DELETING, COMPLETING)
- Contextual metadata (syncId, entityType, phase, duration, record counts)
- Timing helpers for operations
- Update sync-service.ts with structured logging
- Replace console.log/error with structured logger
- Consistent error categorization across all error paths
- Fix swallowed errors in sync history updates
- Add child loggers for entity-specific operations
- Update entity-sync.ts with structured logging
- Complete phase tracking throughout sync lifecycle
- Detailed context for warnings and errors
- Update chunked sync methods with structured logging
- Update picklist sync methods (issue types, sub-issue types)
- Better debugging info with timing and sample data
- Add sync failure analysis script (scripts/analyze-sync-failures.ts)
- Query sync history by date range, entity type, or status
- Generate failure summaries by entity
- Automatic error categorization
- Calculate success rates and statistics
- Display detailed sync records with timing
- Add comprehensive documentation (docs/SYNC_LOGGING_IMPROVEMENTS.md)
- Usage guide and examples
- Migration guide for developers
- Before/after comparisons
This addresses inconsistent logging and improves debugging capabilities for sync operations.
2026-01-23 08:02:02 -05:00
|
|
|
entityLogger.phase(SyncPhase.INITIALIZING);
|
2025-11-19 14:18:16 -05:00
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
const autotaskEntityName = getAutotaskEntityName(entity);
|
|
|
|
|
let params: any = {};
|
|
|
|
|
|
|
|
|
|
// For incremental sync, filter by last sync time
|
2026-01-26 12:07:52 -05:00
|
|
|
// Note: Companies and Resources don't support date-based filtering in Autotask API
|
feat: Veeam RPO analysis, comparison, ticket analysis + company teams table
- Add Veeam RPO analysis page (/veeam-analysis) and comparison page (/veeam-comparison)
- Add API routes: /api/veeam/rpo-analyze, rpo-comparison, rpo-offline-log, ticket-analysis
- Add veeam-rpo-service.ts enhancements (RPO logic, offline detection, comparison)
- Add veeam-analysis-state.ts and rmm-device-resolver.ts services
- Add migrations 065-068: company_teams, veeam_rpo_offline_log, rpo_comparison_tables, veeam_ticket_analysis
- Add backup-status page updates and nav links for new Veeam pages
- Add scripts: deactivate-cis-for-inactive-companies, workstation category updates
- Add docs: mimecast-api-guide, veeam-backup-alerting-recommendation, workstation-backup-overview, ticket-analyzer-prompt
- Minor: webhook-service, entity-sync, entity-mapper, sync-helpers, sync.ts, middleware.ts updates
2026-04-29 09:16:46 -04:00
|
|
|
const supportsIncremental = entity !== EntityType.COMPANIES && entity !== EntityType.RESOURCES && entity !== EntityType.COMPANY_TEAMS;
|
2026-01-26 12:07:52 -05:00
|
|
|
|
|
|
|
|
if (isIncremental && supportsIncremental) {
|
2025-11-19 14:18:16 -05:00
|
|
|
try {
|
|
|
|
|
const lastSyncTime = await getLastSyncTime(entity);
|
|
|
|
|
if (lastSyncTime) {
|
|
|
|
|
params.filter = buildIncrementalFilter(entity, lastSyncTime);
|
feat: implement structured logging for sync operations
- Add comprehensive structured logging utility (lib/utils/sync-logger.ts)
- Log levels: DEBUG, INFO, WARN, ERROR
- Automatic error categorization (NETWORK_ERROR, AUTH_ERROR, DATABASE_ERROR, etc.)
- Phase tracking (INITIALIZING, FETCHING, MAPPING, VALIDATING, UPSERTING, DELETING, COMPLETING)
- Contextual metadata (syncId, entityType, phase, duration, record counts)
- Timing helpers for operations
- Update sync-service.ts with structured logging
- Replace console.log/error with structured logger
- Consistent error categorization across all error paths
- Fix swallowed errors in sync history updates
- Add child loggers for entity-specific operations
- Update entity-sync.ts with structured logging
- Complete phase tracking throughout sync lifecycle
- Detailed context for warnings and errors
- Update chunked sync methods with structured logging
- Update picklist sync methods (issue types, sub-issue types)
- Better debugging info with timing and sample data
- Add sync failure analysis script (scripts/analyze-sync-failures.ts)
- Query sync history by date range, entity type, or status
- Generate failure summaries by entity
- Automatic error categorization
- Calculate success rates and statistics
- Display detailed sync records with timing
- Add comprehensive documentation (docs/SYNC_LOGGING_IMPROVEMENTS.md)
- Usage guide and examples
- Migration guide for developers
- Before/after comparisons
This addresses inconsistent logging and improves debugging capabilities for sync operations.
2026-01-23 08:02:02 -05:00
|
|
|
entityLogger.info(`Incremental sync from ${lastSyncTime.toISOString()}`);
|
2025-11-19 14:18:16 -05:00
|
|
|
} else {
|
feat: implement structured logging for sync operations
- Add comprehensive structured logging utility (lib/utils/sync-logger.ts)
- Log levels: DEBUG, INFO, WARN, ERROR
- Automatic error categorization (NETWORK_ERROR, AUTH_ERROR, DATABASE_ERROR, etc.)
- Phase tracking (INITIALIZING, FETCHING, MAPPING, VALIDATING, UPSERTING, DELETING, COMPLETING)
- Contextual metadata (syncId, entityType, phase, duration, record counts)
- Timing helpers for operations
- Update sync-service.ts with structured logging
- Replace console.log/error with structured logger
- Consistent error categorization across all error paths
- Fix swallowed errors in sync history updates
- Add child loggers for entity-specific operations
- Update entity-sync.ts with structured logging
- Complete phase tracking throughout sync lifecycle
- Detailed context for warnings and errors
- Update chunked sync methods with structured logging
- Update picklist sync methods (issue types, sub-issue types)
- Better debugging info with timing and sample data
- Add sync failure analysis script (scripts/analyze-sync-failures.ts)
- Query sync history by date range, entity type, or status
- Generate failure summaries by entity
- Automatic error categorization
- Calculate success rates and statistics
- Display detailed sync records with timing
- Add comprehensive documentation (docs/SYNC_LOGGING_IMPROVEMENTS.md)
- Usage guide and examples
- Migration guide for developers
- Before/after comparisons
This addresses inconsistent logging and improves debugging capabilities for sync operations.
2026-01-23 08:02:02 -05:00
|
|
|
entityLogger.info('No previous sync found, performing full sync');
|
2025-11-19 14:18:16 -05:00
|
|
|
}
|
|
|
|
|
} catch (error) {
|
feat: implement structured logging for sync operations
- Add comprehensive structured logging utility (lib/utils/sync-logger.ts)
- Log levels: DEBUG, INFO, WARN, ERROR
- Automatic error categorization (NETWORK_ERROR, AUTH_ERROR, DATABASE_ERROR, etc.)
- Phase tracking (INITIALIZING, FETCHING, MAPPING, VALIDATING, UPSERTING, DELETING, COMPLETING)
- Contextual metadata (syncId, entityType, phase, duration, record counts)
- Timing helpers for operations
- Update sync-service.ts with structured logging
- Replace console.log/error with structured logger
- Consistent error categorization across all error paths
- Fix swallowed errors in sync history updates
- Add child loggers for entity-specific operations
- Update entity-sync.ts with structured logging
- Complete phase tracking throughout sync lifecycle
- Detailed context for warnings and errors
- Update chunked sync methods with structured logging
- Update picklist sync methods (issue types, sub-issue types)
- Better debugging info with timing and sample data
- Add sync failure analysis script (scripts/analyze-sync-failures.ts)
- Query sync history by date range, entity type, or status
- Generate failure summaries by entity
- Automatic error categorization
- Calculate success rates and statistics
- Display detailed sync records with timing
- Add comprehensive documentation (docs/SYNC_LOGGING_IMPROVEMENTS.md)
- Usage guide and examples
- Migration guide for developers
- Before/after comparisons
This addresses inconsistent logging and improves debugging capabilities for sync operations.
2026-01-23 08:02:02 -05:00
|
|
|
const err = error instanceof Error ? error : new Error(String(error));
|
|
|
|
|
entityLogger.error('Failed to get last sync time', {}, err);
|
|
|
|
|
throw new Error(`Failed to determine sync time: ${err.message}`);
|
2025-11-19 14:18:16 -05:00
|
|
|
}
|
2026-01-30 22:50:07 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// For full sync OR entities that don't support incremental, build filters
|
|
|
|
|
if (!isIncremental || (isIncremental && !supportsIncremental)) {
|
|
|
|
|
if (isIncremental && !supportsIncremental) {
|
|
|
|
|
entityLogger.info(`${entity} does not support incremental sync, performing full sync instead`);
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-19 14:18:16 -05:00
|
|
|
const filters: Array<{ field: string; op: string; value: any }> = [];
|
|
|
|
|
|
|
|
|
|
// Special handling for entities that require filters
|
|
|
|
|
if (entity === EntityType.CONTRACTS) {
|
|
|
|
|
filters.push(...buildContractsFilter());
|
feat: implement structured logging for sync operations
- Add comprehensive structured logging utility (lib/utils/sync-logger.ts)
- Log levels: DEBUG, INFO, WARN, ERROR
- Automatic error categorization (NETWORK_ERROR, AUTH_ERROR, DATABASE_ERROR, etc.)
- Phase tracking (INITIALIZING, FETCHING, MAPPING, VALIDATING, UPSERTING, DELETING, COMPLETING)
- Contextual metadata (syncId, entityType, phase, duration, record counts)
- Timing helpers for operations
- Update sync-service.ts with structured logging
- Replace console.log/error with structured logger
- Consistent error categorization across all error paths
- Fix swallowed errors in sync history updates
- Add child loggers for entity-specific operations
- Update entity-sync.ts with structured logging
- Complete phase tracking throughout sync lifecycle
- Detailed context for warnings and errors
- Update chunked sync methods with structured logging
- Update picklist sync methods (issue types, sub-issue types)
- Better debugging info with timing and sample data
- Add sync failure analysis script (scripts/analyze-sync-failures.ts)
- Query sync history by date range, entity type, or status
- Generate failure summaries by entity
- Automatic error categorization
- Calculate success rates and statistics
- Display detailed sync records with timing
- Add comprehensive documentation (docs/SYNC_LOGGING_IMPROVEMENTS.md)
- Usage guide and examples
- Migration guide for developers
- Before/after comparisons
This addresses inconsistent logging and improves debugging capabilities for sync operations.
2026-01-23 08:02:02 -05:00
|
|
|
entityLogger.info('Full sync with status filter for active contracts');
|
2026-03-11 09:34:51 -04:00
|
|
|
} else if (entity === EntityType.CONTRACT_SERVICES) {
|
|
|
|
|
filters.push(...buildContractServicesFilter());
|
|
|
|
|
entityLogger.info('Full sync of all contract services');
|
2025-11-19 14:18:16 -05:00
|
|
|
} else if (entity === EntityType.PROJECTS) {
|
|
|
|
|
filters.push(...buildProjectsFilter());
|
feat: implement structured logging for sync operations
- Add comprehensive structured logging utility (lib/utils/sync-logger.ts)
- Log levels: DEBUG, INFO, WARN, ERROR
- Automatic error categorization (NETWORK_ERROR, AUTH_ERROR, DATABASE_ERROR, etc.)
- Phase tracking (INITIALIZING, FETCHING, MAPPING, VALIDATING, UPSERTING, DELETING, COMPLETING)
- Contextual metadata (syncId, entityType, phase, duration, record counts)
- Timing helpers for operations
- Update sync-service.ts with structured logging
- Replace console.log/error with structured logger
- Consistent error categorization across all error paths
- Fix swallowed errors in sync history updates
- Add child loggers for entity-specific operations
- Update entity-sync.ts with structured logging
- Complete phase tracking throughout sync lifecycle
- Detailed context for warnings and errors
- Update chunked sync methods with structured logging
- Update picklist sync methods (issue types, sub-issue types)
- Better debugging info with timing and sample data
- Add sync failure analysis script (scripts/analyze-sync-failures.ts)
- Query sync history by date range, entity type, or status
- Generate failure summaries by entity
- Automatic error categorization
- Calculate success rates and statistics
- Display detailed sync records with timing
- Add comprehensive documentation (docs/SYNC_LOGGING_IMPROVEMENTS.md)
- Usage guide and examples
- Migration guide for developers
- Before/after comparisons
This addresses inconsistent logging and improves debugging capabilities for sync operations.
2026-01-23 08:02:02 -05:00
|
|
|
entityLogger.info('Full sync with status filter for non-completed projects');
|
feat: add project_phases entity sync with task project_id backfill
The Autotask Tasks bulk API does not return projectID in its response,
causing all tasks.project_id to be NULL. This fixes it by:
- Adding project_phases as a synced entity (Autotask endpoint: /Phases)
- Migration 059: project_phases table with project_id, phase_number,
estimated_hours, start/due dates, parent_phase_id, is_scheduled
- EntityType.PROJECT_PHASES added to all sync maps and dependency graph
(depends on PROJECTS, runs before TASKS in sync order)
- buildProjectPhasesFilter: Phases endpoint requires a filter (id > 0)
- mapProjectPhase: maps Autotask field names to DB columns
- Post-sync backfill in syncEntity: after each project_phases sync,
UPDATE tasks SET project_id = pp.project_id FROM project_phases pp
JOIN projects p WHERE tasks.phase_id = pp.id
Only backfills where the project exists in our DB (FK constraint on
tasks.project_id; archived projects are skipped gracefully)
Result: 2,455 of 4,966 tasks now have project_id populated. Tasks
belonging to archived/completed projects have phase_id resolvable via
project_phases even when project_id remains NULL.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-24 13:57:33 -04:00
|
|
|
} else if (entity === EntityType.PROJECT_PHASES) {
|
|
|
|
|
filters.push(...buildProjectPhasesFilter());
|
|
|
|
|
entityLogger.info('Full sync of all project phases');
|
2025-11-19 14:18:16 -05:00
|
|
|
} else if (entity === EntityType.TIME_ENTRIES) {
|
|
|
|
|
filters.push(...buildTimeEntriesFilter(yearsBack));
|
feat: implement structured logging for sync operations
- Add comprehensive structured logging utility (lib/utils/sync-logger.ts)
- Log levels: DEBUG, INFO, WARN, ERROR
- Automatic error categorization (NETWORK_ERROR, AUTH_ERROR, DATABASE_ERROR, etc.)
- Phase tracking (INITIALIZING, FETCHING, MAPPING, VALIDATING, UPSERTING, DELETING, COMPLETING)
- Contextual metadata (syncId, entityType, phase, duration, record counts)
- Timing helpers for operations
- Update sync-service.ts with structured logging
- Replace console.log/error with structured logger
- Consistent error categorization across all error paths
- Fix swallowed errors in sync history updates
- Add child loggers for entity-specific operations
- Update entity-sync.ts with structured logging
- Complete phase tracking throughout sync lifecycle
- Detailed context for warnings and errors
- Update chunked sync methods with structured logging
- Update picklist sync methods (issue types, sub-issue types)
- Better debugging info with timing and sample data
- Add sync failure analysis script (scripts/analyze-sync-failures.ts)
- Query sync history by date range, entity type, or status
- Generate failure summaries by entity
- Automatic error categorization
- Calculate success rates and statistics
- Display detailed sync records with timing
- Add comprehensive documentation (docs/SYNC_LOGGING_IMPROVEMENTS.md)
- Usage guide and examples
- Migration guide for developers
- Before/after comparisons
This addresses inconsistent logging and improves debugging capabilities for sync operations.
2026-01-23 08:02:02 -05:00
|
|
|
entityLogger.info(`Full sync with dateWorked filter for last ${yearsBack} years`);
|
2026-01-24 08:09:10 -05:00
|
|
|
} else if (entity === EntityType.BILLING_ITEMS) {
|
|
|
|
|
filters.push(...buildBillingItemsFilter(yearsBack));
|
|
|
|
|
entityLogger.info(`Full sync with itemDate filter for last ${yearsBack} years`);
|
2025-11-19 14:18:16 -05:00
|
|
|
} else {
|
|
|
|
|
// Add active filter if applicable
|
|
|
|
|
const activeFilter = buildActiveFilter(entity);
|
|
|
|
|
if (activeFilter) {
|
|
|
|
|
filters.push(...activeFilter);
|
feat: implement structured logging for sync operations
- Add comprehensive structured logging utility (lib/utils/sync-logger.ts)
- Log levels: DEBUG, INFO, WARN, ERROR
- Automatic error categorization (NETWORK_ERROR, AUTH_ERROR, DATABASE_ERROR, etc.)
- Phase tracking (INITIALIZING, FETCHING, MAPPING, VALIDATING, UPSERTING, DELETING, COMPLETING)
- Contextual metadata (syncId, entityType, phase, duration, record counts)
- Timing helpers for operations
- Update sync-service.ts with structured logging
- Replace console.log/error with structured logger
- Consistent error categorization across all error paths
- Fix swallowed errors in sync history updates
- Add child loggers for entity-specific operations
- Update entity-sync.ts with structured logging
- Complete phase tracking throughout sync lifecycle
- Detailed context for warnings and errors
- Update chunked sync methods with structured logging
- Update picklist sync methods (issue types, sub-issue types)
- Better debugging info with timing and sample data
- Add sync failure analysis script (scripts/analyze-sync-failures.ts)
- Query sync history by date range, entity type, or status
- Generate failure summaries by entity
- Automatic error categorization
- Calculate success rates and statistics
- Display detailed sync records with timing
- Add comprehensive documentation (docs/SYNC_LOGGING_IMPROVEMENTS.md)
- Usage guide and examples
- Migration guide for developers
- Before/after comparisons
This addresses inconsistent logging and improves debugging capabilities for sync operations.
2026-01-23 08:02:02 -05:00
|
|
|
entityLogger.info('Full sync with active filter');
|
2025-11-19 14:18:16 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Add date range filter for time-based entities (tickets, tasks, etc.)
|
|
|
|
|
const dateRangeFilter = buildDateRangeFilter(entity, yearsBack);
|
|
|
|
|
if (dateRangeFilter) {
|
|
|
|
|
filters.push(...dateRangeFilter);
|
feat: implement structured logging for sync operations
- Add comprehensive structured logging utility (lib/utils/sync-logger.ts)
- Log levels: DEBUG, INFO, WARN, ERROR
- Automatic error categorization (NETWORK_ERROR, AUTH_ERROR, DATABASE_ERROR, etc.)
- Phase tracking (INITIALIZING, FETCHING, MAPPING, VALIDATING, UPSERTING, DELETING, COMPLETING)
- Contextual metadata (syncId, entityType, phase, duration, record counts)
- Timing helpers for operations
- Update sync-service.ts with structured logging
- Replace console.log/error with structured logger
- Consistent error categorization across all error paths
- Fix swallowed errors in sync history updates
- Add child loggers for entity-specific operations
- Update entity-sync.ts with structured logging
- Complete phase tracking throughout sync lifecycle
- Detailed context for warnings and errors
- Update chunked sync methods with structured logging
- Update picklist sync methods (issue types, sub-issue types)
- Better debugging info with timing and sample data
- Add sync failure analysis script (scripts/analyze-sync-failures.ts)
- Query sync history by date range, entity type, or status
- Generate failure summaries by entity
- Automatic error categorization
- Calculate success rates and statistics
- Display detailed sync records with timing
- Add comprehensive documentation (docs/SYNC_LOGGING_IMPROVEMENTS.md)
- Usage guide and examples
- Migration guide for developers
- Before/after comparisons
This addresses inconsistent logging and improves debugging capabilities for sync operations.
2026-01-23 08:02:02 -05:00
|
|
|
entityLogger.info(`Full sync limited to last ${yearsBack} years`);
|
2025-11-19 14:18:16 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (filters.length > 0) {
|
|
|
|
|
params.filter = filters;
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-01-24 09:57:01 -05:00
|
|
|
|
|
|
|
|
// Track whether any filters were applied - if so, skip soft deletes
|
|
|
|
|
const hasAppliedFilters = params.filter && params.filter.length > 0;
|
2025-11-19 14:18:16 -05:00
|
|
|
|
|
|
|
|
// Fetch data from Autotask with pagination
|
feat: implement structured logging for sync operations
- Add comprehensive structured logging utility (lib/utils/sync-logger.ts)
- Log levels: DEBUG, INFO, WARN, ERROR
- Automatic error categorization (NETWORK_ERROR, AUTH_ERROR, DATABASE_ERROR, etc.)
- Phase tracking (INITIALIZING, FETCHING, MAPPING, VALIDATING, UPSERTING, DELETING, COMPLETING)
- Contextual metadata (syncId, entityType, phase, duration, record counts)
- Timing helpers for operations
- Update sync-service.ts with structured logging
- Replace console.log/error with structured logger
- Consistent error categorization across all error paths
- Fix swallowed errors in sync history updates
- Add child loggers for entity-specific operations
- Update entity-sync.ts with structured logging
- Complete phase tracking throughout sync lifecycle
- Detailed context for warnings and errors
- Update chunked sync methods with structured logging
- Update picklist sync methods (issue types, sub-issue types)
- Better debugging info with timing and sample data
- Add sync failure analysis script (scripts/analyze-sync-failures.ts)
- Query sync history by date range, entity type, or status
- Generate failure summaries by entity
- Automatic error categorization
- Calculate success rates and statistics
- Display detailed sync records with timing
- Add comprehensive documentation (docs/SYNC_LOGGING_IMPROVEMENTS.md)
- Usage guide and examples
- Migration guide for developers
- Before/after comparisons
This addresses inconsistent logging and improves debugging capabilities for sync operations.
2026-01-23 08:02:02 -05:00
|
|
|
entityLogger.phase(SyncPhase.FETCHING, 'Fetching records from Autotask API');
|
2025-11-19 14:18:16 -05:00
|
|
|
syncProgressTracker.updateProgress(trackingId, { phase: 'fetching' });
|
|
|
|
|
|
|
|
|
|
let autotaskRecords: any[];
|
feat: implement structured logging for sync operations
- Add comprehensive structured logging utility (lib/utils/sync-logger.ts)
- Log levels: DEBUG, INFO, WARN, ERROR
- Automatic error categorization (NETWORK_ERROR, AUTH_ERROR, DATABASE_ERROR, etc.)
- Phase tracking (INITIALIZING, FETCHING, MAPPING, VALIDATING, UPSERTING, DELETING, COMPLETING)
- Contextual metadata (syncId, entityType, phase, duration, record counts)
- Timing helpers for operations
- Update sync-service.ts with structured logging
- Replace console.log/error with structured logger
- Consistent error categorization across all error paths
- Fix swallowed errors in sync history updates
- Add child loggers for entity-specific operations
- Update entity-sync.ts with structured logging
- Complete phase tracking throughout sync lifecycle
- Detailed context for warnings and errors
- Update chunked sync methods with structured logging
- Update picklist sync methods (issue types, sub-issue types)
- Better debugging info with timing and sample data
- Add sync failure analysis script (scripts/analyze-sync-failures.ts)
- Query sync history by date range, entity type, or status
- Generate failure summaries by entity
- Automatic error categorization
- Calculate success rates and statistics
- Display detailed sync records with timing
- Add comprehensive documentation (docs/SYNC_LOGGING_IMPROVEMENTS.md)
- Usage guide and examples
- Migration guide for developers
- Before/after comparisons
This addresses inconsistent logging and improves debugging capabilities for sync operations.
2026-01-23 08:02:02 -05:00
|
|
|
const fetchStartTime = Date.now();
|
2025-11-19 14:18:16 -05:00
|
|
|
try {
|
|
|
|
|
autotaskRecords = await this.autotaskClient.queryEntityPaginated(
|
|
|
|
|
autotaskEntityName,
|
|
|
|
|
params,
|
|
|
|
|
500 // Page size
|
|
|
|
|
);
|
feat: implement structured logging for sync operations
- Add comprehensive structured logging utility (lib/utils/sync-logger.ts)
- Log levels: DEBUG, INFO, WARN, ERROR
- Automatic error categorization (NETWORK_ERROR, AUTH_ERROR, DATABASE_ERROR, etc.)
- Phase tracking (INITIALIZING, FETCHING, MAPPING, VALIDATING, UPSERTING, DELETING, COMPLETING)
- Contextual metadata (syncId, entityType, phase, duration, record counts)
- Timing helpers for operations
- Update sync-service.ts with structured logging
- Replace console.log/error with structured logger
- Consistent error categorization across all error paths
- Fix swallowed errors in sync history updates
- Add child loggers for entity-specific operations
- Update entity-sync.ts with structured logging
- Complete phase tracking throughout sync lifecycle
- Detailed context for warnings and errors
- Update chunked sync methods with structured logging
- Update picklist sync methods (issue types, sub-issue types)
- Better debugging info with timing and sample data
- Add sync failure analysis script (scripts/analyze-sync-failures.ts)
- Query sync history by date range, entity type, or status
- Generate failure summaries by entity
- Automatic error categorization
- Calculate success rates and statistics
- Display detailed sync records with timing
- Add comprehensive documentation (docs/SYNC_LOGGING_IMPROVEMENTS.md)
- Usage guide and examples
- Migration guide for developers
- Before/after comparisons
This addresses inconsistent logging and improves debugging capabilities for sync operations.
2026-01-23 08:02:02 -05:00
|
|
|
entityLogger.debug('API fetch completed', { duration: Date.now() - fetchStartTime });
|
2025-11-19 14:18:16 -05:00
|
|
|
} catch (error) {
|
feat: implement structured logging for sync operations
- Add comprehensive structured logging utility (lib/utils/sync-logger.ts)
- Log levels: DEBUG, INFO, WARN, ERROR
- Automatic error categorization (NETWORK_ERROR, AUTH_ERROR, DATABASE_ERROR, etc.)
- Phase tracking (INITIALIZING, FETCHING, MAPPING, VALIDATING, UPSERTING, DELETING, COMPLETING)
- Contextual metadata (syncId, entityType, phase, duration, record counts)
- Timing helpers for operations
- Update sync-service.ts with structured logging
- Replace console.log/error with structured logger
- Consistent error categorization across all error paths
- Fix swallowed errors in sync history updates
- Add child loggers for entity-specific operations
- Update entity-sync.ts with structured logging
- Complete phase tracking throughout sync lifecycle
- Detailed context for warnings and errors
- Update chunked sync methods with structured logging
- Update picklist sync methods (issue types, sub-issue types)
- Better debugging info with timing and sample data
- Add sync failure analysis script (scripts/analyze-sync-failures.ts)
- Query sync history by date range, entity type, or status
- Generate failure summaries by entity
- Automatic error categorization
- Calculate success rates and statistics
- Display detailed sync records with timing
- Add comprehensive documentation (docs/SYNC_LOGGING_IMPROVEMENTS.md)
- Usage guide and examples
- Migration guide for developers
- Before/after comparisons
This addresses inconsistent logging and improves debugging capabilities for sync operations.
2026-01-23 08:02:02 -05:00
|
|
|
const err = error instanceof Error ? error : new Error(String(error));
|
|
|
|
|
const errorCategory = categorizeError(err);
|
|
|
|
|
entityLogger.error('API fetch failed', { phase: SyncPhase.FETCHING, errorCategory }, err);
|
|
|
|
|
throw new Error(`Autotask API error: ${err.message}`);
|
2025-11-19 14:18:16 -05:00
|
|
|
}
|
|
|
|
|
|
feat: implement structured logging for sync operations
- Add comprehensive structured logging utility (lib/utils/sync-logger.ts)
- Log levels: DEBUG, INFO, WARN, ERROR
- Automatic error categorization (NETWORK_ERROR, AUTH_ERROR, DATABASE_ERROR, etc.)
- Phase tracking (INITIALIZING, FETCHING, MAPPING, VALIDATING, UPSERTING, DELETING, COMPLETING)
- Contextual metadata (syncId, entityType, phase, duration, record counts)
- Timing helpers for operations
- Update sync-service.ts with structured logging
- Replace console.log/error with structured logger
- Consistent error categorization across all error paths
- Fix swallowed errors in sync history updates
- Add child loggers for entity-specific operations
- Update entity-sync.ts with structured logging
- Complete phase tracking throughout sync lifecycle
- Detailed context for warnings and errors
- Update chunked sync methods with structured logging
- Update picklist sync methods (issue types, sub-issue types)
- Better debugging info with timing and sample data
- Add sync failure analysis script (scripts/analyze-sync-failures.ts)
- Query sync history by date range, entity type, or status
- Generate failure summaries by entity
- Automatic error categorization
- Calculate success rates and statistics
- Display detailed sync records with timing
- Add comprehensive documentation (docs/SYNC_LOGGING_IMPROVEMENTS.md)
- Usage guide and examples
- Migration guide for developers
- Before/after comparisons
This addresses inconsistent logging and improves debugging capabilities for sync operations.
2026-01-23 08:02:02 -05:00
|
|
|
entityLogger.info('Fetched records from Autotask', { recordCount: autotaskRecords.length });
|
2025-11-19 14:18:16 -05:00
|
|
|
syncProgressTracker.updateProgress(trackingId, {
|
|
|
|
|
totalRecords: autotaskRecords.length,
|
|
|
|
|
phase: 'mapping'
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (autotaskRecords.length === 0) {
|
feat: implement structured logging for sync operations
- Add comprehensive structured logging utility (lib/utils/sync-logger.ts)
- Log levels: DEBUG, INFO, WARN, ERROR
- Automatic error categorization (NETWORK_ERROR, AUTH_ERROR, DATABASE_ERROR, etc.)
- Phase tracking (INITIALIZING, FETCHING, MAPPING, VALIDATING, UPSERTING, DELETING, COMPLETING)
- Contextual metadata (syncId, entityType, phase, duration, record counts)
- Timing helpers for operations
- Update sync-service.ts with structured logging
- Replace console.log/error with structured logger
- Consistent error categorization across all error paths
- Fix swallowed errors in sync history updates
- Add child loggers for entity-specific operations
- Update entity-sync.ts with structured logging
- Complete phase tracking throughout sync lifecycle
- Detailed context for warnings and errors
- Update chunked sync methods with structured logging
- Update picklist sync methods (issue types, sub-issue types)
- Better debugging info with timing and sample data
- Add sync failure analysis script (scripts/analyze-sync-failures.ts)
- Query sync history by date range, entity type, or status
- Generate failure summaries by entity
- Automatic error categorization
- Calculate success rates and statistics
- Display detailed sync records with timing
- Add comprehensive documentation (docs/SYNC_LOGGING_IMPROVEMENTS.md)
- Usage guide and examples
- Migration guide for developers
- Before/after comparisons
This addresses inconsistent logging and improves debugging capabilities for sync operations.
2026-01-23 08:02:02 -05:00
|
|
|
entityLogger.info('No records to sync');
|
2025-11-19 14:18:16 -05:00
|
|
|
syncProgressTracker.completeSync(trackingId, 0);
|
|
|
|
|
return { recordsAdded: 0, recordsUpdated: 0, recordsDeleted: 0 };
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Map Autotask data to PostgreSQL schema
|
feat: implement structured logging for sync operations
- Add comprehensive structured logging utility (lib/utils/sync-logger.ts)
- Log levels: DEBUG, INFO, WARN, ERROR
- Automatic error categorization (NETWORK_ERROR, AUTH_ERROR, DATABASE_ERROR, etc.)
- Phase tracking (INITIALIZING, FETCHING, MAPPING, VALIDATING, UPSERTING, DELETING, COMPLETING)
- Contextual metadata (syncId, entityType, phase, duration, record counts)
- Timing helpers for operations
- Update sync-service.ts with structured logging
- Replace console.log/error with structured logger
- Consistent error categorization across all error paths
- Fix swallowed errors in sync history updates
- Add child loggers for entity-specific operations
- Update entity-sync.ts with structured logging
- Complete phase tracking throughout sync lifecycle
- Detailed context for warnings and errors
- Update chunked sync methods with structured logging
- Update picklist sync methods (issue types, sub-issue types)
- Better debugging info with timing and sample data
- Add sync failure analysis script (scripts/analyze-sync-failures.ts)
- Query sync history by date range, entity type, or status
- Generate failure summaries by entity
- Automatic error categorization
- Calculate success rates and statistics
- Display detailed sync records with timing
- Add comprehensive documentation (docs/SYNC_LOGGING_IMPROVEMENTS.md)
- Usage guide and examples
- Migration guide for developers
- Before/after comparisons
This addresses inconsistent logging and improves debugging capabilities for sync operations.
2026-01-23 08:02:02 -05:00
|
|
|
entityLogger.phase(SyncPhase.MAPPING, `Mapping ${autotaskRecords.length} records to database schema`);
|
2025-11-19 14:18:16 -05:00
|
|
|
|
|
|
|
|
// DEBUG: Log first record to see actual field names from Autotask
|
|
|
|
|
if (autotaskRecords.length > 0 && (entity === EntityType.TICKETS || entity === EntityType.TIME_ENTRIES)) {
|
feat: implement structured logging for sync operations
- Add comprehensive structured logging utility (lib/utils/sync-logger.ts)
- Log levels: DEBUG, INFO, WARN, ERROR
- Automatic error categorization (NETWORK_ERROR, AUTH_ERROR, DATABASE_ERROR, etc.)
- Phase tracking (INITIALIZING, FETCHING, MAPPING, VALIDATING, UPSERTING, DELETING, COMPLETING)
- Contextual metadata (syncId, entityType, phase, duration, record counts)
- Timing helpers for operations
- Update sync-service.ts with structured logging
- Replace console.log/error with structured logger
- Consistent error categorization across all error paths
- Fix swallowed errors in sync history updates
- Add child loggers for entity-specific operations
- Update entity-sync.ts with structured logging
- Complete phase tracking throughout sync lifecycle
- Detailed context for warnings and errors
- Update chunked sync methods with structured logging
- Update picklist sync methods (issue types, sub-issue types)
- Better debugging info with timing and sample data
- Add sync failure analysis script (scripts/analyze-sync-failures.ts)
- Query sync history by date range, entity type, or status
- Generate failure summaries by entity
- Automatic error categorization
- Calculate success rates and statistics
- Display detailed sync records with timing
- Add comprehensive documentation (docs/SYNC_LOGGING_IMPROVEMENTS.md)
- Usage guide and examples
- Migration guide for developers
- Before/after comparisons
This addresses inconsistent logging and improves debugging capabilities for sync operations.
2026-01-23 08:02:02 -05:00
|
|
|
entityLogger.debug('Sample raw Autotask record keys', { keys: Object.keys(autotaskRecords[0]) });
|
2025-11-19 14:18:16 -05:00
|
|
|
if (entity === EntityType.TIME_ENTRIES) {
|
feat: implement structured logging for sync operations
- Add comprehensive structured logging utility (lib/utils/sync-logger.ts)
- Log levels: DEBUG, INFO, WARN, ERROR
- Automatic error categorization (NETWORK_ERROR, AUTH_ERROR, DATABASE_ERROR, etc.)
- Phase tracking (INITIALIZING, FETCHING, MAPPING, VALIDATING, UPSERTING, DELETING, COMPLETING)
- Contextual metadata (syncId, entityType, phase, duration, record counts)
- Timing helpers for operations
- Update sync-service.ts with structured logging
- Replace console.log/error with structured logger
- Consistent error categorization across all error paths
- Fix swallowed errors in sync history updates
- Add child loggers for entity-specific operations
- Update entity-sync.ts with structured logging
- Complete phase tracking throughout sync lifecycle
- Detailed context for warnings and errors
- Update chunked sync methods with structured logging
- Update picklist sync methods (issue types, sub-issue types)
- Better debugging info with timing and sample data
- Add sync failure analysis script (scripts/analyze-sync-failures.ts)
- Query sync history by date range, entity type, or status
- Generate failure summaries by entity
- Automatic error categorization
- Calculate success rates and statistics
- Display detailed sync records with timing
- Add comprehensive documentation (docs/SYNC_LOGGING_IMPROVEMENTS.md)
- Usage guide and examples
- Migration guide for developers
- Before/after comparisons
This addresses inconsistent logging and improves debugging capabilities for sync operations.
2026-01-23 08:02:02 -05:00
|
|
|
entityLogger.debug('Sample time entry', { sample: JSON.stringify(autotaskRecords[0], null, 2) });
|
2025-11-19 14:18:16 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let mappedRecords: Record<string, any>[];
|
feat: implement structured logging for sync operations
- Add comprehensive structured logging utility (lib/utils/sync-logger.ts)
- Log levels: DEBUG, INFO, WARN, ERROR
- Automatic error categorization (NETWORK_ERROR, AUTH_ERROR, DATABASE_ERROR, etc.)
- Phase tracking (INITIALIZING, FETCHING, MAPPING, VALIDATING, UPSERTING, DELETING, COMPLETING)
- Contextual metadata (syncId, entityType, phase, duration, record counts)
- Timing helpers for operations
- Update sync-service.ts with structured logging
- Replace console.log/error with structured logger
- Consistent error categorization across all error paths
- Fix swallowed errors in sync history updates
- Add child loggers for entity-specific operations
- Update entity-sync.ts with structured logging
- Complete phase tracking throughout sync lifecycle
- Detailed context for warnings and errors
- Update chunked sync methods with structured logging
- Update picklist sync methods (issue types, sub-issue types)
- Better debugging info with timing and sample data
- Add sync failure analysis script (scripts/analyze-sync-failures.ts)
- Query sync history by date range, entity type, or status
- Generate failure summaries by entity
- Automatic error categorization
- Calculate success rates and statistics
- Display detailed sync records with timing
- Add comprehensive documentation (docs/SYNC_LOGGING_IMPROVEMENTS.md)
- Usage guide and examples
- Migration guide for developers
- Before/after comparisons
This addresses inconsistent logging and improves debugging capabilities for sync operations.
2026-01-23 08:02:02 -05:00
|
|
|
const mapStartTime = Date.now();
|
2025-11-19 14:18:16 -05:00
|
|
|
try {
|
|
|
|
|
mappedRecords = mapAutotaskBatch(entity, autotaskRecords);
|
feat: implement structured logging for sync operations
- Add comprehensive structured logging utility (lib/utils/sync-logger.ts)
- Log levels: DEBUG, INFO, WARN, ERROR
- Automatic error categorization (NETWORK_ERROR, AUTH_ERROR, DATABASE_ERROR, etc.)
- Phase tracking (INITIALIZING, FETCHING, MAPPING, VALIDATING, UPSERTING, DELETING, COMPLETING)
- Contextual metadata (syncId, entityType, phase, duration, record counts)
- Timing helpers for operations
- Update sync-service.ts with structured logging
- Replace console.log/error with structured logger
- Consistent error categorization across all error paths
- Fix swallowed errors in sync history updates
- Add child loggers for entity-specific operations
- Update entity-sync.ts with structured logging
- Complete phase tracking throughout sync lifecycle
- Detailed context for warnings and errors
- Update chunked sync methods with structured logging
- Update picklist sync methods (issue types, sub-issue types)
- Better debugging info with timing and sample data
- Add sync failure analysis script (scripts/analyze-sync-failures.ts)
- Query sync history by date range, entity type, or status
- Generate failure summaries by entity
- Automatic error categorization
- Calculate success rates and statistics
- Display detailed sync records with timing
- Add comprehensive documentation (docs/SYNC_LOGGING_IMPROVEMENTS.md)
- Usage guide and examples
- Migration guide for developers
- Before/after comparisons
This addresses inconsistent logging and improves debugging capabilities for sync operations.
2026-01-23 08:02:02 -05:00
|
|
|
entityLogger.debug('Mapping completed', { duration: Date.now() - mapStartTime });
|
2025-11-19 14:18:16 -05:00
|
|
|
} catch (error) {
|
feat: implement structured logging for sync operations
- Add comprehensive structured logging utility (lib/utils/sync-logger.ts)
- Log levels: DEBUG, INFO, WARN, ERROR
- Automatic error categorization (NETWORK_ERROR, AUTH_ERROR, DATABASE_ERROR, etc.)
- Phase tracking (INITIALIZING, FETCHING, MAPPING, VALIDATING, UPSERTING, DELETING, COMPLETING)
- Contextual metadata (syncId, entityType, phase, duration, record counts)
- Timing helpers for operations
- Update sync-service.ts with structured logging
- Replace console.log/error with structured logger
- Consistent error categorization across all error paths
- Fix swallowed errors in sync history updates
- Add child loggers for entity-specific operations
- Update entity-sync.ts with structured logging
- Complete phase tracking throughout sync lifecycle
- Detailed context for warnings and errors
- Update chunked sync methods with structured logging
- Update picklist sync methods (issue types, sub-issue types)
- Better debugging info with timing and sample data
- Add sync failure analysis script (scripts/analyze-sync-failures.ts)
- Query sync history by date range, entity type, or status
- Generate failure summaries by entity
- Automatic error categorization
- Calculate success rates and statistics
- Display detailed sync records with timing
- Add comprehensive documentation (docs/SYNC_LOGGING_IMPROVEMENTS.md)
- Usage guide and examples
- Migration guide for developers
- Before/after comparisons
This addresses inconsistent logging and improves debugging capabilities for sync operations.
2026-01-23 08:02:02 -05:00
|
|
|
const err = error instanceof Error ? error : new Error(String(error));
|
|
|
|
|
const errorCategory = categorizeError(err);
|
|
|
|
|
entityLogger.error('Mapping failed', { phase: SyncPhase.MAPPING, errorCategory }, err);
|
|
|
|
|
throw new Error(`Data mapping error: ${err.message}`);
|
2025-11-19 14:18:16 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (mappedRecords.length === 0) {
|
feat: implement structured logging for sync operations
- Add comprehensive structured logging utility (lib/utils/sync-logger.ts)
- Log levels: DEBUG, INFO, WARN, ERROR
- Automatic error categorization (NETWORK_ERROR, AUTH_ERROR, DATABASE_ERROR, etc.)
- Phase tracking (INITIALIZING, FETCHING, MAPPING, VALIDATING, UPSERTING, DELETING, COMPLETING)
- Contextual metadata (syncId, entityType, phase, duration, record counts)
- Timing helpers for operations
- Update sync-service.ts with structured logging
- Replace console.log/error with structured logger
- Consistent error categorization across all error paths
- Fix swallowed errors in sync history updates
- Add child loggers for entity-specific operations
- Update entity-sync.ts with structured logging
- Complete phase tracking throughout sync lifecycle
- Detailed context for warnings and errors
- Update chunked sync methods with structured logging
- Update picklist sync methods (issue types, sub-issue types)
- Better debugging info with timing and sample data
- Add sync failure analysis script (scripts/analyze-sync-failures.ts)
- Query sync history by date range, entity type, or status
- Generate failure summaries by entity
- Automatic error categorization
- Calculate success rates and statistics
- Display detailed sync records with timing
- Add comprehensive documentation (docs/SYNC_LOGGING_IMPROVEMENTS.md)
- Usage guide and examples
- Migration guide for developers
- Before/after comparisons
This addresses inconsistent logging and improves debugging capabilities for sync operations.
2026-01-23 08:02:02 -05:00
|
|
|
entityLogger.warn('All records failed mapping validation', { originalCount: autotaskRecords.length });
|
2025-11-19 14:18:16 -05:00
|
|
|
return { recordsAdded: 0, recordsUpdated: 0, recordsDeleted: 0 };
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Check for records with missing company_id (for entities that require it)
|
|
|
|
|
// Note: TIME_ENTRIES removed from this check because company_id is nullable for time entries
|
feat: implement structured logging for sync operations
- Add comprehensive structured logging utility (lib/utils/sync-logger.ts)
- Log levels: DEBUG, INFO, WARN, ERROR
- Automatic error categorization (NETWORK_ERROR, AUTH_ERROR, DATABASE_ERROR, etc.)
- Phase tracking (INITIALIZING, FETCHING, MAPPING, VALIDATING, UPSERTING, DELETING, COMPLETING)
- Contextual metadata (syncId, entityType, phase, duration, record counts)
- Timing helpers for operations
- Update sync-service.ts with structured logging
- Replace console.log/error with structured logger
- Consistent error categorization across all error paths
- Fix swallowed errors in sync history updates
- Add child loggers for entity-specific operations
- Update entity-sync.ts with structured logging
- Complete phase tracking throughout sync lifecycle
- Detailed context for warnings and errors
- Update chunked sync methods with structured logging
- Update picklist sync methods (issue types, sub-issue types)
- Better debugging info with timing and sample data
- Add sync failure analysis script (scripts/analyze-sync-failures.ts)
- Query sync history by date range, entity type, or status
- Generate failure summaries by entity
- Automatic error categorization
- Calculate success rates and statistics
- Display detailed sync records with timing
- Add comprehensive documentation (docs/SYNC_LOGGING_IMPROVEMENTS.md)
- Usage guide and examples
- Migration guide for developers
- Before/after comparisons
This addresses inconsistent logging and improves debugging capabilities for sync operations.
2026-01-23 08:02:02 -05:00
|
|
|
entityLogger.phase(SyncPhase.VALIDATING, 'Validating records');
|
2025-11-19 14:18:16 -05:00
|
|
|
if (entity === EntityType.TICKETS || entity === EntityType.PROJECTS ||
|
|
|
|
|
entity === EntityType.CONFIGURATION_ITEMS || entity === EntityType.CONTACTS ||
|
|
|
|
|
entity === EntityType.CONTRACTS || entity === EntityType.BILLING_ITEMS) {
|
|
|
|
|
const recordsWithoutCompany = mappedRecords.filter(r => !r.company_id);
|
|
|
|
|
if (recordsWithoutCompany.length > 0) {
|
feat: implement structured logging for sync operations
- Add comprehensive structured logging utility (lib/utils/sync-logger.ts)
- Log levels: DEBUG, INFO, WARN, ERROR
- Automatic error categorization (NETWORK_ERROR, AUTH_ERROR, DATABASE_ERROR, etc.)
- Phase tracking (INITIALIZING, FETCHING, MAPPING, VALIDATING, UPSERTING, DELETING, COMPLETING)
- Contextual metadata (syncId, entityType, phase, duration, record counts)
- Timing helpers for operations
- Update sync-service.ts with structured logging
- Replace console.log/error with structured logger
- Consistent error categorization across all error paths
- Fix swallowed errors in sync history updates
- Add child loggers for entity-specific operations
- Update entity-sync.ts with structured logging
- Complete phase tracking throughout sync lifecycle
- Detailed context for warnings and errors
- Update chunked sync methods with structured logging
- Update picklist sync methods (issue types, sub-issue types)
- Better debugging info with timing and sample data
- Add sync failure analysis script (scripts/analyze-sync-failures.ts)
- Query sync history by date range, entity type, or status
- Generate failure summaries by entity
- Automatic error categorization
- Calculate success rates and statistics
- Display detailed sync records with timing
- Add comprehensive documentation (docs/SYNC_LOGGING_IMPROVEMENTS.md)
- Usage guide and examples
- Migration guide for developers
- Before/after comparisons
This addresses inconsistent logging and improves debugging capabilities for sync operations.
2026-01-23 08:02:02 -05:00
|
|
|
entityLogger.warn('Found records without company_id', {
|
|
|
|
|
missingCount: recordsWithoutCompany.length,
|
|
|
|
|
totalCount: mappedRecords.length,
|
|
|
|
|
sampleIds: recordsWithoutCompany.slice(0, 5).map(r => r.id),
|
|
|
|
|
});
|
2025-11-19 14:18:16 -05:00
|
|
|
// Filter out records without company_id to prevent constraint violation
|
|
|
|
|
mappedRecords = mappedRecords.filter(r => r.company_id);
|
feat: implement structured logging for sync operations
- Add comprehensive structured logging utility (lib/utils/sync-logger.ts)
- Log levels: DEBUG, INFO, WARN, ERROR
- Automatic error categorization (NETWORK_ERROR, AUTH_ERROR, DATABASE_ERROR, etc.)
- Phase tracking (INITIALIZING, FETCHING, MAPPING, VALIDATING, UPSERTING, DELETING, COMPLETING)
- Contextual metadata (syncId, entityType, phase, duration, record counts)
- Timing helpers for operations
- Update sync-service.ts with structured logging
- Replace console.log/error with structured logger
- Consistent error categorization across all error paths
- Fix swallowed errors in sync history updates
- Add child loggers for entity-specific operations
- Update entity-sync.ts with structured logging
- Complete phase tracking throughout sync lifecycle
- Detailed context for warnings and errors
- Update chunked sync methods with structured logging
- Update picklist sync methods (issue types, sub-issue types)
- Better debugging info with timing and sample data
- Add sync failure analysis script (scripts/analyze-sync-failures.ts)
- Query sync history by date range, entity type, or status
- Generate failure summaries by entity
- Automatic error categorization
- Calculate success rates and statistics
- Display detailed sync records with timing
- Add comprehensive documentation (docs/SYNC_LOGGING_IMPROVEMENTS.md)
- Usage guide and examples
- Migration guide for developers
- Before/after comparisons
This addresses inconsistent logging and improves debugging capabilities for sync operations.
2026-01-23 08:02:02 -05:00
|
|
|
entityLogger.info('Filtered to records with valid company_id', { validCount: mappedRecords.length });
|
2025-11-19 14:18:16 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Validate resource foreign keys for tickets
|
|
|
|
|
if (entity === EntityType.TICKETS) {
|
|
|
|
|
const initialCount = mappedRecords.length;
|
|
|
|
|
|
|
|
|
|
// Get all valid resource IDs from database
|
|
|
|
|
const validResourceIds = await this.getValidResourceIds();
|
|
|
|
|
|
|
|
|
|
// Filter tickets with invalid resource references
|
2026-04-05 08:55:41 -04:00
|
|
|
let skippedResourceCount = 0;
|
2025-11-19 14:18:16 -05:00
|
|
|
mappedRecords = mappedRecords.map(ticket => {
|
2026-04-05 08:55:41 -04:00
|
|
|
// Set to null — bulkUpsert uses COALESCE for these columns so existing DB value is preserved
|
2025-11-19 14:18:16 -05:00
|
|
|
if (ticket.assigned_resource_id && !validResourceIds.has(ticket.assigned_resource_id)) {
|
2026-04-05 08:55:41 -04:00
|
|
|
entityLogger.debug(`Unknown assigned_resource_id, will preserve existing DB value via COALESCE`, {
|
feat: implement structured logging for sync operations
- Add comprehensive structured logging utility (lib/utils/sync-logger.ts)
- Log levels: DEBUG, INFO, WARN, ERROR
- Automatic error categorization (NETWORK_ERROR, AUTH_ERROR, DATABASE_ERROR, etc.)
- Phase tracking (INITIALIZING, FETCHING, MAPPING, VALIDATING, UPSERTING, DELETING, COMPLETING)
- Contextual metadata (syncId, entityType, phase, duration, record counts)
- Timing helpers for operations
- Update sync-service.ts with structured logging
- Replace console.log/error with structured logger
- Consistent error categorization across all error paths
- Fix swallowed errors in sync history updates
- Add child loggers for entity-specific operations
- Update entity-sync.ts with structured logging
- Complete phase tracking throughout sync lifecycle
- Detailed context for warnings and errors
- Update chunked sync methods with structured logging
- Update picklist sync methods (issue types, sub-issue types)
- Better debugging info with timing and sample data
- Add sync failure analysis script (scripts/analyze-sync-failures.ts)
- Query sync history by date range, entity type, or status
- Generate failure summaries by entity
- Automatic error categorization
- Calculate success rates and statistics
- Display detailed sync records with timing
- Add comprehensive documentation (docs/SYNC_LOGGING_IMPROVEMENTS.md)
- Usage guide and examples
- Migration guide for developers
- Before/after comparisons
This addresses inconsistent logging and improves debugging capabilities for sync operations.
2026-01-23 08:02:02 -05:00
|
|
|
ticketId: ticket.id,
|
2026-04-05 08:55:41 -04:00
|
|
|
unknownResourceId: ticket.assigned_resource_id,
|
feat: implement structured logging for sync operations
- Add comprehensive structured logging utility (lib/utils/sync-logger.ts)
- Log levels: DEBUG, INFO, WARN, ERROR
- Automatic error categorization (NETWORK_ERROR, AUTH_ERROR, DATABASE_ERROR, etc.)
- Phase tracking (INITIALIZING, FETCHING, MAPPING, VALIDATING, UPSERTING, DELETING, COMPLETING)
- Contextual metadata (syncId, entityType, phase, duration, record counts)
- Timing helpers for operations
- Update sync-service.ts with structured logging
- Replace console.log/error with structured logger
- Consistent error categorization across all error paths
- Fix swallowed errors in sync history updates
- Add child loggers for entity-specific operations
- Update entity-sync.ts with structured logging
- Complete phase tracking throughout sync lifecycle
- Detailed context for warnings and errors
- Update chunked sync methods with structured logging
- Update picklist sync methods (issue types, sub-issue types)
- Better debugging info with timing and sample data
- Add sync failure analysis script (scripts/analyze-sync-failures.ts)
- Query sync history by date range, entity type, or status
- Generate failure summaries by entity
- Automatic error categorization
- Calculate success rates and statistics
- Display detailed sync records with timing
- Add comprehensive documentation (docs/SYNC_LOGGING_IMPROVEMENTS.md)
- Usage guide and examples
- Migration guide for developers
- Before/after comparisons
This addresses inconsistent logging and improves debugging capabilities for sync operations.
2026-01-23 08:02:02 -05:00
|
|
|
});
|
2025-11-19 14:18:16 -05:00
|
|
|
ticket.assigned_resource_id = null;
|
2026-04-05 08:55:41 -04:00
|
|
|
skippedResourceCount++;
|
2025-11-19 14:18:16 -05:00
|
|
|
}
|
|
|
|
|
if (ticket.first_response_assigned_resource_id && !validResourceIds.has(ticket.first_response_assigned_resource_id)) {
|
|
|
|
|
ticket.first_response_assigned_resource_id = null;
|
|
|
|
|
}
|
|
|
|
|
if (ticket.first_response_initiating_resource_id && !validResourceIds.has(ticket.first_response_initiating_resource_id)) {
|
|
|
|
|
ticket.first_response_initiating_resource_id = null;
|
|
|
|
|
}
|
|
|
|
|
return ticket;
|
|
|
|
|
});
|
|
|
|
|
|
2026-04-05 08:55:41 -04:00
|
|
|
if (skippedResourceCount > 0) {
|
|
|
|
|
entityLogger.warn('Skipped unknown resource references (existing DB values preserved via COALESCE)', { skippedResourceCount });
|
2025-11-19 14:18:16 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Validate contact foreign keys for configuration items
|
|
|
|
|
if (entity === EntityType.CONFIGURATION_ITEMS) {
|
|
|
|
|
const initialCount = mappedRecords.length;
|
|
|
|
|
|
|
|
|
|
// Get all valid contact IDs from database
|
|
|
|
|
const validContactIds = await this.getValidContactIds();
|
|
|
|
|
|
|
|
|
|
// Filter configuration items with invalid contact references
|
|
|
|
|
mappedRecords = mappedRecords.map(item => {
|
|
|
|
|
// Set invalid contact IDs to null instead of filtering out the entire item
|
|
|
|
|
if (item.contact_id && !validContactIds.has(item.contact_id)) {
|
feat: implement structured logging for sync operations
- Add comprehensive structured logging utility (lib/utils/sync-logger.ts)
- Log levels: DEBUG, INFO, WARN, ERROR
- Automatic error categorization (NETWORK_ERROR, AUTH_ERROR, DATABASE_ERROR, etc.)
- Phase tracking (INITIALIZING, FETCHING, MAPPING, VALIDATING, UPSERTING, DELETING, COMPLETING)
- Contextual metadata (syncId, entityType, phase, duration, record counts)
- Timing helpers for operations
- Update sync-service.ts with structured logging
- Replace console.log/error with structured logger
- Consistent error categorization across all error paths
- Fix swallowed errors in sync history updates
- Add child loggers for entity-specific operations
- Update entity-sync.ts with structured logging
- Complete phase tracking throughout sync lifecycle
- Detailed context for warnings and errors
- Update chunked sync methods with structured logging
- Update picklist sync methods (issue types, sub-issue types)
- Better debugging info with timing and sample data
- Add sync failure analysis script (scripts/analyze-sync-failures.ts)
- Query sync history by date range, entity type, or status
- Generate failure summaries by entity
- Automatic error categorization
- Calculate success rates and statistics
- Display detailed sync records with timing
- Add comprehensive documentation (docs/SYNC_LOGGING_IMPROVEMENTS.md)
- Usage guide and examples
- Migration guide for developers
- Before/after comparisons
This addresses inconsistent logging and improves debugging capabilities for sync operations.
2026-01-23 08:02:02 -05:00
|
|
|
entityLogger.debug(`Invalid contact_id, setting to null`, {
|
|
|
|
|
itemId: item.id,
|
|
|
|
|
invalidContactId: item.contact_id,
|
|
|
|
|
});
|
2025-11-19 14:18:16 -05:00
|
|
|
item.contact_id = null;
|
|
|
|
|
}
|
|
|
|
|
return item;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const nullifiedCount = initialCount - mappedRecords.filter(i => i.contact_id).length;
|
|
|
|
|
if (nullifiedCount > 0) {
|
feat: implement structured logging for sync operations
- Add comprehensive structured logging utility (lib/utils/sync-logger.ts)
- Log levels: DEBUG, INFO, WARN, ERROR
- Automatic error categorization (NETWORK_ERROR, AUTH_ERROR, DATABASE_ERROR, etc.)
- Phase tracking (INITIALIZING, FETCHING, MAPPING, VALIDATING, UPSERTING, DELETING, COMPLETING)
- Contextual metadata (syncId, entityType, phase, duration, record counts)
- Timing helpers for operations
- Update sync-service.ts with structured logging
- Replace console.log/error with structured logger
- Consistent error categorization across all error paths
- Fix swallowed errors in sync history updates
- Add child loggers for entity-specific operations
- Update entity-sync.ts with structured logging
- Complete phase tracking throughout sync lifecycle
- Detailed context for warnings and errors
- Update chunked sync methods with structured logging
- Update picklist sync methods (issue types, sub-issue types)
- Better debugging info with timing and sample data
- Add sync failure analysis script (scripts/analyze-sync-failures.ts)
- Query sync history by date range, entity type, or status
- Generate failure summaries by entity
- Automatic error categorization
- Calculate success rates and statistics
- Display detailed sync records with timing
- Add comprehensive documentation (docs/SYNC_LOGGING_IMPROVEMENTS.md)
- Usage guide and examples
- Migration guide for developers
- Before/after comparisons
This addresses inconsistent logging and improves debugging capabilities for sync operations.
2026-01-23 08:02:02 -05:00
|
|
|
entityLogger.warn('Nullified invalid contact references', { nullifiedCount });
|
2025-11-19 14:18:16 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-24 08:13:18 -05:00
|
|
|
// Validate project and resource foreign keys for tasks
|
2026-01-24 08:09:10 -05:00
|
|
|
if (entity === EntityType.TASKS) {
|
|
|
|
|
const initialCount = mappedRecords.length;
|
|
|
|
|
|
2026-01-24 08:13:18 -05:00
|
|
|
// Get all valid project IDs and resource IDs from database
|
2026-01-24 08:09:10 -05:00
|
|
|
const validProjectIds = await this.getValidProjectIds();
|
2026-01-24 08:13:18 -05:00
|
|
|
const validResourceIds = await this.getValidResourceIds();
|
2026-01-24 08:09:10 -05:00
|
|
|
|
2026-01-24 08:13:18 -05:00
|
|
|
// Filter tasks with invalid foreign key references
|
2026-01-24 08:09:10 -05:00
|
|
|
mappedRecords = mappedRecords.map(task => {
|
2026-01-24 08:13:18 -05:00
|
|
|
// Set invalid project IDs to null
|
2026-01-24 08:09:10 -05:00
|
|
|
if (task.project_id && !validProjectIds.has(task.project_id)) {
|
|
|
|
|
entityLogger.debug(`Invalid project_id, setting to null`, {
|
|
|
|
|
taskId: task.id,
|
|
|
|
|
invalidProjectId: task.project_id,
|
|
|
|
|
});
|
|
|
|
|
task.project_id = null;
|
|
|
|
|
}
|
2026-01-24 08:13:18 -05:00
|
|
|
|
|
|
|
|
// Set invalid resource IDs to null
|
|
|
|
|
if (task.assigned_resource_id && !validResourceIds.has(task.assigned_resource_id)) {
|
|
|
|
|
entityLogger.debug(`Invalid assigned_resource_id, setting to null`, {
|
|
|
|
|
taskId: task.id,
|
|
|
|
|
invalidResourceId: task.assigned_resource_id,
|
|
|
|
|
});
|
|
|
|
|
task.assigned_resource_id = null;
|
|
|
|
|
}
|
|
|
|
|
if (task.creator_resource_id && !validResourceIds.has(task.creator_resource_id)) {
|
|
|
|
|
task.creator_resource_id = null;
|
|
|
|
|
}
|
|
|
|
|
if (task.completed_by_resource_id && !validResourceIds.has(task.completed_by_resource_id)) {
|
|
|
|
|
task.completed_by_resource_id = null;
|
|
|
|
|
}
|
|
|
|
|
if (task.last_activity_resource_id && !validResourceIds.has(task.last_activity_resource_id)) {
|
|
|
|
|
task.last_activity_resource_id = null;
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-24 08:09:10 -05:00
|
|
|
return task;
|
|
|
|
|
});
|
|
|
|
|
|
2026-01-24 08:13:18 -05:00
|
|
|
const nullifiedProjectCount = initialCount - mappedRecords.filter(t => t.project_id).length;
|
|
|
|
|
const nullifiedResourceCount = initialCount - mappedRecords.filter(t => t.assigned_resource_id).length;
|
|
|
|
|
if (nullifiedProjectCount > 0 || nullifiedResourceCount > 0) {
|
|
|
|
|
entityLogger.warn('Nullified invalid foreign key references', {
|
|
|
|
|
nullifiedProjectCount,
|
|
|
|
|
nullifiedResourceCount
|
|
|
|
|
});
|
2026-01-24 08:09:10 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
feat: implement structured logging for sync operations
- Add comprehensive structured logging utility (lib/utils/sync-logger.ts)
- Log levels: DEBUG, INFO, WARN, ERROR
- Automatic error categorization (NETWORK_ERROR, AUTH_ERROR, DATABASE_ERROR, etc.)
- Phase tracking (INITIALIZING, FETCHING, MAPPING, VALIDATING, UPSERTING, DELETING, COMPLETING)
- Contextual metadata (syncId, entityType, phase, duration, record counts)
- Timing helpers for operations
- Update sync-service.ts with structured logging
- Replace console.log/error with structured logger
- Consistent error categorization across all error paths
- Fix swallowed errors in sync history updates
- Add child loggers for entity-specific operations
- Update entity-sync.ts with structured logging
- Complete phase tracking throughout sync lifecycle
- Detailed context for warnings and errors
- Update chunked sync methods with structured logging
- Update picklist sync methods (issue types, sub-issue types)
- Better debugging info with timing and sample data
- Add sync failure analysis script (scripts/analyze-sync-failures.ts)
- Query sync history by date range, entity type, or status
- Generate failure summaries by entity
- Automatic error categorization
- Calculate success rates and statistics
- Display detailed sync records with timing
- Add comprehensive documentation (docs/SYNC_LOGGING_IMPROVEMENTS.md)
- Usage guide and examples
- Migration guide for developers
- Before/after comparisons
This addresses inconsistent logging and improves debugging capabilities for sync operations.
2026-01-23 08:02:02 -05:00
|
|
|
entityLogger.info('Successfully mapped records', { mappedCount: mappedRecords.length });
|
2025-11-19 14:18:16 -05:00
|
|
|
|
|
|
|
|
// Bulk upsert to PostgreSQL
|
feat: implement structured logging for sync operations
- Add comprehensive structured logging utility (lib/utils/sync-logger.ts)
- Log levels: DEBUG, INFO, WARN, ERROR
- Automatic error categorization (NETWORK_ERROR, AUTH_ERROR, DATABASE_ERROR, etc.)
- Phase tracking (INITIALIZING, FETCHING, MAPPING, VALIDATING, UPSERTING, DELETING, COMPLETING)
- Contextual metadata (syncId, entityType, phase, duration, record counts)
- Timing helpers for operations
- Update sync-service.ts with structured logging
- Replace console.log/error with structured logger
- Consistent error categorization across all error paths
- Fix swallowed errors in sync history updates
- Add child loggers for entity-specific operations
- Update entity-sync.ts with structured logging
- Complete phase tracking throughout sync lifecycle
- Detailed context for warnings and errors
- Update chunked sync methods with structured logging
- Update picklist sync methods (issue types, sub-issue types)
- Better debugging info with timing and sample data
- Add sync failure analysis script (scripts/analyze-sync-failures.ts)
- Query sync history by date range, entity type, or status
- Generate failure summaries by entity
- Automatic error categorization
- Calculate success rates and statistics
- Display detailed sync records with timing
- Add comprehensive documentation (docs/SYNC_LOGGING_IMPROVEMENTS.md)
- Usage guide and examples
- Migration guide for developers
- Before/after comparisons
This addresses inconsistent logging and improves debugging capabilities for sync operations.
2026-01-23 08:02:02 -05:00
|
|
|
entityLogger.phase(SyncPhase.UPSERTING, 'Upserting records to PostgreSQL');
|
2025-11-19 14:18:16 -05:00
|
|
|
syncProgressTracker.updateProgress(trackingId, { phase: 'upserting' });
|
|
|
|
|
|
|
|
|
|
let upsertedCount: number;
|
feat: implement structured logging for sync operations
- Add comprehensive structured logging utility (lib/utils/sync-logger.ts)
- Log levels: DEBUG, INFO, WARN, ERROR
- Automatic error categorization (NETWORK_ERROR, AUTH_ERROR, DATABASE_ERROR, etc.)
- Phase tracking (INITIALIZING, FETCHING, MAPPING, VALIDATING, UPSERTING, DELETING, COMPLETING)
- Contextual metadata (syncId, entityType, phase, duration, record counts)
- Timing helpers for operations
- Update sync-service.ts with structured logging
- Replace console.log/error with structured logger
- Consistent error categorization across all error paths
- Fix swallowed errors in sync history updates
- Add child loggers for entity-specific operations
- Update entity-sync.ts with structured logging
- Complete phase tracking throughout sync lifecycle
- Detailed context for warnings and errors
- Update chunked sync methods with structured logging
- Update picklist sync methods (issue types, sub-issue types)
- Better debugging info with timing and sample data
- Add sync failure analysis script (scripts/analyze-sync-failures.ts)
- Query sync history by date range, entity type, or status
- Generate failure summaries by entity
- Automatic error categorization
- Calculate success rates and statistics
- Display detailed sync records with timing
- Add comprehensive documentation (docs/SYNC_LOGGING_IMPROVEMENTS.md)
- Usage guide and examples
- Migration guide for developers
- Before/after comparisons
This addresses inconsistent logging and improves debugging capabilities for sync operations.
2026-01-23 08:02:02 -05:00
|
|
|
const upsertStartTime = Date.now();
|
2025-11-19 14:18:16 -05:00
|
|
|
try {
|
|
|
|
|
upsertedCount = await bulkUpsertRecords(entity, mappedRecords, 100);
|
feat: implement structured logging for sync operations
- Add comprehensive structured logging utility (lib/utils/sync-logger.ts)
- Log levels: DEBUG, INFO, WARN, ERROR
- Automatic error categorization (NETWORK_ERROR, AUTH_ERROR, DATABASE_ERROR, etc.)
- Phase tracking (INITIALIZING, FETCHING, MAPPING, VALIDATING, UPSERTING, DELETING, COMPLETING)
- Contextual metadata (syncId, entityType, phase, duration, record counts)
- Timing helpers for operations
- Update sync-service.ts with structured logging
- Replace console.log/error with structured logger
- Consistent error categorization across all error paths
- Fix swallowed errors in sync history updates
- Add child loggers for entity-specific operations
- Update entity-sync.ts with structured logging
- Complete phase tracking throughout sync lifecycle
- Detailed context for warnings and errors
- Update chunked sync methods with structured logging
- Update picklist sync methods (issue types, sub-issue types)
- Better debugging info with timing and sample data
- Add sync failure analysis script (scripts/analyze-sync-failures.ts)
- Query sync history by date range, entity type, or status
- Generate failure summaries by entity
- Automatic error categorization
- Calculate success rates and statistics
- Display detailed sync records with timing
- Add comprehensive documentation (docs/SYNC_LOGGING_IMPROVEMENTS.md)
- Usage guide and examples
- Migration guide for developers
- Before/after comparisons
This addresses inconsistent logging and improves debugging capabilities for sync operations.
2026-01-23 08:02:02 -05:00
|
|
|
entityLogger.debug('Upsert completed', { duration: Date.now() - upsertStartTime });
|
2025-11-19 14:18:16 -05:00
|
|
|
} catch (error) {
|
feat: implement structured logging for sync operations
- Add comprehensive structured logging utility (lib/utils/sync-logger.ts)
- Log levels: DEBUG, INFO, WARN, ERROR
- Automatic error categorization (NETWORK_ERROR, AUTH_ERROR, DATABASE_ERROR, etc.)
- Phase tracking (INITIALIZING, FETCHING, MAPPING, VALIDATING, UPSERTING, DELETING, COMPLETING)
- Contextual metadata (syncId, entityType, phase, duration, record counts)
- Timing helpers for operations
- Update sync-service.ts with structured logging
- Replace console.log/error with structured logger
- Consistent error categorization across all error paths
- Fix swallowed errors in sync history updates
- Add child loggers for entity-specific operations
- Update entity-sync.ts with structured logging
- Complete phase tracking throughout sync lifecycle
- Detailed context for warnings and errors
- Update chunked sync methods with structured logging
- Update picklist sync methods (issue types, sub-issue types)
- Better debugging info with timing and sample data
- Add sync failure analysis script (scripts/analyze-sync-failures.ts)
- Query sync history by date range, entity type, or status
- Generate failure summaries by entity
- Automatic error categorization
- Calculate success rates and statistics
- Display detailed sync records with timing
- Add comprehensive documentation (docs/SYNC_LOGGING_IMPROVEMENTS.md)
- Usage guide and examples
- Migration guide for developers
- Before/after comparisons
This addresses inconsistent logging and improves debugging capabilities for sync operations.
2026-01-23 08:02:02 -05:00
|
|
|
const err = error instanceof Error ? error : new Error(String(error));
|
|
|
|
|
const errorCategory = categorizeError(err);
|
|
|
|
|
entityLogger.error('Database upsert failed', { phase: SyncPhase.UPSERTING, errorCategory }, err);
|
|
|
|
|
throw new Error(`Database error: ${err.message}`);
|
2025-11-19 14:18:16 -05:00
|
|
|
}
|
|
|
|
|
|
feat: implement structured logging for sync operations
- Add comprehensive structured logging utility (lib/utils/sync-logger.ts)
- Log levels: DEBUG, INFO, WARN, ERROR
- Automatic error categorization (NETWORK_ERROR, AUTH_ERROR, DATABASE_ERROR, etc.)
- Phase tracking (INITIALIZING, FETCHING, MAPPING, VALIDATING, UPSERTING, DELETING, COMPLETING)
- Contextual metadata (syncId, entityType, phase, duration, record counts)
- Timing helpers for operations
- Update sync-service.ts with structured logging
- Replace console.log/error with structured logger
- Consistent error categorization across all error paths
- Fix swallowed errors in sync history updates
- Add child loggers for entity-specific operations
- Update entity-sync.ts with structured logging
- Complete phase tracking throughout sync lifecycle
- Detailed context for warnings and errors
- Update chunked sync methods with structured logging
- Update picklist sync methods (issue types, sub-issue types)
- Better debugging info with timing and sample data
- Add sync failure analysis script (scripts/analyze-sync-failures.ts)
- Query sync history by date range, entity type, or status
- Generate failure summaries by entity
- Automatic error categorization
- Calculate success rates and statistics
- Display detailed sync records with timing
- Add comprehensive documentation (docs/SYNC_LOGGING_IMPROVEMENTS.md)
- Usage guide and examples
- Migration guide for developers
- Before/after comparisons
This addresses inconsistent logging and improves debugging capabilities for sync operations.
2026-01-23 08:02:02 -05:00
|
|
|
entityLogger.info('Upserted records to PostgreSQL', { upsertedCount });
|
2025-11-19 14:18:16 -05:00
|
|
|
|
2026-03-11 09:34:51 -04:00
|
|
|
// Post-sync enrichment: populate service_name from autotask_services lookup
|
|
|
|
|
if (entity === EntityType.CONTRACT_SERVICES) {
|
|
|
|
|
try {
|
|
|
|
|
const enrichResult = await postgresClient.query(`
|
|
|
|
|
UPDATE contract_services cs
|
|
|
|
|
SET service_name = s.name
|
|
|
|
|
FROM autotask_services s
|
|
|
|
|
WHERE cs.service_id = s.id AND cs.service_name IS NULL AND s.name IS NOT NULL
|
|
|
|
|
`);
|
|
|
|
|
entityLogger.info('Enriched contract_services with service names', { rowCount: enrichResult.rowCount });
|
|
|
|
|
} catch (err) {
|
|
|
|
|
entityLogger.warn('service_name enrichment skipped (autotask_services may not be synced yet)');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
feat: add project_phases entity sync with task project_id backfill
The Autotask Tasks bulk API does not return projectID in its response,
causing all tasks.project_id to be NULL. This fixes it by:
- Adding project_phases as a synced entity (Autotask endpoint: /Phases)
- Migration 059: project_phases table with project_id, phase_number,
estimated_hours, start/due dates, parent_phase_id, is_scheduled
- EntityType.PROJECT_PHASES added to all sync maps and dependency graph
(depends on PROJECTS, runs before TASKS in sync order)
- buildProjectPhasesFilter: Phases endpoint requires a filter (id > 0)
- mapProjectPhase: maps Autotask field names to DB columns
- Post-sync backfill in syncEntity: after each project_phases sync,
UPDATE tasks SET project_id = pp.project_id FROM project_phases pp
JOIN projects p WHERE tasks.phase_id = pp.id
Only backfills where the project exists in our DB (FK constraint on
tasks.project_id; archived projects are skipped gracefully)
Result: 2,455 of 4,966 tasks now have project_id populated. Tasks
belonging to archived/completed projects have phase_id resolvable via
project_phases even when project_id remains NULL.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-24 13:57:33 -04:00
|
|
|
// Post-sync backfill: after syncing phases, populate tasks.project_id via phase → project join.
|
|
|
|
|
// The Autotask Tasks bulk query does not return projectID — it must be resolved through phaseID.
|
|
|
|
|
if (entity === EntityType.PROJECT_PHASES) {
|
|
|
|
|
try {
|
|
|
|
|
const backfillResult = await postgresClient.query(
|
|
|
|
|
`UPDATE tasks
|
|
|
|
|
SET project_id = pp.project_id
|
|
|
|
|
FROM project_phases pp
|
|
|
|
|
JOIN projects p ON p.id = pp.project_id
|
|
|
|
|
WHERE tasks.phase_id = pp.id
|
|
|
|
|
AND tasks.project_id IS DISTINCT FROM pp.project_id
|
|
|
|
|
AND pp.project_id IS NOT NULL`
|
|
|
|
|
);
|
|
|
|
|
const updated = (backfillResult as any).rowCount ?? 0;
|
|
|
|
|
entityLogger.info('Backfilled tasks.project_id via phase → project join', { updatedTaskCount: updated });
|
|
|
|
|
} catch (err) {
|
|
|
|
|
entityLogger.warn('Task project_id backfill failed', { error: String(err) });
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
feat: Veeam RPO analysis, comparison, ticket analysis + company teams table
- Add Veeam RPO analysis page (/veeam-analysis) and comparison page (/veeam-comparison)
- Add API routes: /api/veeam/rpo-analyze, rpo-comparison, rpo-offline-log, ticket-analysis
- Add veeam-rpo-service.ts enhancements (RPO logic, offline detection, comparison)
- Add veeam-analysis-state.ts and rmm-device-resolver.ts services
- Add migrations 065-068: company_teams, veeam_rpo_offline_log, rpo_comparison_tables, veeam_ticket_analysis
- Add backup-status page updates and nav links for new Veeam pages
- Add scripts: deactivate-cis-for-inactive-companies, workstation category updates
- Add docs: mimecast-api-guide, veeam-backup-alerting-recommendation, workstation-backup-overview, ticket-analyzer-prompt
- Minor: webhook-service, entity-sync, entity-mapper, sync-helpers, sync.ts, middleware.ts updates
2026-04-29 09:16:46 -04:00
|
|
|
// After contacts sync, backfill primary_contact_id and billing_contact_id on companies
|
|
|
|
|
if (entity === EntityType.CONTACTS) {
|
|
|
|
|
try {
|
|
|
|
|
const primaryResult = await postgresClient.query(
|
|
|
|
|
`UPDATE companies c
|
|
|
|
|
SET primary_contact_id = (
|
|
|
|
|
SELECT id FROM contacts
|
|
|
|
|
WHERE company_id = c.id AND primary_contact = true AND is_deleted = false
|
|
|
|
|
ORDER BY id LIMIT 1
|
|
|
|
|
)
|
|
|
|
|
WHERE EXISTS (
|
|
|
|
|
SELECT 1 FROM contacts
|
|
|
|
|
WHERE company_id = c.id AND primary_contact = true AND is_deleted = false
|
|
|
|
|
)`
|
|
|
|
|
);
|
|
|
|
|
entityLogger.info('Backfilled companies.primary_contact_id', { updatedCount: (primaryResult as any).rowCount ?? 0 });
|
|
|
|
|
|
|
|
|
|
const billingResult = await postgresClient.query(
|
|
|
|
|
`UPDATE companies c
|
|
|
|
|
SET billing_contact_id = (
|
|
|
|
|
SELECT id FROM contacts
|
|
|
|
|
WHERE company_id = c.id AND billing_contact = true AND is_deleted = false
|
|
|
|
|
ORDER BY id LIMIT 1
|
|
|
|
|
)
|
|
|
|
|
WHERE EXISTS (
|
|
|
|
|
SELECT 1 FROM contacts
|
|
|
|
|
WHERE company_id = c.id AND billing_contact = true AND is_deleted = false
|
|
|
|
|
)`
|
|
|
|
|
);
|
|
|
|
|
entityLogger.info('Backfilled companies.billing_contact_id', { updatedCount: (billingResult as any).rowCount ?? 0 });
|
|
|
|
|
} catch (err) {
|
|
|
|
|
entityLogger.warn('Contact FK backfill on companies failed', { error: String(err) });
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-19 14:18:16 -05:00
|
|
|
// For full sync, soft delete records not in the fetched set
|
2026-01-24 09:57:01 -05:00
|
|
|
// IMPORTANT: Skip soft deletes if ANY filters were applied (date, status, active, etc.)
|
feat: QuickBooks Online integration
- Add QBO OAuth2 client with token refresh (lib/services/qbo-client.ts)
- Add QBO sync service for invoices, payments, deposits, purchases, journal entries, reports (lib/services/qbo-sync-service.ts)
- Add QBO types (lib/types/qbo.ts)
- Add API routes: /api/qbo/auth, /api/qbo/sync, /api/qbo/disconnect
- Add /admin/qbo status and sync management page
- Add legal pages: /legal/eula, /legal/privacy (Intuit app assessment)
- Add QBO nav link under Admin
- Fix reports: remove invalid summarize_column_by, add accounting_method from Preferences API, add showrows=all&showcols=all
- Add CashFlow report type alongside P&L and BalanceSheet
- Add NoReportData check to skip empty report months
- Add intuit_tid capture in error messages
- Add redirect: follow for cluster routing
- Migration 051: qbo_tokens, qbo_invoices, qbo_payments, qbo_deposits, qbo_transactions, qbo_reports tables
Also includes earlier work:
- Ping flap suppression pipeline step
- Ticket digest reports with LLM analysis
- Zabbix WAN monitor and gap analysis
- Kiosk is_deleted filter fixes
- Datto RMM ping target enrichment
- Entity sync soft-delete detection
2026-03-17 07:39:55 -04:00
|
|
|
// because we cannot know what records exist outside the filter criteria.
|
|
|
|
|
// EXCEPTION: TICKETS — we do a separate ID-only fetch from Autotask (no filters) to detect
|
|
|
|
|
// deletions even when date filters were applied to the main sync.
|
2025-11-19 14:18:16 -05:00
|
|
|
let deletedCount = 0;
|
feat: QuickBooks Online integration
- Add QBO OAuth2 client with token refresh (lib/services/qbo-client.ts)
- Add QBO sync service for invoices, payments, deposits, purchases, journal entries, reports (lib/services/qbo-sync-service.ts)
- Add QBO types (lib/types/qbo.ts)
- Add API routes: /api/qbo/auth, /api/qbo/sync, /api/qbo/disconnect
- Add /admin/qbo status and sync management page
- Add legal pages: /legal/eula, /legal/privacy (Intuit app assessment)
- Add QBO nav link under Admin
- Fix reports: remove invalid summarize_column_by, add accounting_method from Preferences API, add showrows=all&showcols=all
- Add CashFlow report type alongside P&L and BalanceSheet
- Add NoReportData check to skip empty report months
- Add intuit_tid capture in error messages
- Add redirect: follow for cluster routing
- Migration 051: qbo_tokens, qbo_invoices, qbo_payments, qbo_deposits, qbo_transactions, qbo_reports tables
Also includes earlier work:
- Ping flap suppression pipeline step
- Ticket digest reports with LLM analysis
- Zabbix WAN monitor and gap analysis
- Kiosk is_deleted filter fixes
- Datto RMM ping target enrichment
- Entity sync soft-delete detection
2026-03-17 07:39:55 -04:00
|
|
|
|
2026-01-24 09:57:01 -05:00
|
|
|
if (!isIncremental && !hasAppliedFilters) {
|
feat: implement structured logging for sync operations
- Add comprehensive structured logging utility (lib/utils/sync-logger.ts)
- Log levels: DEBUG, INFO, WARN, ERROR
- Automatic error categorization (NETWORK_ERROR, AUTH_ERROR, DATABASE_ERROR, etc.)
- Phase tracking (INITIALIZING, FETCHING, MAPPING, VALIDATING, UPSERTING, DELETING, COMPLETING)
- Contextual metadata (syncId, entityType, phase, duration, record counts)
- Timing helpers for operations
- Update sync-service.ts with structured logging
- Replace console.log/error with structured logger
- Consistent error categorization across all error paths
- Fix swallowed errors in sync history updates
- Add child loggers for entity-specific operations
- Update entity-sync.ts with structured logging
- Complete phase tracking throughout sync lifecycle
- Detailed context for warnings and errors
- Update chunked sync methods with structured logging
- Update picklist sync methods (issue types, sub-issue types)
- Better debugging info with timing and sample data
- Add sync failure analysis script (scripts/analyze-sync-failures.ts)
- Query sync history by date range, entity type, or status
- Generate failure summaries by entity
- Automatic error categorization
- Calculate success rates and statistics
- Display detailed sync records with timing
- Add comprehensive documentation (docs/SYNC_LOGGING_IMPROVEMENTS.md)
- Usage guide and examples
- Migration guide for developers
- Before/after comparisons
This addresses inconsistent logging and improves debugging capabilities for sync operations.
2026-01-23 08:02:02 -05:00
|
|
|
entityLogger.phase(SyncPhase.DELETING, 'Checking for records to soft delete');
|
2025-11-19 14:18:16 -05:00
|
|
|
syncProgressTracker.updateProgress(trackingId, { phase: 'deleting' });
|
feat: QuickBooks Online integration
- Add QBO OAuth2 client with token refresh (lib/services/qbo-client.ts)
- Add QBO sync service for invoices, payments, deposits, purchases, journal entries, reports (lib/services/qbo-sync-service.ts)
- Add QBO types (lib/types/qbo.ts)
- Add API routes: /api/qbo/auth, /api/qbo/sync, /api/qbo/disconnect
- Add /admin/qbo status and sync management page
- Add legal pages: /legal/eula, /legal/privacy (Intuit app assessment)
- Add QBO nav link under Admin
- Fix reports: remove invalid summarize_column_by, add accounting_method from Preferences API, add showrows=all&showcols=all
- Add CashFlow report type alongside P&L and BalanceSheet
- Add NoReportData check to skip empty report months
- Add intuit_tid capture in error messages
- Add redirect: follow for cluster routing
- Migration 051: qbo_tokens, qbo_invoices, qbo_payments, qbo_deposits, qbo_transactions, qbo_reports tables
Also includes earlier work:
- Ping flap suppression pipeline step
- Ticket digest reports with LLM analysis
- Zabbix WAN monitor and gap analysis
- Kiosk is_deleted filter fixes
- Datto RMM ping target enrichment
- Entity sync soft-delete detection
2026-03-17 07:39:55 -04:00
|
|
|
|
2025-11-19 14:18:16 -05:00
|
|
|
try {
|
|
|
|
|
const activeIds = mappedRecords.map(r => r.id);
|
|
|
|
|
deletedCount = await softDeleteMissingRecords(entity, activeIds);
|
feat: implement structured logging for sync operations
- Add comprehensive structured logging utility (lib/utils/sync-logger.ts)
- Log levels: DEBUG, INFO, WARN, ERROR
- Automatic error categorization (NETWORK_ERROR, AUTH_ERROR, DATABASE_ERROR, etc.)
- Phase tracking (INITIALIZING, FETCHING, MAPPING, VALIDATING, UPSERTING, DELETING, COMPLETING)
- Contextual metadata (syncId, entityType, phase, duration, record counts)
- Timing helpers for operations
- Update sync-service.ts with structured logging
- Replace console.log/error with structured logger
- Consistent error categorization across all error paths
- Fix swallowed errors in sync history updates
- Add child loggers for entity-specific operations
- Update entity-sync.ts with structured logging
- Complete phase tracking throughout sync lifecycle
- Detailed context for warnings and errors
- Update chunked sync methods with structured logging
- Update picklist sync methods (issue types, sub-issue types)
- Better debugging info with timing and sample data
- Add sync failure analysis script (scripts/analyze-sync-failures.ts)
- Query sync history by date range, entity type, or status
- Generate failure summaries by entity
- Automatic error categorization
- Calculate success rates and statistics
- Display detailed sync records with timing
- Add comprehensive documentation (docs/SYNC_LOGGING_IMPROVEMENTS.md)
- Usage guide and examples
- Migration guide for developers
- Before/after comparisons
This addresses inconsistent logging and improves debugging capabilities for sync operations.
2026-01-23 08:02:02 -05:00
|
|
|
entityLogger.info('Soft deleted missing records', { deletedCount });
|
2025-11-19 14:18:16 -05:00
|
|
|
} catch (error) {
|
feat: implement structured logging for sync operations
- Add comprehensive structured logging utility (lib/utils/sync-logger.ts)
- Log levels: DEBUG, INFO, WARN, ERROR
- Automatic error categorization (NETWORK_ERROR, AUTH_ERROR, DATABASE_ERROR, etc.)
- Phase tracking (INITIALIZING, FETCHING, MAPPING, VALIDATING, UPSERTING, DELETING, COMPLETING)
- Contextual metadata (syncId, entityType, phase, duration, record counts)
- Timing helpers for operations
- Update sync-service.ts with structured logging
- Replace console.log/error with structured logger
- Consistent error categorization across all error paths
- Fix swallowed errors in sync history updates
- Add child loggers for entity-specific operations
- Update entity-sync.ts with structured logging
- Complete phase tracking throughout sync lifecycle
- Detailed context for warnings and errors
- Update chunked sync methods with structured logging
- Update picklist sync methods (issue types, sub-issue types)
- Better debugging info with timing and sample data
- Add sync failure analysis script (scripts/analyze-sync-failures.ts)
- Query sync history by date range, entity type, or status
- Generate failure summaries by entity
- Automatic error categorization
- Calculate success rates and statistics
- Display detailed sync records with timing
- Add comprehensive documentation (docs/SYNC_LOGGING_IMPROVEMENTS.md)
- Usage guide and examples
- Migration guide for developers
- Before/after comparisons
This addresses inconsistent logging and improves debugging capabilities for sync operations.
2026-01-23 08:02:02 -05:00
|
|
|
const err = error instanceof Error ? error : new Error(String(error));
|
|
|
|
|
entityLogger.warn('Soft delete failed, continuing sync', {}, err);
|
feat: QuickBooks Online integration
- Add QBO OAuth2 client with token refresh (lib/services/qbo-client.ts)
- Add QBO sync service for invoices, payments, deposits, purchases, journal entries, reports (lib/services/qbo-sync-service.ts)
- Add QBO types (lib/types/qbo.ts)
- Add API routes: /api/qbo/auth, /api/qbo/sync, /api/qbo/disconnect
- Add /admin/qbo status and sync management page
- Add legal pages: /legal/eula, /legal/privacy (Intuit app assessment)
- Add QBO nav link under Admin
- Fix reports: remove invalid summarize_column_by, add accounting_method from Preferences API, add showrows=all&showcols=all
- Add CashFlow report type alongside P&L and BalanceSheet
- Add NoReportData check to skip empty report months
- Add intuit_tid capture in error messages
- Add redirect: follow for cluster routing
- Migration 051: qbo_tokens, qbo_invoices, qbo_payments, qbo_deposits, qbo_transactions, qbo_reports tables
Also includes earlier work:
- Ping flap suppression pipeline step
- Ticket digest reports with LLM analysis
- Zabbix WAN monitor and gap analysis
- Kiosk is_deleted filter fixes
- Datto RMM ping target enrichment
- Entity sync soft-delete detection
2026-03-17 07:39:55 -04:00
|
|
|
}
|
|
|
|
|
} else if (!isIncremental && hasAppliedFilters && entity === EntityType.TICKETS) {
|
|
|
|
|
entityLogger.phase(SyncPhase.DELETING, 'Fetching all Autotask ticket IDs for deletion diff');
|
|
|
|
|
syncProgressTracker.updateProgress(trackingId, { phase: 'deleting' });
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
// Fetch all ticket IDs from Autotask with no filters for deletion diff
|
|
|
|
|
const allAutotaskTickets = await this.autotaskClient.queryEntityPaginated(
|
|
|
|
|
'Tickets',
|
|
|
|
|
{},
|
|
|
|
|
500
|
|
|
|
|
);
|
|
|
|
|
const liveIds = new Set(allAutotaskTickets.map((t: any) => String(t.id)));
|
|
|
|
|
|
|
|
|
|
// Find Pulse ticket IDs not present in Autotask → these were deleted
|
|
|
|
|
const pulseResult = await postgresClient.query(
|
|
|
|
|
`SELECT id FROM tickets WHERE is_deleted = false`
|
|
|
|
|
);
|
|
|
|
|
const toDelete = pulseResult.rows
|
|
|
|
|
.map((r: { id: number }) => r.id)
|
|
|
|
|
.filter((id: number) => !liveIds.has(String(id)));
|
|
|
|
|
|
|
|
|
|
if (toDelete.length > 0) {
|
|
|
|
|
const result = await postgresClient.query(
|
|
|
|
|
`UPDATE tickets
|
|
|
|
|
SET is_deleted = true, deleted_at = CURRENT_TIMESTAMP
|
|
|
|
|
WHERE id = ANY($1::int[])`,
|
|
|
|
|
[toDelete]
|
|
|
|
|
);
|
|
|
|
|
deletedCount = result.rowCount || 0;
|
|
|
|
|
entityLogger.info('Soft deleted tickets missing from Autotask', { deletedCount });
|
|
|
|
|
} else {
|
|
|
|
|
entityLogger.info('No deleted tickets detected');
|
|
|
|
|
}
|
|
|
|
|
} catch (error) {
|
|
|
|
|
const err = error instanceof Error ? error : new Error(String(error));
|
|
|
|
|
entityLogger.warn('Ticket deletion diff failed, continuing sync', {}, err);
|
2025-11-19 14:18:16 -05:00
|
|
|
}
|
2026-01-24 09:57:01 -05:00
|
|
|
} else if (!isIncremental && hasAppliedFilters) {
|
|
|
|
|
entityLogger.info('Skipping soft-delete because filters were applied (would delete records outside filter criteria)');
|
2025-11-19 14:18:16 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Calculate added vs updated (simplified - actual count would require tracking)
|
|
|
|
|
const recordsAdded = Math.floor(upsertedCount * 0.1); // Estimate 10% new
|
|
|
|
|
const recordsUpdated = upsertedCount - recordsAdded;
|
|
|
|
|
|
|
|
|
|
// Mark sync as completed
|
feat: implement structured logging for sync operations
- Add comprehensive structured logging utility (lib/utils/sync-logger.ts)
- Log levels: DEBUG, INFO, WARN, ERROR
- Automatic error categorization (NETWORK_ERROR, AUTH_ERROR, DATABASE_ERROR, etc.)
- Phase tracking (INITIALIZING, FETCHING, MAPPING, VALIDATING, UPSERTING, DELETING, COMPLETING)
- Contextual metadata (syncId, entityType, phase, duration, record counts)
- Timing helpers for operations
- Update sync-service.ts with structured logging
- Replace console.log/error with structured logger
- Consistent error categorization across all error paths
- Fix swallowed errors in sync history updates
- Add child loggers for entity-specific operations
- Update entity-sync.ts with structured logging
- Complete phase tracking throughout sync lifecycle
- Detailed context for warnings and errors
- Update chunked sync methods with structured logging
- Update picklist sync methods (issue types, sub-issue types)
- Better debugging info with timing and sample data
- Add sync failure analysis script (scripts/analyze-sync-failures.ts)
- Query sync history by date range, entity type, or status
- Generate failure summaries by entity
- Automatic error categorization
- Calculate success rates and statistics
- Display detailed sync records with timing
- Add comprehensive documentation (docs/SYNC_LOGGING_IMPROVEMENTS.md)
- Usage guide and examples
- Migration guide for developers
- Before/after comparisons
This addresses inconsistent logging and improves debugging capabilities for sync operations.
2026-01-23 08:02:02 -05:00
|
|
|
entityLogger.phase(SyncPhase.COMPLETING);
|
2025-11-19 14:18:16 -05:00
|
|
|
syncProgressTracker.completeSync(trackingId, mappedRecords.length);
|
feat: implement structured logging for sync operations
- Add comprehensive structured logging utility (lib/utils/sync-logger.ts)
- Log levels: DEBUG, INFO, WARN, ERROR
- Automatic error categorization (NETWORK_ERROR, AUTH_ERROR, DATABASE_ERROR, etc.)
- Phase tracking (INITIALIZING, FETCHING, MAPPING, VALIDATING, UPSERTING, DELETING, COMPLETING)
- Contextual metadata (syncId, entityType, phase, duration, record counts)
- Timing helpers for operations
- Update sync-service.ts with structured logging
- Replace console.log/error with structured logger
- Consistent error categorization across all error paths
- Fix swallowed errors in sync history updates
- Add child loggers for entity-specific operations
- Update entity-sync.ts with structured logging
- Complete phase tracking throughout sync lifecycle
- Detailed context for warnings and errors
- Update chunked sync methods with structured logging
- Update picklist sync methods (issue types, sub-issue types)
- Better debugging info with timing and sample data
- Add sync failure analysis script (scripts/analyze-sync-failures.ts)
- Query sync history by date range, entity type, or status
- Generate failure summaries by entity
- Automatic error categorization
- Calculate success rates and statistics
- Display detailed sync records with timing
- Add comprehensive documentation (docs/SYNC_LOGGING_IMPROVEMENTS.md)
- Usage guide and examples
- Migration guide for developers
- Before/after comparisons
This addresses inconsistent logging and improves debugging capabilities for sync operations.
2026-01-23 08:02:02 -05:00
|
|
|
entityLogger.complete(`${entity} sync`, syncStartTime, {
|
|
|
|
|
recordsAdded,
|
|
|
|
|
recordsUpdated,
|
|
|
|
|
recordsDeleted: deletedCount,
|
|
|
|
|
});
|
2025-11-19 14:18:16 -05:00
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
recordsAdded,
|
|
|
|
|
recordsUpdated,
|
|
|
|
|
recordsDeleted: deletedCount,
|
|
|
|
|
};
|
|
|
|
|
} catch (error) {
|
feat: implement structured logging for sync operations
- Add comprehensive structured logging utility (lib/utils/sync-logger.ts)
- Log levels: DEBUG, INFO, WARN, ERROR
- Automatic error categorization (NETWORK_ERROR, AUTH_ERROR, DATABASE_ERROR, etc.)
- Phase tracking (INITIALIZING, FETCHING, MAPPING, VALIDATING, UPSERTING, DELETING, COMPLETING)
- Contextual metadata (syncId, entityType, phase, duration, record counts)
- Timing helpers for operations
- Update sync-service.ts with structured logging
- Replace console.log/error with structured logger
- Consistent error categorization across all error paths
- Fix swallowed errors in sync history updates
- Add child loggers for entity-specific operations
- Update entity-sync.ts with structured logging
- Complete phase tracking throughout sync lifecycle
- Detailed context for warnings and errors
- Update chunked sync methods with structured logging
- Update picklist sync methods (issue types, sub-issue types)
- Better debugging info with timing and sample data
- Add sync failure analysis script (scripts/analyze-sync-failures.ts)
- Query sync history by date range, entity type, or status
- Generate failure summaries by entity
- Automatic error categorization
- Calculate success rates and statistics
- Display detailed sync records with timing
- Add comprehensive documentation (docs/SYNC_LOGGING_IMPROVEMENTS.md)
- Usage guide and examples
- Migration guide for developers
- Before/after comparisons
This addresses inconsistent logging and improves debugging capabilities for sync operations.
2026-01-23 08:02:02 -05:00
|
|
|
const err = error instanceof Error ? error : new Error(String(error));
|
2025-11-19 14:18:16 -05:00
|
|
|
|
|
|
|
|
// Mark sync as failed
|
feat: implement structured logging for sync operations
- Add comprehensive structured logging utility (lib/utils/sync-logger.ts)
- Log levels: DEBUG, INFO, WARN, ERROR
- Automatic error categorization (NETWORK_ERROR, AUTH_ERROR, DATABASE_ERROR, etc.)
- Phase tracking (INITIALIZING, FETCHING, MAPPING, VALIDATING, UPSERTING, DELETING, COMPLETING)
- Contextual metadata (syncId, entityType, phase, duration, record counts)
- Timing helpers for operations
- Update sync-service.ts with structured logging
- Replace console.log/error with structured logger
- Consistent error categorization across all error paths
- Fix swallowed errors in sync history updates
- Add child loggers for entity-specific operations
- Update entity-sync.ts with structured logging
- Complete phase tracking throughout sync lifecycle
- Detailed context for warnings and errors
- Update chunked sync methods with structured logging
- Update picklist sync methods (issue types, sub-issue types)
- Better debugging info with timing and sample data
- Add sync failure analysis script (scripts/analyze-sync-failures.ts)
- Query sync history by date range, entity type, or status
- Generate failure summaries by entity
- Automatic error categorization
- Calculate success rates and statistics
- Display detailed sync records with timing
- Add comprehensive documentation (docs/SYNC_LOGGING_IMPROVEMENTS.md)
- Usage guide and examples
- Migration guide for developers
- Before/after comparisons
This addresses inconsistent logging and improves debugging capabilities for sync operations.
2026-01-23 08:02:02 -05:00
|
|
|
syncProgressTracker.failSync(trackingId, err.message);
|
|
|
|
|
entityLogger.fail(`${entity} sync`, syncStartTime, err);
|
2025-11-19 14:18:16 -05:00
|
|
|
|
|
|
|
|
throw error;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Sync Companies
|
|
|
|
|
*/
|
|
|
|
|
async syncCompanies(isIncremental: boolean = false): Promise<EntitySyncStats> {
|
|
|
|
|
return await this.syncEntity(EntityType.COMPANIES, isIncremental);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Sync Tickets
|
|
|
|
|
*/
|
|
|
|
|
async syncTickets(isIncremental: boolean = false, yearsBack?: number): Promise<EntitySyncStats> {
|
|
|
|
|
return await this.syncEntity(EntityType.TICKETS, isIncremental, yearsBack);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Sync Tickets with Monthly Chunking
|
|
|
|
|
* Breaks large date ranges into monthly chunks to prevent timeouts and API failures
|
|
|
|
|
* @param yearsBack Number of years to look back
|
|
|
|
|
* @param onChunkProgress Callback for progress updates
|
|
|
|
|
* @returns Aggregated sync statistics
|
|
|
|
|
*/
|
|
|
|
|
async syncTicketsChunked(
|
|
|
|
|
yearsBack: number = 2,
|
|
|
|
|
onChunkProgress?: (chunk: { index: number; total: number; description: string; recordsProcessed: number }) => void
|
|
|
|
|
): Promise<EntitySyncStats> {
|
|
|
|
|
const entity = EntityType.TICKETS;
|
feat: implement structured logging for sync operations
- Add comprehensive structured logging utility (lib/utils/sync-logger.ts)
- Log levels: DEBUG, INFO, WARN, ERROR
- Automatic error categorization (NETWORK_ERROR, AUTH_ERROR, DATABASE_ERROR, etc.)
- Phase tracking (INITIALIZING, FETCHING, MAPPING, VALIDATING, UPSERTING, DELETING, COMPLETING)
- Contextual metadata (syncId, entityType, phase, duration, record counts)
- Timing helpers for operations
- Update sync-service.ts with structured logging
- Replace console.log/error with structured logger
- Consistent error categorization across all error paths
- Fix swallowed errors in sync history updates
- Add child loggers for entity-specific operations
- Update entity-sync.ts with structured logging
- Complete phase tracking throughout sync lifecycle
- Detailed context for warnings and errors
- Update chunked sync methods with structured logging
- Update picklist sync methods (issue types, sub-issue types)
- Better debugging info with timing and sample data
- Add sync failure analysis script (scripts/analyze-sync-failures.ts)
- Query sync history by date range, entity type, or status
- Generate failure summaries by entity
- Automatic error categorization
- Calculate success rates and statistics
- Display detailed sync records with timing
- Add comprehensive documentation (docs/SYNC_LOGGING_IMPROVEMENTS.md)
- Usage guide and examples
- Migration guide for developers
- Before/after comparisons
This addresses inconsistent logging and improves debugging capabilities for sync operations.
2026-01-23 08:02:02 -05:00
|
|
|
const chunkLogger = this.logger.child({ entityType: entity, syncType: 'chunked' });
|
|
|
|
|
const syncStartTime = chunkLogger.start(`Chunked sync for last ${yearsBack} years`);
|
2025-11-19 14:18:16 -05:00
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
// Calculate date chunks (monthly)
|
|
|
|
|
const chunks = this.calculateMonthlyChunks(yearsBack);
|
feat: implement structured logging for sync operations
- Add comprehensive structured logging utility (lib/utils/sync-logger.ts)
- Log levels: DEBUG, INFO, WARN, ERROR
- Automatic error categorization (NETWORK_ERROR, AUTH_ERROR, DATABASE_ERROR, etc.)
- Phase tracking (INITIALIZING, FETCHING, MAPPING, VALIDATING, UPSERTING, DELETING, COMPLETING)
- Contextual metadata (syncId, entityType, phase, duration, record counts)
- Timing helpers for operations
- Update sync-service.ts with structured logging
- Replace console.log/error with structured logger
- Consistent error categorization across all error paths
- Fix swallowed errors in sync history updates
- Add child loggers for entity-specific operations
- Update entity-sync.ts with structured logging
- Complete phase tracking throughout sync lifecycle
- Detailed context for warnings and errors
- Update chunked sync methods with structured logging
- Update picklist sync methods (issue types, sub-issue types)
- Better debugging info with timing and sample data
- Add sync failure analysis script (scripts/analyze-sync-failures.ts)
- Query sync history by date range, entity type, or status
- Generate failure summaries by entity
- Automatic error categorization
- Calculate success rates and statistics
- Display detailed sync records with timing
- Add comprehensive documentation (docs/SYNC_LOGGING_IMPROVEMENTS.md)
- Usage guide and examples
- Migration guide for developers
- Before/after comparisons
This addresses inconsistent logging and improves debugging capabilities for sync operations.
2026-01-23 08:02:02 -05:00
|
|
|
chunkLogger.info('Split into monthly chunks', { chunkCount: chunks.length, yearsBack });
|
2025-11-19 14:18:16 -05:00
|
|
|
|
|
|
|
|
let totalRecordsAdded = 0;
|
|
|
|
|
let totalRecordsUpdated = 0;
|
|
|
|
|
let totalRecordsDeleted = 0;
|
|
|
|
|
const failedChunks: string[] = [];
|
|
|
|
|
|
|
|
|
|
// Process each chunk
|
|
|
|
|
for (let i = 0; i < chunks.length; i++) {
|
|
|
|
|
const chunk = chunks[i];
|
|
|
|
|
const chunkDescription = `${chunk.startDate.toLocaleDateString('en-US', { month: 'short', year: 'numeric' })}`;
|
|
|
|
|
|
feat: implement structured logging for sync operations
- Add comprehensive structured logging utility (lib/utils/sync-logger.ts)
- Log levels: DEBUG, INFO, WARN, ERROR
- Automatic error categorization (NETWORK_ERROR, AUTH_ERROR, DATABASE_ERROR, etc.)
- Phase tracking (INITIALIZING, FETCHING, MAPPING, VALIDATING, UPSERTING, DELETING, COMPLETING)
- Contextual metadata (syncId, entityType, phase, duration, record counts)
- Timing helpers for operations
- Update sync-service.ts with structured logging
- Replace console.log/error with structured logger
- Consistent error categorization across all error paths
- Fix swallowed errors in sync history updates
- Add child loggers for entity-specific operations
- Update entity-sync.ts with structured logging
- Complete phase tracking throughout sync lifecycle
- Detailed context for warnings and errors
- Update chunked sync methods with structured logging
- Update picklist sync methods (issue types, sub-issue types)
- Better debugging info with timing and sample data
- Add sync failure analysis script (scripts/analyze-sync-failures.ts)
- Query sync history by date range, entity type, or status
- Generate failure summaries by entity
- Automatic error categorization
- Calculate success rates and statistics
- Display detailed sync records with timing
- Add comprehensive documentation (docs/SYNC_LOGGING_IMPROVEMENTS.md)
- Usage guide and examples
- Migration guide for developers
- Before/after comparisons
This addresses inconsistent logging and improves debugging capabilities for sync operations.
2026-01-23 08:02:02 -05:00
|
|
|
chunkLogger.info(`Processing chunk ${i + 1}/${chunks.length}`, { chunkDescription });
|
2025-11-19 14:18:16 -05:00
|
|
|
|
|
|
|
|
// Notify progress
|
|
|
|
|
if (onChunkProgress) {
|
|
|
|
|
onChunkProgress({
|
|
|
|
|
index: i + 1,
|
|
|
|
|
total: chunks.length,
|
|
|
|
|
description: chunkDescription,
|
|
|
|
|
recordsProcessed: totalRecordsAdded + totalRecordsUpdated,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
// Fetch tickets for this date range
|
|
|
|
|
const autotaskEntityName = getAutotaskEntityName(entity);
|
|
|
|
|
const filters = [
|
|
|
|
|
{ field: 'createDate', op: 'gte' as const, value: chunk.startDate.toISOString() },
|
|
|
|
|
{ field: 'createDate', op: 'lt' as const, value: chunk.endDate.toISOString() },
|
|
|
|
|
];
|
|
|
|
|
|
feat: implement structured logging for sync operations
- Add comprehensive structured logging utility (lib/utils/sync-logger.ts)
- Log levels: DEBUG, INFO, WARN, ERROR
- Automatic error categorization (NETWORK_ERROR, AUTH_ERROR, DATABASE_ERROR, etc.)
- Phase tracking (INITIALIZING, FETCHING, MAPPING, VALIDATING, UPSERTING, DELETING, COMPLETING)
- Contextual metadata (syncId, entityType, phase, duration, record counts)
- Timing helpers for operations
- Update sync-service.ts with structured logging
- Replace console.log/error with structured logger
- Consistent error categorization across all error paths
- Fix swallowed errors in sync history updates
- Add child loggers for entity-specific operations
- Update entity-sync.ts with structured logging
- Complete phase tracking throughout sync lifecycle
- Detailed context for warnings and errors
- Update chunked sync methods with structured logging
- Update picklist sync methods (issue types, sub-issue types)
- Better debugging info with timing and sample data
- Add sync failure analysis script (scripts/analyze-sync-failures.ts)
- Query sync history by date range, entity type, or status
- Generate failure summaries by entity
- Automatic error categorization
- Calculate success rates and statistics
- Display detailed sync records with timing
- Add comprehensive documentation (docs/SYNC_LOGGING_IMPROVEMENTS.md)
- Usage guide and examples
- Migration guide for developers
- Before/after comparisons
This addresses inconsistent logging and improves debugging capabilities for sync operations.
2026-01-23 08:02:02 -05:00
|
|
|
chunkLogger.debug('Fetching records for chunk', {
|
|
|
|
|
chunkIndex: i + 1,
|
|
|
|
|
startDate: chunk.startDate.toISOString(),
|
|
|
|
|
endDate: chunk.endDate.toISOString(),
|
|
|
|
|
});
|
2025-11-19 14:18:16 -05:00
|
|
|
|
|
|
|
|
const autotaskRecords = await this.autotaskClient.queryEntityPaginated(
|
|
|
|
|
autotaskEntityName,
|
|
|
|
|
{ filter: filters },
|
|
|
|
|
500
|
|
|
|
|
);
|
|
|
|
|
|
feat: implement structured logging for sync operations
- Add comprehensive structured logging utility (lib/utils/sync-logger.ts)
- Log levels: DEBUG, INFO, WARN, ERROR
- Automatic error categorization (NETWORK_ERROR, AUTH_ERROR, DATABASE_ERROR, etc.)
- Phase tracking (INITIALIZING, FETCHING, MAPPING, VALIDATING, UPSERTING, DELETING, COMPLETING)
- Contextual metadata (syncId, entityType, phase, duration, record counts)
- Timing helpers for operations
- Update sync-service.ts with structured logging
- Replace console.log/error with structured logger
- Consistent error categorization across all error paths
- Fix swallowed errors in sync history updates
- Add child loggers for entity-specific operations
- Update entity-sync.ts with structured logging
- Complete phase tracking throughout sync lifecycle
- Detailed context for warnings and errors
- Update chunked sync methods with structured logging
- Update picklist sync methods (issue types, sub-issue types)
- Better debugging info with timing and sample data
- Add sync failure analysis script (scripts/analyze-sync-failures.ts)
- Query sync history by date range, entity type, or status
- Generate failure summaries by entity
- Automatic error categorization
- Calculate success rates and statistics
- Display detailed sync records with timing
- Add comprehensive documentation (docs/SYNC_LOGGING_IMPROVEMENTS.md)
- Usage guide and examples
- Migration guide for developers
- Before/after comparisons
This addresses inconsistent logging and improves debugging capabilities for sync operations.
2026-01-23 08:02:02 -05:00
|
|
|
chunkLogger.info(`Chunk ${i + 1}: Fetched records`, { recordCount: autotaskRecords.length });
|
2025-11-19 14:18:16 -05:00
|
|
|
|
|
|
|
|
if (autotaskRecords.length > 0) {
|
|
|
|
|
// Map and upsert records
|
|
|
|
|
let mappedRecords = mapAutotaskBatch(entity, autotaskRecords);
|
|
|
|
|
|
|
|
|
|
// Filter out records without company_id
|
feat: implement structured logging for sync operations
- Add comprehensive structured logging utility (lib/utils/sync-logger.ts)
- Log levels: DEBUG, INFO, WARN, ERROR
- Automatic error categorization (NETWORK_ERROR, AUTH_ERROR, DATABASE_ERROR, etc.)
- Phase tracking (INITIALIZING, FETCHING, MAPPING, VALIDATING, UPSERTING, DELETING, COMPLETING)
- Contextual metadata (syncId, entityType, phase, duration, record counts)
- Timing helpers for operations
- Update sync-service.ts with structured logging
- Replace console.log/error with structured logger
- Consistent error categorization across all error paths
- Fix swallowed errors in sync history updates
- Add child loggers for entity-specific operations
- Update entity-sync.ts with structured logging
- Complete phase tracking throughout sync lifecycle
- Detailed context for warnings and errors
- Update chunked sync methods with structured logging
- Update picklist sync methods (issue types, sub-issue types)
- Better debugging info with timing and sample data
- Add sync failure analysis script (scripts/analyze-sync-failures.ts)
- Query sync history by date range, entity type, or status
- Generate failure summaries by entity
- Automatic error categorization
- Calculate success rates and statistics
- Display detailed sync records with timing
- Add comprehensive documentation (docs/SYNC_LOGGING_IMPROVEMENTS.md)
- Usage guide and examples
- Migration guide for developers
- Before/after comparisons
This addresses inconsistent logging and improves debugging capabilities for sync operations.
2026-01-23 08:02:02 -05:00
|
|
|
const beforeFilter = mappedRecords.length;
|
2025-11-19 14:18:16 -05:00
|
|
|
mappedRecords = mappedRecords.filter(r => r.company_id);
|
feat: implement structured logging for sync operations
- Add comprehensive structured logging utility (lib/utils/sync-logger.ts)
- Log levels: DEBUG, INFO, WARN, ERROR
- Automatic error categorization (NETWORK_ERROR, AUTH_ERROR, DATABASE_ERROR, etc.)
- Phase tracking (INITIALIZING, FETCHING, MAPPING, VALIDATING, UPSERTING, DELETING, COMPLETING)
- Contextual metadata (syncId, entityType, phase, duration, record counts)
- Timing helpers for operations
- Update sync-service.ts with structured logging
- Replace console.log/error with structured logger
- Consistent error categorization across all error paths
- Fix swallowed errors in sync history updates
- Add child loggers for entity-specific operations
- Update entity-sync.ts with structured logging
- Complete phase tracking throughout sync lifecycle
- Detailed context for warnings and errors
- Update chunked sync methods with structured logging
- Update picklist sync methods (issue types, sub-issue types)
- Better debugging info with timing and sample data
- Add sync failure analysis script (scripts/analyze-sync-failures.ts)
- Query sync history by date range, entity type, or status
- Generate failure summaries by entity
- Automatic error categorization
- Calculate success rates and statistics
- Display detailed sync records with timing
- Add comprehensive documentation (docs/SYNC_LOGGING_IMPROVEMENTS.md)
- Usage guide and examples
- Migration guide for developers
- Before/after comparisons
This addresses inconsistent logging and improves debugging capabilities for sync operations.
2026-01-23 08:02:02 -05:00
|
|
|
if (mappedRecords.length < beforeFilter) {
|
|
|
|
|
chunkLogger.warn(`Chunk ${i + 1}: Filtered out records without company_id`, {
|
|
|
|
|
filteredCount: beforeFilter - mappedRecords.length,
|
|
|
|
|
});
|
2025-11-19 14:18:16 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Validate resource foreign keys (fetch once per sync, not per chunk)
|
|
|
|
|
if (i === 0) {
|
|
|
|
|
// Cache valid resource IDs for all chunks
|
|
|
|
|
this.cachedValidResourceIds = await this.getValidResourceIds();
|
feat: implement structured logging for sync operations
- Add comprehensive structured logging utility (lib/utils/sync-logger.ts)
- Log levels: DEBUG, INFO, WARN, ERROR
- Automatic error categorization (NETWORK_ERROR, AUTH_ERROR, DATABASE_ERROR, etc.)
- Phase tracking (INITIALIZING, FETCHING, MAPPING, VALIDATING, UPSERTING, DELETING, COMPLETING)
- Contextual metadata (syncId, entityType, phase, duration, record counts)
- Timing helpers for operations
- Update sync-service.ts with structured logging
- Replace console.log/error with structured logger
- Consistent error categorization across all error paths
- Fix swallowed errors in sync history updates
- Add child loggers for entity-specific operations
- Update entity-sync.ts with structured logging
- Complete phase tracking throughout sync lifecycle
- Detailed context for warnings and errors
- Update chunked sync methods with structured logging
- Update picklist sync methods (issue types, sub-issue types)
- Better debugging info with timing and sample data
- Add sync failure analysis script (scripts/analyze-sync-failures.ts)
- Query sync history by date range, entity type, or status
- Generate failure summaries by entity
- Automatic error categorization
- Calculate success rates and statistics
- Display detailed sync records with timing
- Add comprehensive documentation (docs/SYNC_LOGGING_IMPROVEMENTS.md)
- Usage guide and examples
- Migration guide for developers
- Before/after comparisons
This addresses inconsistent logging and improves debugging capabilities for sync operations.
2026-01-23 08:02:02 -05:00
|
|
|
chunkLogger.info('Cached valid resource IDs', { cacheSize: this.cachedValidResourceIds.size });
|
2025-11-19 14:18:16 -05:00
|
|
|
}
|
|
|
|
|
|
2026-04-05 08:55:41 -04:00
|
|
|
// Null out unknown resource references — bulkUpsert uses COALESCE so existing DB value is preserved
|
2025-11-19 14:18:16 -05:00
|
|
|
mappedRecords = mappedRecords.map(ticket => {
|
|
|
|
|
if (ticket.assigned_resource_id && !this.cachedValidResourceIds!.has(ticket.assigned_resource_id)) {
|
|
|
|
|
ticket.assigned_resource_id = null;
|
|
|
|
|
}
|
|
|
|
|
if (ticket.first_response_assigned_resource_id && !this.cachedValidResourceIds!.has(ticket.first_response_assigned_resource_id)) {
|
|
|
|
|
ticket.first_response_assigned_resource_id = null;
|
|
|
|
|
}
|
|
|
|
|
if (ticket.first_response_initiating_resource_id && !this.cachedValidResourceIds!.has(ticket.first_response_initiating_resource_id)) {
|
|
|
|
|
ticket.first_response_initiating_resource_id = null;
|
|
|
|
|
}
|
|
|
|
|
return ticket;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (mappedRecords.length > 0) {
|
|
|
|
|
const upsertedCount = await bulkUpsertRecords(entity, mappedRecords, 100);
|
feat: add Autotask tags sync (tag groups, tags, ticket tag associations)
- Migration 057: autotask_tag_groups, autotask_tags, and junction tables
(ticket_tags, company_tags, configuration_item_tags, contact_tags)
- Add TAG_GROUPS and TAGS to EntityType enum and dependency map
- Add mapTagGroup() and mapTag() entity mapper functions
- Add syncTagGroups(), syncTags(), syncTicketTagAssociations() methods
- Wire TicketTagAssociations bulk sync into full/incremental sync flow
- Add 'exist' operator to QueryFilter type
- No FK on ticket_id (tagged tickets may be outside 2yr sync window)
Synced: 26 tag groups, 7299 tags, 10141 ticket-tag associations
2026-03-20 09:22:40 -04:00
|
|
|
|
2025-11-19 14:18:16 -05:00
|
|
|
// Estimate added vs updated
|
|
|
|
|
const recordsAdded = Math.floor(upsertedCount * 0.1);
|
|
|
|
|
const recordsUpdated = upsertedCount - recordsAdded;
|
|
|
|
|
|
|
|
|
|
totalRecordsAdded += recordsAdded;
|
|
|
|
|
totalRecordsUpdated += recordsUpdated;
|
|
|
|
|
|
feat: implement structured logging for sync operations
- Add comprehensive structured logging utility (lib/utils/sync-logger.ts)
- Log levels: DEBUG, INFO, WARN, ERROR
- Automatic error categorization (NETWORK_ERROR, AUTH_ERROR, DATABASE_ERROR, etc.)
- Phase tracking (INITIALIZING, FETCHING, MAPPING, VALIDATING, UPSERTING, DELETING, COMPLETING)
- Contextual metadata (syncId, entityType, phase, duration, record counts)
- Timing helpers for operations
- Update sync-service.ts with structured logging
- Replace console.log/error with structured logger
- Consistent error categorization across all error paths
- Fix swallowed errors in sync history updates
- Add child loggers for entity-specific operations
- Update entity-sync.ts with structured logging
- Complete phase tracking throughout sync lifecycle
- Detailed context for warnings and errors
- Update chunked sync methods with structured logging
- Update picklist sync methods (issue types, sub-issue types)
- Better debugging info with timing and sample data
- Add sync failure analysis script (scripts/analyze-sync-failures.ts)
- Query sync history by date range, entity type, or status
- Generate failure summaries by entity
- Automatic error categorization
- Calculate success rates and statistics
- Display detailed sync records with timing
- Add comprehensive documentation (docs/SYNC_LOGGING_IMPROVEMENTS.md)
- Usage guide and examples
- Migration guide for developers
- Before/after comparisons
This addresses inconsistent logging and improves debugging capabilities for sync operations.
2026-01-23 08:02:02 -05:00
|
|
|
chunkLogger.info(`Chunk ${i + 1}: Upserted records`, {
|
|
|
|
|
upsertedCount,
|
|
|
|
|
recordsAdded,
|
|
|
|
|
recordsUpdated,
|
|
|
|
|
});
|
2025-11-19 14:18:16 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} catch (error) {
|
feat: implement structured logging for sync operations
- Add comprehensive structured logging utility (lib/utils/sync-logger.ts)
- Log levels: DEBUG, INFO, WARN, ERROR
- Automatic error categorization (NETWORK_ERROR, AUTH_ERROR, DATABASE_ERROR, etc.)
- Phase tracking (INITIALIZING, FETCHING, MAPPING, VALIDATING, UPSERTING, DELETING, COMPLETING)
- Contextual metadata (syncId, entityType, phase, duration, record counts)
- Timing helpers for operations
- Update sync-service.ts with structured logging
- Replace console.log/error with structured logger
- Consistent error categorization across all error paths
- Fix swallowed errors in sync history updates
- Add child loggers for entity-specific operations
- Update entity-sync.ts with structured logging
- Complete phase tracking throughout sync lifecycle
- Detailed context for warnings and errors
- Update chunked sync methods with structured logging
- Update picklist sync methods (issue types, sub-issue types)
- Better debugging info with timing and sample data
- Add sync failure analysis script (scripts/analyze-sync-failures.ts)
- Query sync history by date range, entity type, or status
- Generate failure summaries by entity
- Automatic error categorization
- Calculate success rates and statistics
- Display detailed sync records with timing
- Add comprehensive documentation (docs/SYNC_LOGGING_IMPROVEMENTS.md)
- Usage guide and examples
- Migration guide for developers
- Before/after comparisons
This addresses inconsistent logging and improves debugging capabilities for sync operations.
2026-01-23 08:02:02 -05:00
|
|
|
const err = error instanceof Error ? error : new Error(String(error));
|
|
|
|
|
const errorCategory = categorizeError(err);
|
|
|
|
|
chunkLogger.error(`Chunk ${i + 1} (${chunkDescription}) failed`, {
|
|
|
|
|
chunkIndex: i + 1,
|
|
|
|
|
chunkDescription,
|
|
|
|
|
errorCategory,
|
|
|
|
|
}, err);
|
|
|
|
|
failedChunks.push(`${chunkDescription}: ${err.message}`);
|
2025-11-19 14:18:16 -05:00
|
|
|
// Continue with next chunk instead of failing entire sync
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
feat: implement structured logging for sync operations
- Add comprehensive structured logging utility (lib/utils/sync-logger.ts)
- Log levels: DEBUG, INFO, WARN, ERROR
- Automatic error categorization (NETWORK_ERROR, AUTH_ERROR, DATABASE_ERROR, etc.)
- Phase tracking (INITIALIZING, FETCHING, MAPPING, VALIDATING, UPSERTING, DELETING, COMPLETING)
- Contextual metadata (syncId, entityType, phase, duration, record counts)
- Timing helpers for operations
- Update sync-service.ts with structured logging
- Replace console.log/error with structured logger
- Consistent error categorization across all error paths
- Fix swallowed errors in sync history updates
- Add child loggers for entity-specific operations
- Update entity-sync.ts with structured logging
- Complete phase tracking throughout sync lifecycle
- Detailed context for warnings and errors
- Update chunked sync methods with structured logging
- Update picklist sync methods (issue types, sub-issue types)
- Better debugging info with timing and sample data
- Add sync failure analysis script (scripts/analyze-sync-failures.ts)
- Query sync history by date range, entity type, or status
- Generate failure summaries by entity
- Automatic error categorization
- Calculate success rates and statistics
- Display detailed sync records with timing
- Add comprehensive documentation (docs/SYNC_LOGGING_IMPROVEMENTS.md)
- Usage guide and examples
- Migration guide for developers
- Before/after comparisons
This addresses inconsistent logging and improves debugging capabilities for sync operations.
2026-01-23 08:02:02 -05:00
|
|
|
chunkLogger.complete('Chunked sync', syncStartTime, {
|
|
|
|
|
totalRecordsAdded,
|
|
|
|
|
totalRecordsUpdated,
|
|
|
|
|
totalRecordsDeleted,
|
|
|
|
|
totalChunks: chunks.length,
|
|
|
|
|
failedChunks: failedChunks.length,
|
|
|
|
|
});
|
2025-11-19 14:18:16 -05:00
|
|
|
|
|
|
|
|
if (failedChunks.length > 0) {
|
feat: implement structured logging for sync operations
- Add comprehensive structured logging utility (lib/utils/sync-logger.ts)
- Log levels: DEBUG, INFO, WARN, ERROR
- Automatic error categorization (NETWORK_ERROR, AUTH_ERROR, DATABASE_ERROR, etc.)
- Phase tracking (INITIALIZING, FETCHING, MAPPING, VALIDATING, UPSERTING, DELETING, COMPLETING)
- Contextual metadata (syncId, entityType, phase, duration, record counts)
- Timing helpers for operations
- Update sync-service.ts with structured logging
- Replace console.log/error with structured logger
- Consistent error categorization across all error paths
- Fix swallowed errors in sync history updates
- Add child loggers for entity-specific operations
- Update entity-sync.ts with structured logging
- Complete phase tracking throughout sync lifecycle
- Detailed context for warnings and errors
- Update chunked sync methods with structured logging
- Update picklist sync methods (issue types, sub-issue types)
- Better debugging info with timing and sample data
- Add sync failure analysis script (scripts/analyze-sync-failures.ts)
- Query sync history by date range, entity type, or status
- Generate failure summaries by entity
- Automatic error categorization
- Calculate success rates and statistics
- Display detailed sync records with timing
- Add comprehensive documentation (docs/SYNC_LOGGING_IMPROVEMENTS.md)
- Usage guide and examples
- Migration guide for developers
- Before/after comparisons
This addresses inconsistent logging and improves debugging capabilities for sync operations.
2026-01-23 08:02:02 -05:00
|
|
|
chunkLogger.warn('Some chunks failed', { failedChunks });
|
2025-11-19 14:18:16 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
recordsAdded: totalRecordsAdded,
|
|
|
|
|
recordsUpdated: totalRecordsUpdated,
|
|
|
|
|
recordsDeleted: totalRecordsDeleted,
|
|
|
|
|
};
|
|
|
|
|
} catch (error) {
|
feat: implement structured logging for sync operations
- Add comprehensive structured logging utility (lib/utils/sync-logger.ts)
- Log levels: DEBUG, INFO, WARN, ERROR
- Automatic error categorization (NETWORK_ERROR, AUTH_ERROR, DATABASE_ERROR, etc.)
- Phase tracking (INITIALIZING, FETCHING, MAPPING, VALIDATING, UPSERTING, DELETING, COMPLETING)
- Contextual metadata (syncId, entityType, phase, duration, record counts)
- Timing helpers for operations
- Update sync-service.ts with structured logging
- Replace console.log/error with structured logger
- Consistent error categorization across all error paths
- Fix swallowed errors in sync history updates
- Add child loggers for entity-specific operations
- Update entity-sync.ts with structured logging
- Complete phase tracking throughout sync lifecycle
- Detailed context for warnings and errors
- Update chunked sync methods with structured logging
- Update picklist sync methods (issue types, sub-issue types)
- Better debugging info with timing and sample data
- Add sync failure analysis script (scripts/analyze-sync-failures.ts)
- Query sync history by date range, entity type, or status
- Generate failure summaries by entity
- Automatic error categorization
- Calculate success rates and statistics
- Display detailed sync records with timing
- Add comprehensive documentation (docs/SYNC_LOGGING_IMPROVEMENTS.md)
- Usage guide and examples
- Migration guide for developers
- Before/after comparisons
This addresses inconsistent logging and improves debugging capabilities for sync operations.
2026-01-23 08:02:02 -05:00
|
|
|
const err = error instanceof Error ? error : new Error(String(error));
|
|
|
|
|
chunkLogger.fail('Chunked sync', syncStartTime, err);
|
2025-11-19 14:18:16 -05:00
|
|
|
throw error;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get all valid resource IDs from the database
|
|
|
|
|
* Used to validate foreign key references before insert
|
|
|
|
|
* @returns Set of valid resource IDs
|
|
|
|
|
*/
|
|
|
|
|
private async getValidResourceIds(): Promise<Set<number>> {
|
2026-04-05 08:55:41 -04:00
|
|
|
const query = 'SELECT id FROM resources WHERE is_deleted = false';
|
|
|
|
|
const result = await postgresClient.query<{ id: number }>(query);
|
|
|
|
|
return new Set(result.rows.map(row => Number(row.id)));
|
2025-11-19 14:18:16 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Used to validate foreign key references before insert
|
|
|
|
|
* @returns Set of valid contact IDs
|
|
|
|
|
*/
|
|
|
|
|
private async getValidContactIds(): Promise<Set<number>> {
|
|
|
|
|
try {
|
|
|
|
|
const query = 'SELECT id FROM contacts WHERE is_deleted = false';
|
|
|
|
|
const result = await postgresClient.query<{ id: number }>(query);
|
2026-04-05 08:55:41 -04:00
|
|
|
return new Set(result.rows.map(row => Number(row.id)));
|
2025-11-19 14:18:16 -05:00
|
|
|
} catch (error) {
|
feat: implement structured logging for sync operations
- Add comprehensive structured logging utility (lib/utils/sync-logger.ts)
- Log levels: DEBUG, INFO, WARN, ERROR
- Automatic error categorization (NETWORK_ERROR, AUTH_ERROR, DATABASE_ERROR, etc.)
- Phase tracking (INITIALIZING, FETCHING, MAPPING, VALIDATING, UPSERTING, DELETING, COMPLETING)
- Contextual metadata (syncId, entityType, phase, duration, record counts)
- Timing helpers for operations
- Update sync-service.ts with structured logging
- Replace console.log/error with structured logger
- Consistent error categorization across all error paths
- Fix swallowed errors in sync history updates
- Add child loggers for entity-specific operations
- Update entity-sync.ts with structured logging
- Complete phase tracking throughout sync lifecycle
- Detailed context for warnings and errors
- Update chunked sync methods with structured logging
- Update picklist sync methods (issue types, sub-issue types)
- Better debugging info with timing and sample data
- Add sync failure analysis script (scripts/analyze-sync-failures.ts)
- Query sync history by date range, entity type, or status
- Generate failure summaries by entity
- Automatic error categorization
- Calculate success rates and statistics
- Display detailed sync records with timing
- Add comprehensive documentation (docs/SYNC_LOGGING_IMPROVEMENTS.md)
- Usage guide and examples
- Migration guide for developers
- Before/after comparisons
This addresses inconsistent logging and improves debugging capabilities for sync operations.
2026-01-23 08:02:02 -05:00
|
|
|
const err = error instanceof Error ? error : new Error(String(error));
|
|
|
|
|
this.logger.error('Failed to fetch valid contact IDs', {}, err);
|
2025-11-19 14:18:16 -05:00
|
|
|
// Return empty set on error - will cause all contact IDs to be nullified
|
|
|
|
|
return new Set();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-24 08:09:10 -05:00
|
|
|
/**
|
|
|
|
|
* Get all valid project IDs from the database
|
|
|
|
|
* Used to validate foreign key references before insert
|
|
|
|
|
* @returns Set of valid project IDs
|
|
|
|
|
*/
|
|
|
|
|
private async getValidProjectIds(): Promise<Set<number>> {
|
|
|
|
|
try {
|
|
|
|
|
const query = 'SELECT id FROM projects WHERE is_deleted = false';
|
|
|
|
|
const result = await postgresClient.query<{ id: number }>(query);
|
2026-04-05 08:55:41 -04:00
|
|
|
return new Set(result.rows.map(row => Number(row.id)));
|
2026-01-24 08:09:10 -05:00
|
|
|
} catch (error) {
|
|
|
|
|
const err = error instanceof Error ? error : new Error(String(error));
|
|
|
|
|
this.logger.error('Failed to fetch valid project IDs', {}, err);
|
|
|
|
|
// Return empty set on error - will cause all project IDs to be nullified
|
|
|
|
|
return new Set();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-19 14:18:16 -05:00
|
|
|
/**
|
|
|
|
|
* Calculate monthly date chunks for a given time period
|
|
|
|
|
* @param yearsBack Number of years to look back
|
|
|
|
|
* @returns Array of date range chunks
|
|
|
|
|
*/
|
|
|
|
|
private calculateMonthlyChunks(yearsBack: number): Array<{ startDate: Date; endDate: Date }> {
|
|
|
|
|
const chunks: Array<{ startDate: Date; endDate: Date }> = [];
|
|
|
|
|
const now = new Date();
|
|
|
|
|
const startDate = new Date(now);
|
|
|
|
|
startDate.setFullYear(now.getFullYear() - yearsBack);
|
|
|
|
|
startDate.setHours(0, 0, 0, 0);
|
|
|
|
|
|
|
|
|
|
let currentDate = new Date(startDate);
|
|
|
|
|
|
|
|
|
|
while (currentDate < now) {
|
|
|
|
|
const chunkStart = new Date(currentDate);
|
|
|
|
|
|
|
|
|
|
// Move to next month
|
|
|
|
|
const chunkEnd = new Date(currentDate);
|
|
|
|
|
chunkEnd.setMonth(chunkEnd.getMonth() + 1);
|
|
|
|
|
|
|
|
|
|
// Don't go beyond current date
|
|
|
|
|
if (chunkEnd > now) {
|
|
|
|
|
chunkEnd.setTime(now.getTime());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
chunks.push({
|
|
|
|
|
startDate: chunkStart,
|
|
|
|
|
endDate: chunkEnd,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
currentDate = new Date(chunkEnd);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return chunks;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Sync Tasks
|
|
|
|
|
*/
|
|
|
|
|
async syncTasks(isIncremental: boolean = false): Promise<EntitySyncStats> {
|
|
|
|
|
return await this.syncEntity(EntityType.TASKS, isIncremental);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Sync Projects
|
|
|
|
|
*/
|
|
|
|
|
async syncProjects(isIncremental: boolean = false): Promise<EntitySyncStats> {
|
|
|
|
|
return await this.syncEntity(EntityType.PROJECTS, isIncremental);
|
|
|
|
|
}
|
|
|
|
|
|
feat: add project_phases entity sync with task project_id backfill
The Autotask Tasks bulk API does not return projectID in its response,
causing all tasks.project_id to be NULL. This fixes it by:
- Adding project_phases as a synced entity (Autotask endpoint: /Phases)
- Migration 059: project_phases table with project_id, phase_number,
estimated_hours, start/due dates, parent_phase_id, is_scheduled
- EntityType.PROJECT_PHASES added to all sync maps and dependency graph
(depends on PROJECTS, runs before TASKS in sync order)
- buildProjectPhasesFilter: Phases endpoint requires a filter (id > 0)
- mapProjectPhase: maps Autotask field names to DB columns
- Post-sync backfill in syncEntity: after each project_phases sync,
UPDATE tasks SET project_id = pp.project_id FROM project_phases pp
JOIN projects p WHERE tasks.phase_id = pp.id
Only backfills where the project exists in our DB (FK constraint on
tasks.project_id; archived projects are skipped gracefully)
Result: 2,455 of 4,966 tasks now have project_id populated. Tasks
belonging to archived/completed projects have phase_id resolvable via
project_phases even when project_id remains NULL.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-24 13:57:33 -04:00
|
|
|
/**
|
|
|
|
|
* Sync Project Phases, then backfill project_id on tasks that reference those phases.
|
|
|
|
|
* Autotask's Tasks bulk query does not return projectID — it must be resolved via phaseID.
|
|
|
|
|
*/
|
|
|
|
|
async syncProjectPhases(isIncremental: boolean = false): Promise<EntitySyncStats> {
|
|
|
|
|
const stats = await this.syncEntity(EntityType.PROJECT_PHASES, isIncremental);
|
|
|
|
|
|
|
|
|
|
// Backfill tasks.project_id using the newly synced phases
|
|
|
|
|
try {
|
|
|
|
|
const result = await postgresClient.query<{ rowCount: number }>(
|
|
|
|
|
`UPDATE tasks
|
|
|
|
|
SET project_id = pp.project_id
|
|
|
|
|
FROM project_phases pp
|
|
|
|
|
WHERE tasks.phase_id = pp.id
|
|
|
|
|
AND tasks.project_id IS DISTINCT FROM pp.project_id
|
|
|
|
|
AND pp.project_id IS NOT NULL`
|
|
|
|
|
);
|
|
|
|
|
const updated = (result as any).rowCount ?? 0;
|
|
|
|
|
if (updated > 0) {
|
|
|
|
|
this.logger.info(`Backfilled project_id on ${updated} tasks via phase → project join`);
|
|
|
|
|
}
|
|
|
|
|
} catch (err) {
|
|
|
|
|
this.logger.warn('Task project_id backfill failed', { error: String(err) });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return stats;
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-19 14:18:16 -05:00
|
|
|
/**
|
|
|
|
|
* Sync Resources (Users)
|
|
|
|
|
*/
|
|
|
|
|
async syncResources(isIncremental: boolean = false): Promise<EntitySyncStats> {
|
|
|
|
|
return await this.syncEntity(EntityType.RESOURCES, isIncremental);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Sync Configuration Items
|
|
|
|
|
*/
|
|
|
|
|
async syncConfigurationItems(isIncremental: boolean = false): Promise<EntitySyncStats> {
|
|
|
|
|
return await this.syncEntity(EntityType.CONFIGURATION_ITEMS, isIncremental);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Sync Contacts
|
|
|
|
|
*/
|
|
|
|
|
async syncContacts(isIncremental: boolean = false): Promise<EntitySyncStats> {
|
|
|
|
|
return await this.syncEntity(EntityType.CONTACTS, isIncremental);
|
|
|
|
|
}
|
|
|
|
|
|
feat: Veeam RPO analysis, comparison, ticket analysis + company teams table
- Add Veeam RPO analysis page (/veeam-analysis) and comparison page (/veeam-comparison)
- Add API routes: /api/veeam/rpo-analyze, rpo-comparison, rpo-offline-log, ticket-analysis
- Add veeam-rpo-service.ts enhancements (RPO logic, offline detection, comparison)
- Add veeam-analysis-state.ts and rmm-device-resolver.ts services
- Add migrations 065-068: company_teams, veeam_rpo_offline_log, rpo_comparison_tables, veeam_ticket_analysis
- Add backup-status page updates and nav links for new Veeam pages
- Add scripts: deactivate-cis-for-inactive-companies, workstation category updates
- Add docs: mimecast-api-guide, veeam-backup-alerting-recommendation, workstation-backup-overview, ticket-analyzer-prompt
- Minor: webhook-service, entity-sync, entity-mapper, sync-helpers, sync.ts, middleware.ts updates
2026-04-29 09:16:46 -04:00
|
|
|
/**
|
|
|
|
|
* Sync Company Teams (TAMs, CSMs, co-managed resources assigned to a company)
|
|
|
|
|
*/
|
|
|
|
|
async syncCompanyTeams(isIncremental: boolean = false): Promise<EntitySyncStats> {
|
|
|
|
|
return await this.syncEntity(EntityType.COMPANY_TEAMS, isIncremental);
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-19 14:18:16 -05:00
|
|
|
/**
|
|
|
|
|
* Sync Contracts
|
|
|
|
|
*/
|
|
|
|
|
async syncContracts(isIncremental: boolean = false): Promise<EntitySyncStats> {
|
|
|
|
|
return await this.syncEntity(EntityType.CONTRACTS, isIncremental);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Sync Billing Items
|
|
|
|
|
*/
|
|
|
|
|
async syncBillingItems(isIncremental: boolean = false): Promise<EntitySyncStats> {
|
|
|
|
|
return await this.syncEntity(EntityType.BILLING_ITEMS, isIncremental);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2026-01-23 17:02:09 -05:00
|
|
|
* Sync Statuses (Picklist from Ticket field)
|
2025-11-19 14:18:16 -05:00
|
|
|
*/
|
|
|
|
|
async syncStatuses(isIncremental: boolean = false): Promise<EntitySyncStats> {
|
2026-01-23 17:02:09 -05:00
|
|
|
const picklistLogger = this.logger.child({ entityType: EntityType.STATUSES, syncType: 'picklist' });
|
|
|
|
|
const syncStartTime = picklistLogger.start('Picklist sync');
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
// Get status picklist values from Tickets entity
|
|
|
|
|
const picklistValues = await this.autotaskClient.getPicklistValues('Tickets', 'status');
|
|
|
|
|
|
|
|
|
|
// Convert picklist to database format
|
|
|
|
|
const records = Object.entries(picklistValues).map(([value, label]) => ({
|
|
|
|
|
value: parseInt(value),
|
|
|
|
|
label: label,
|
|
|
|
|
is_active: true,
|
|
|
|
|
sort_order: parseInt(value),
|
|
|
|
|
synced_at: new Date(),
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
picklistLogger.info('Found picklist values', { recordCount: records.length });
|
|
|
|
|
|
2026-01-24 08:47:52 -05:00
|
|
|
// Get existing values to calculate added vs updated
|
2026-01-23 17:02:09 -05:00
|
|
|
const tableName = getTableName(EntityType.STATUSES);
|
2026-01-24 08:47:52 -05:00
|
|
|
const existingQuery = `SELECT value FROM ${tableName}`;
|
|
|
|
|
const existingResult = await postgresClient.query<{ value: number }>(existingQuery);
|
|
|
|
|
const existingValues = new Set(existingResult.rows.map((r: any) => r.value));
|
|
|
|
|
|
|
|
|
|
const recordsAdded = records.filter((r: any) => !existingValues.has(r.value)).length;
|
|
|
|
|
const recordsUpdated = records.filter((r: any) => existingValues.has(r.value)).length;
|
|
|
|
|
|
|
|
|
|
// Upsert to database
|
|
|
|
|
await postgresClient.bulkUpsert(tableName, records, ['value']);
|
2026-01-23 17:02:09 -05:00
|
|
|
|
|
|
|
|
const stats: EntitySyncStats = {
|
2026-01-24 08:47:52 -05:00
|
|
|
recordsAdded,
|
|
|
|
|
recordsUpdated,
|
2026-01-23 17:02:09 -05:00
|
|
|
recordsDeleted: 0,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
picklistLogger.complete('Picklist sync', syncStartTime, {
|
|
|
|
|
recordsAdded: stats.recordsAdded,
|
|
|
|
|
recordsUpdated: stats.recordsUpdated,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return stats;
|
|
|
|
|
} catch (error) {
|
|
|
|
|
const err = error instanceof Error ? error : new Error(String(error));
|
|
|
|
|
picklistLogger.fail('Picklist sync', syncStartTime, err);
|
|
|
|
|
throw error;
|
|
|
|
|
}
|
2025-11-19 14:18:16 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Sync Issue Types (Picklist from Ticket field)
|
|
|
|
|
*/
|
|
|
|
|
async syncIssueTypes(isIncremental: boolean = false): Promise<EntitySyncStats> {
|
feat: implement structured logging for sync operations
- Add comprehensive structured logging utility (lib/utils/sync-logger.ts)
- Log levels: DEBUG, INFO, WARN, ERROR
- Automatic error categorization (NETWORK_ERROR, AUTH_ERROR, DATABASE_ERROR, etc.)
- Phase tracking (INITIALIZING, FETCHING, MAPPING, VALIDATING, UPSERTING, DELETING, COMPLETING)
- Contextual metadata (syncId, entityType, phase, duration, record counts)
- Timing helpers for operations
- Update sync-service.ts with structured logging
- Replace console.log/error with structured logger
- Consistent error categorization across all error paths
- Fix swallowed errors in sync history updates
- Add child loggers for entity-specific operations
- Update entity-sync.ts with structured logging
- Complete phase tracking throughout sync lifecycle
- Detailed context for warnings and errors
- Update chunked sync methods with structured logging
- Update picklist sync methods (issue types, sub-issue types)
- Better debugging info with timing and sample data
- Add sync failure analysis script (scripts/analyze-sync-failures.ts)
- Query sync history by date range, entity type, or status
- Generate failure summaries by entity
- Automatic error categorization
- Calculate success rates and statistics
- Display detailed sync records with timing
- Add comprehensive documentation (docs/SYNC_LOGGING_IMPROVEMENTS.md)
- Usage guide and examples
- Migration guide for developers
- Before/after comparisons
This addresses inconsistent logging and improves debugging capabilities for sync operations.
2026-01-23 08:02:02 -05:00
|
|
|
const picklistLogger = this.logger.child({ entityType: EntityType.ISSUE_TYPES, syncType: 'picklist' });
|
|
|
|
|
const syncStartTime = picklistLogger.start('Picklist sync');
|
2025-11-19 14:18:16 -05:00
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
// Get issue type picklist values from Tickets entity
|
|
|
|
|
const picklistValues = await this.autotaskClient.getPicklistValues('Tickets', 'issueType');
|
|
|
|
|
|
|
|
|
|
// Convert picklist to database format
|
|
|
|
|
const records = Object.entries(picklistValues).map(([value, label]) => ({
|
|
|
|
|
value: parseInt(value),
|
|
|
|
|
label: label,
|
|
|
|
|
is_active: true,
|
|
|
|
|
sort_order: parseInt(value),
|
|
|
|
|
synced_at: new Date(),
|
|
|
|
|
}));
|
|
|
|
|
|
feat: implement structured logging for sync operations
- Add comprehensive structured logging utility (lib/utils/sync-logger.ts)
- Log levels: DEBUG, INFO, WARN, ERROR
- Automatic error categorization (NETWORK_ERROR, AUTH_ERROR, DATABASE_ERROR, etc.)
- Phase tracking (INITIALIZING, FETCHING, MAPPING, VALIDATING, UPSERTING, DELETING, COMPLETING)
- Contextual metadata (syncId, entityType, phase, duration, record counts)
- Timing helpers for operations
- Update sync-service.ts with structured logging
- Replace console.log/error with structured logger
- Consistent error categorization across all error paths
- Fix swallowed errors in sync history updates
- Add child loggers for entity-specific operations
- Update entity-sync.ts with structured logging
- Complete phase tracking throughout sync lifecycle
- Detailed context for warnings and errors
- Update chunked sync methods with structured logging
- Update picklist sync methods (issue types, sub-issue types)
- Better debugging info with timing and sample data
- Add sync failure analysis script (scripts/analyze-sync-failures.ts)
- Query sync history by date range, entity type, or status
- Generate failure summaries by entity
- Automatic error categorization
- Calculate success rates and statistics
- Display detailed sync records with timing
- Add comprehensive documentation (docs/SYNC_LOGGING_IMPROVEMENTS.md)
- Usage guide and examples
- Migration guide for developers
- Before/after comparisons
This addresses inconsistent logging and improves debugging capabilities for sync operations.
2026-01-23 08:02:02 -05:00
|
|
|
picklistLogger.info('Found picklist values', { recordCount: records.length });
|
2025-11-19 14:18:16 -05:00
|
|
|
|
2026-01-24 08:47:52 -05:00
|
|
|
// Get existing values to calculate added vs updated
|
2025-11-19 14:18:16 -05:00
|
|
|
const tableName = getTableName(EntityType.ISSUE_TYPES);
|
2026-01-24 08:47:52 -05:00
|
|
|
const existingQuery = `SELECT value FROM ${tableName}`;
|
|
|
|
|
const existingResult = await postgresClient.query<{ value: number }>(existingQuery);
|
|
|
|
|
const existingValues = new Set(existingResult.rows.map((r: any) => r.value));
|
|
|
|
|
|
|
|
|
|
const recordsAdded = records.filter((r: any) => !existingValues.has(r.value)).length;
|
|
|
|
|
const recordsUpdated = records.filter((r: any) => existingValues.has(r.value)).length;
|
|
|
|
|
|
|
|
|
|
// Upsert to database
|
|
|
|
|
await postgresClient.bulkUpsert(tableName, records, ['value']);
|
2025-11-19 14:18:16 -05:00
|
|
|
|
|
|
|
|
const stats: EntitySyncStats = {
|
2026-01-24 08:47:52 -05:00
|
|
|
recordsAdded,
|
|
|
|
|
recordsUpdated,
|
2025-11-19 14:18:16 -05:00
|
|
|
recordsDeleted: 0,
|
|
|
|
|
};
|
|
|
|
|
|
feat: implement structured logging for sync operations
- Add comprehensive structured logging utility (lib/utils/sync-logger.ts)
- Log levels: DEBUG, INFO, WARN, ERROR
- Automatic error categorization (NETWORK_ERROR, AUTH_ERROR, DATABASE_ERROR, etc.)
- Phase tracking (INITIALIZING, FETCHING, MAPPING, VALIDATING, UPSERTING, DELETING, COMPLETING)
- Contextual metadata (syncId, entityType, phase, duration, record counts)
- Timing helpers for operations
- Update sync-service.ts with structured logging
- Replace console.log/error with structured logger
- Consistent error categorization across all error paths
- Fix swallowed errors in sync history updates
- Add child loggers for entity-specific operations
- Update entity-sync.ts with structured logging
- Complete phase tracking throughout sync lifecycle
- Detailed context for warnings and errors
- Update chunked sync methods with structured logging
- Update picklist sync methods (issue types, sub-issue types)
- Better debugging info with timing and sample data
- Add sync failure analysis script (scripts/analyze-sync-failures.ts)
- Query sync history by date range, entity type, or status
- Generate failure summaries by entity
- Automatic error categorization
- Calculate success rates and statistics
- Display detailed sync records with timing
- Add comprehensive documentation (docs/SYNC_LOGGING_IMPROVEMENTS.md)
- Usage guide and examples
- Migration guide for developers
- Before/after comparisons
This addresses inconsistent logging and improves debugging capabilities for sync operations.
2026-01-23 08:02:02 -05:00
|
|
|
picklistLogger.complete('Picklist sync', syncStartTime, {
|
|
|
|
|
recordsAdded: stats.recordsAdded,
|
|
|
|
|
recordsUpdated: stats.recordsUpdated,
|
|
|
|
|
});
|
2025-11-19 14:18:16 -05:00
|
|
|
|
|
|
|
|
return stats;
|
|
|
|
|
} catch (error) {
|
feat: implement structured logging for sync operations
- Add comprehensive structured logging utility (lib/utils/sync-logger.ts)
- Log levels: DEBUG, INFO, WARN, ERROR
- Automatic error categorization (NETWORK_ERROR, AUTH_ERROR, DATABASE_ERROR, etc.)
- Phase tracking (INITIALIZING, FETCHING, MAPPING, VALIDATING, UPSERTING, DELETING, COMPLETING)
- Contextual metadata (syncId, entityType, phase, duration, record counts)
- Timing helpers for operations
- Update sync-service.ts with structured logging
- Replace console.log/error with structured logger
- Consistent error categorization across all error paths
- Fix swallowed errors in sync history updates
- Add child loggers for entity-specific operations
- Update entity-sync.ts with structured logging
- Complete phase tracking throughout sync lifecycle
- Detailed context for warnings and errors
- Update chunked sync methods with structured logging
- Update picklist sync methods (issue types, sub-issue types)
- Better debugging info with timing and sample data
- Add sync failure analysis script (scripts/analyze-sync-failures.ts)
- Query sync history by date range, entity type, or status
- Generate failure summaries by entity
- Automatic error categorization
- Calculate success rates and statistics
- Display detailed sync records with timing
- Add comprehensive documentation (docs/SYNC_LOGGING_IMPROVEMENTS.md)
- Usage guide and examples
- Migration guide for developers
- Before/after comparisons
This addresses inconsistent logging and improves debugging capabilities for sync operations.
2026-01-23 08:02:02 -05:00
|
|
|
const err = error instanceof Error ? error : new Error(String(error));
|
|
|
|
|
picklistLogger.fail('Picklist sync', syncStartTime, err);
|
2025-11-19 14:18:16 -05:00
|
|
|
throw error;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Sync Sub-Issue Types (Picklist from Ticket field)
|
|
|
|
|
*/
|
|
|
|
|
async syncSubIssueTypes(isIncremental: boolean = false): Promise<EntitySyncStats> {
|
feat: implement structured logging for sync operations
- Add comprehensive structured logging utility (lib/utils/sync-logger.ts)
- Log levels: DEBUG, INFO, WARN, ERROR
- Automatic error categorization (NETWORK_ERROR, AUTH_ERROR, DATABASE_ERROR, etc.)
- Phase tracking (INITIALIZING, FETCHING, MAPPING, VALIDATING, UPSERTING, DELETING, COMPLETING)
- Contextual metadata (syncId, entityType, phase, duration, record counts)
- Timing helpers for operations
- Update sync-service.ts with structured logging
- Replace console.log/error with structured logger
- Consistent error categorization across all error paths
- Fix swallowed errors in sync history updates
- Add child loggers for entity-specific operations
- Update entity-sync.ts with structured logging
- Complete phase tracking throughout sync lifecycle
- Detailed context for warnings and errors
- Update chunked sync methods with structured logging
- Update picklist sync methods (issue types, sub-issue types)
- Better debugging info with timing and sample data
- Add sync failure analysis script (scripts/analyze-sync-failures.ts)
- Query sync history by date range, entity type, or status
- Generate failure summaries by entity
- Automatic error categorization
- Calculate success rates and statistics
- Display detailed sync records with timing
- Add comprehensive documentation (docs/SYNC_LOGGING_IMPROVEMENTS.md)
- Usage guide and examples
- Migration guide for developers
- Before/after comparisons
This addresses inconsistent logging and improves debugging capabilities for sync operations.
2026-01-23 08:02:02 -05:00
|
|
|
const picklistLogger = this.logger.child({ entityType: EntityType.SUB_ISSUE_TYPES, syncType: 'picklist' });
|
|
|
|
|
const syncStartTime = picklistLogger.start('Picklist sync');
|
2025-11-19 14:18:16 -05:00
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
// Get sub-issue type picklist values from Tickets entity
|
|
|
|
|
const url = `${this.autotaskClient['config'].apiUrl}/Tickets/entityInformation/fields`;
|
|
|
|
|
const response = await fetch(url, {
|
|
|
|
|
method: 'GET',
|
|
|
|
|
headers: this.autotaskClient['getAuthHeaders'](),
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const responseText = await response.text();
|
|
|
|
|
if (!response.ok) {
|
|
|
|
|
throw new Error(`Failed to fetch field info: ${responseText}`);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const fieldData = JSON.parse(responseText);
|
|
|
|
|
const subIssueTypeField = fieldData.fields.find((f: any) => f.name === 'subIssueType');
|
|
|
|
|
|
|
|
|
|
if (!subIssueTypeField || !subIssueTypeField.picklistValues) {
|
|
|
|
|
throw new Error('subIssueType field or picklist values not found');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Convert picklist to database format, capturing parent value if it exists
|
|
|
|
|
const records = subIssueTypeField.picklistValues.map((item: any) => ({
|
|
|
|
|
value: parseInt(item.value),
|
|
|
|
|
label: item.label,
|
|
|
|
|
is_active: item.isActive !== false,
|
|
|
|
|
parent_value: item.parentValue ? parseInt(item.parentValue) : null,
|
|
|
|
|
sort_order: item.sortOrder || parseInt(item.value),
|
|
|
|
|
synced_at: new Date(),
|
|
|
|
|
}));
|
|
|
|
|
|
feat: implement structured logging for sync operations
- Add comprehensive structured logging utility (lib/utils/sync-logger.ts)
- Log levels: DEBUG, INFO, WARN, ERROR
- Automatic error categorization (NETWORK_ERROR, AUTH_ERROR, DATABASE_ERROR, etc.)
- Phase tracking (INITIALIZING, FETCHING, MAPPING, VALIDATING, UPSERTING, DELETING, COMPLETING)
- Contextual metadata (syncId, entityType, phase, duration, record counts)
- Timing helpers for operations
- Update sync-service.ts with structured logging
- Replace console.log/error with structured logger
- Consistent error categorization across all error paths
- Fix swallowed errors in sync history updates
- Add child loggers for entity-specific operations
- Update entity-sync.ts with structured logging
- Complete phase tracking throughout sync lifecycle
- Detailed context for warnings and errors
- Update chunked sync methods with structured logging
- Update picklist sync methods (issue types, sub-issue types)
- Better debugging info with timing and sample data
- Add sync failure analysis script (scripts/analyze-sync-failures.ts)
- Query sync history by date range, entity type, or status
- Generate failure summaries by entity
- Automatic error categorization
- Calculate success rates and statistics
- Display detailed sync records with timing
- Add comprehensive documentation (docs/SYNC_LOGGING_IMPROVEMENTS.md)
- Usage guide and examples
- Migration guide for developers
- Before/after comparisons
This addresses inconsistent logging and improves debugging capabilities for sync operations.
2026-01-23 08:02:02 -05:00
|
|
|
picklistLogger.info('Found picklist values', { recordCount: records.length });
|
2025-11-19 14:18:16 -05:00
|
|
|
|
2026-01-24 08:47:52 -05:00
|
|
|
// Get existing values to calculate added vs updated
|
2025-11-19 14:18:16 -05:00
|
|
|
const tableName = getTableName(EntityType.SUB_ISSUE_TYPES);
|
2026-01-24 08:47:52 -05:00
|
|
|
const existingQuery = `SELECT value FROM ${tableName}`;
|
|
|
|
|
const existingResult = await postgresClient.query<{ value: number }>(existingQuery);
|
|
|
|
|
const existingValues = new Set(existingResult.rows.map(r => r.value));
|
|
|
|
|
|
|
|
|
|
const recordsAdded = records.filter((r: any) => !existingValues.has(r.value)).length;
|
|
|
|
|
const recordsUpdated = records.filter((r: any) => existingValues.has(r.value)).length;
|
|
|
|
|
|
|
|
|
|
// Upsert to database
|
|
|
|
|
await postgresClient.bulkUpsert(tableName, records, ['value']);
|
2025-11-19 14:18:16 -05:00
|
|
|
|
|
|
|
|
const stats: EntitySyncStats = {
|
2026-01-24 08:47:52 -05:00
|
|
|
recordsAdded,
|
|
|
|
|
recordsUpdated,
|
2025-11-19 14:18:16 -05:00
|
|
|
recordsDeleted: 0,
|
|
|
|
|
};
|
|
|
|
|
|
feat: implement structured logging for sync operations
- Add comprehensive structured logging utility (lib/utils/sync-logger.ts)
- Log levels: DEBUG, INFO, WARN, ERROR
- Automatic error categorization (NETWORK_ERROR, AUTH_ERROR, DATABASE_ERROR, etc.)
- Phase tracking (INITIALIZING, FETCHING, MAPPING, VALIDATING, UPSERTING, DELETING, COMPLETING)
- Contextual metadata (syncId, entityType, phase, duration, record counts)
- Timing helpers for operations
- Update sync-service.ts with structured logging
- Replace console.log/error with structured logger
- Consistent error categorization across all error paths
- Fix swallowed errors in sync history updates
- Add child loggers for entity-specific operations
- Update entity-sync.ts with structured logging
- Complete phase tracking throughout sync lifecycle
- Detailed context for warnings and errors
- Update chunked sync methods with structured logging
- Update picklist sync methods (issue types, sub-issue types)
- Better debugging info with timing and sample data
- Add sync failure analysis script (scripts/analyze-sync-failures.ts)
- Query sync history by date range, entity type, or status
- Generate failure summaries by entity
- Automatic error categorization
- Calculate success rates and statistics
- Display detailed sync records with timing
- Add comprehensive documentation (docs/SYNC_LOGGING_IMPROVEMENTS.md)
- Usage guide and examples
- Migration guide for developers
- Before/after comparisons
This addresses inconsistent logging and improves debugging capabilities for sync operations.
2026-01-23 08:02:02 -05:00
|
|
|
picklistLogger.complete('Picklist sync', syncStartTime, {
|
|
|
|
|
recordsAdded: stats.recordsAdded,
|
|
|
|
|
recordsUpdated: stats.recordsUpdated,
|
|
|
|
|
});
|
2025-11-19 14:18:16 -05:00
|
|
|
|
|
|
|
|
return stats;
|
|
|
|
|
} catch (error) {
|
feat: implement structured logging for sync operations
- Add comprehensive structured logging utility (lib/utils/sync-logger.ts)
- Log levels: DEBUG, INFO, WARN, ERROR
- Automatic error categorization (NETWORK_ERROR, AUTH_ERROR, DATABASE_ERROR, etc.)
- Phase tracking (INITIALIZING, FETCHING, MAPPING, VALIDATING, UPSERTING, DELETING, COMPLETING)
- Contextual metadata (syncId, entityType, phase, duration, record counts)
- Timing helpers for operations
- Update sync-service.ts with structured logging
- Replace console.log/error with structured logger
- Consistent error categorization across all error paths
- Fix swallowed errors in sync history updates
- Add child loggers for entity-specific operations
- Update entity-sync.ts with structured logging
- Complete phase tracking throughout sync lifecycle
- Detailed context for warnings and errors
- Update chunked sync methods with structured logging
- Update picklist sync methods (issue types, sub-issue types)
- Better debugging info with timing and sample data
- Add sync failure analysis script (scripts/analyze-sync-failures.ts)
- Query sync history by date range, entity type, or status
- Generate failure summaries by entity
- Automatic error categorization
- Calculate success rates and statistics
- Display detailed sync records with timing
- Add comprehensive documentation (docs/SYNC_LOGGING_IMPROVEMENTS.md)
- Usage guide and examples
- Migration guide for developers
- Before/after comparisons
This addresses inconsistent logging and improves debugging capabilities for sync operations.
2026-01-23 08:02:02 -05:00
|
|
|
const err = error instanceof Error ? error : new Error(String(error));
|
|
|
|
|
picklistLogger.fail('Picklist sync', syncStartTime, err);
|
2025-11-19 14:18:16 -05:00
|
|
|
throw error;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-20 10:28:15 -05:00
|
|
|
/**
|
|
|
|
|
* Sync Queues (Picklist from Ticket field)
|
|
|
|
|
*/
|
|
|
|
|
async syncQueues(isIncremental: boolean = false): Promise<EntitySyncStats> {
|
|
|
|
|
const picklistLogger = this.logger.child({ entityType: EntityType.QUEUES, syncType: 'picklist' });
|
|
|
|
|
const syncStartTime = picklistLogger.start('Picklist sync');
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
const picklistValues = await this.autotaskClient.getPicklistValues('Tickets', 'queueID');
|
|
|
|
|
|
|
|
|
|
const records = Object.entries(picklistValues).map(([value, label]) => ({
|
|
|
|
|
value: parseInt(value),
|
|
|
|
|
label: label,
|
|
|
|
|
is_active: true,
|
|
|
|
|
sort_order: parseInt(value),
|
|
|
|
|
synced_at: new Date(),
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
picklistLogger.info('Found picklist values', { recordCount: records.length });
|
|
|
|
|
|
|
|
|
|
const tableName = getTableName(EntityType.QUEUES);
|
|
|
|
|
const existingQuery = `SELECT value FROM ${tableName}`;
|
|
|
|
|
const existingResult = await postgresClient.query<{ value: number }>(existingQuery);
|
|
|
|
|
const existingValues = new Set(existingResult.rows.map((r: any) => r.value));
|
|
|
|
|
|
|
|
|
|
const recordsAdded = records.filter((r: any) => !existingValues.has(r.value)).length;
|
|
|
|
|
const recordsUpdated = records.filter((r: any) => existingValues.has(r.value)).length;
|
|
|
|
|
|
|
|
|
|
await postgresClient.bulkUpsert(tableName, records, ['value']);
|
|
|
|
|
|
|
|
|
|
const stats: EntitySyncStats = { recordsAdded, recordsUpdated, recordsDeleted: 0 };
|
|
|
|
|
|
|
|
|
|
picklistLogger.complete('Picklist sync', syncStartTime, {
|
|
|
|
|
recordsAdded: stats.recordsAdded,
|
|
|
|
|
recordsUpdated: stats.recordsUpdated,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return stats;
|
|
|
|
|
} catch (error) {
|
|
|
|
|
const err = error instanceof Error ? error : new Error(String(error));
|
|
|
|
|
picklistLogger.fail('Picklist sync', syncStartTime, err);
|
|
|
|
|
throw error;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Sync Priorities (Picklist from Ticket field)
|
|
|
|
|
*/
|
|
|
|
|
async syncPriorities(isIncremental: boolean = false): Promise<EntitySyncStats> {
|
|
|
|
|
const picklistLogger = this.logger.child({ entityType: EntityType.PRIORITIES, syncType: 'picklist' });
|
|
|
|
|
const syncStartTime = picklistLogger.start('Picklist sync');
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
const picklistValues = await this.autotaskClient.getPicklistValues('Tickets', 'priority');
|
|
|
|
|
|
|
|
|
|
const records = Object.entries(picklistValues).map(([value, label]) => ({
|
|
|
|
|
value: parseInt(value),
|
|
|
|
|
label: label,
|
|
|
|
|
is_active: true,
|
|
|
|
|
sort_order: parseInt(value),
|
|
|
|
|
synced_at: new Date(),
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
picklistLogger.info('Found picklist values', { recordCount: records.length });
|
|
|
|
|
|
|
|
|
|
const tableName = getTableName(EntityType.PRIORITIES);
|
|
|
|
|
const existingQuery = `SELECT value FROM ${tableName}`;
|
|
|
|
|
const existingResult = await postgresClient.query<{ value: number }>(existingQuery);
|
|
|
|
|
const existingValues = new Set(existingResult.rows.map((r: any) => r.value));
|
|
|
|
|
|
|
|
|
|
const recordsAdded = records.filter((r: any) => !existingValues.has(r.value)).length;
|
|
|
|
|
const recordsUpdated = records.filter((r: any) => existingValues.has(r.value)).length;
|
|
|
|
|
|
|
|
|
|
await postgresClient.bulkUpsert(tableName, records, ['value']);
|
|
|
|
|
|
|
|
|
|
const stats: EntitySyncStats = { recordsAdded, recordsUpdated, recordsDeleted: 0 };
|
|
|
|
|
|
|
|
|
|
picklistLogger.complete('Picklist sync', syncStartTime, {
|
|
|
|
|
recordsAdded: stats.recordsAdded,
|
|
|
|
|
recordsUpdated: stats.recordsUpdated,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return stats;
|
|
|
|
|
} catch (error) {
|
|
|
|
|
const err = error instanceof Error ? error : new Error(String(error));
|
|
|
|
|
picklistLogger.fail('Picklist sync', syncStartTime, err);
|
|
|
|
|
throw error;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Sync Ticket Categories (Picklist from Ticket field)
|
|
|
|
|
*/
|
|
|
|
|
async syncTicketCategories(isIncremental: boolean = false): Promise<EntitySyncStats> {
|
|
|
|
|
const picklistLogger = this.logger.child({ entityType: EntityType.TICKET_CATEGORIES, syncType: 'picklist' });
|
|
|
|
|
const syncStartTime = picklistLogger.start('Picklist sync');
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
const picklistValues = await this.autotaskClient.getPicklistValues('Tickets', 'ticketCategory');
|
|
|
|
|
|
|
|
|
|
const records = Object.entries(picklistValues).map(([value, label]) => ({
|
|
|
|
|
value: parseInt(value),
|
|
|
|
|
label: label,
|
|
|
|
|
is_active: true,
|
|
|
|
|
sort_order: parseInt(value),
|
|
|
|
|
synced_at: new Date(),
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
picklistLogger.info('Found picklist values', { recordCount: records.length });
|
|
|
|
|
|
|
|
|
|
const tableName = getTableName(EntityType.TICKET_CATEGORIES);
|
|
|
|
|
const existingQuery = `SELECT value FROM ${tableName}`;
|
|
|
|
|
const existingResult = await postgresClient.query<{ value: number }>(existingQuery);
|
|
|
|
|
const existingValues = new Set(existingResult.rows.map((r: any) => r.value));
|
|
|
|
|
|
|
|
|
|
const recordsAdded = records.filter((r: any) => !existingValues.has(r.value)).length;
|
|
|
|
|
const recordsUpdated = records.filter((r: any) => existingValues.has(r.value)).length;
|
|
|
|
|
|
|
|
|
|
await postgresClient.bulkUpsert(tableName, records, ['value']);
|
|
|
|
|
|
|
|
|
|
const stats: EntitySyncStats = { recordsAdded, recordsUpdated, recordsDeleted: 0 };
|
|
|
|
|
|
|
|
|
|
picklistLogger.complete('Picklist sync', syncStartTime, {
|
|
|
|
|
recordsAdded: stats.recordsAdded,
|
|
|
|
|
recordsUpdated: stats.recordsUpdated,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return stats;
|
|
|
|
|
} catch (error) {
|
|
|
|
|
const err = error instanceof Error ? error : new Error(String(error));
|
feat: Display Settings UI + Company Category/Type sync
- Add /admin/display-settings page with Kiosk and Mobile sections
- Company category checkbox filter + excluded companies searchable multi-select
- New DB tables: company_categories, company_types (migration 064)
- Sync COMPANY_CATEGORIES via CompanyCategories entity (id/name/isActive)
- Sync COMPANY_TYPES via Companies.companyType picklist
- Add to EntityType, ENTITY_DEPENDENCIES, sync-helpers, entity-mapper, entity-sync
- New API routes: /api/admin/display-settings (GET/POST), /api/data/company-categories, /api/data/companies-list
- Update all 4 routes (kiosk/stats, kiosk/activity, mobile/tickets, mobile/dashboard)
to filter by kiosk_settings company_category_ids + excluded_company_ids
- Add Display Settings nav link (SlidersHorizontal icon) to Admin menu
- Seed kiosk_settings: kiosk_company_category_ids=1, mobile_company_category_ids=1
2026-04-06 09:03:19 -04:00
|
|
|
picklistLogger.fail('Picklist sync', syncStartTime, err);
|
|
|
|
|
throw error;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Sync Company Categories (queried from CompanyCategories entity — id, name, isActive)
|
|
|
|
|
*/
|
|
|
|
|
async syncCompanyCategories(isIncremental: boolean = false): Promise<EntitySyncStats> {
|
|
|
|
|
const syncLogger = this.logger.child({ entityType: EntityType.COMPANY_CATEGORIES, syncType: 'entity' });
|
|
|
|
|
const syncStartTime = syncLogger.start('Company Categories sync');
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
const apiRecords = await this.autotaskClient.queryEntityPaginated(
|
|
|
|
|
'CompanyCategories',
|
|
|
|
|
{ filter: [{ field: 'id', op: 'gt', value: 0 }] },
|
|
|
|
|
500
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const records = apiRecords.map((r: any) => ({
|
|
|
|
|
value: r.id,
|
|
|
|
|
label: r.name || r.nickname || String(r.id),
|
|
|
|
|
is_active: r.isActive !== false,
|
|
|
|
|
sort_order: r.id,
|
|
|
|
|
synced_at: new Date(),
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
syncLogger.info('Fetched company categories', { recordCount: records.length });
|
|
|
|
|
|
|
|
|
|
const tableName = getTableName(EntityType.COMPANY_CATEGORIES);
|
|
|
|
|
const existingResult = await postgresClient.query<{ value: number }>(`SELECT value FROM ${tableName}`);
|
|
|
|
|
const existingValues = new Set(existingResult.rows.map((r: any) => r.value));
|
|
|
|
|
|
|
|
|
|
const recordsAdded = records.filter((r: any) => !existingValues.has(r.value)).length;
|
|
|
|
|
const recordsUpdated = records.filter((r: any) => existingValues.has(r.value)).length;
|
|
|
|
|
|
|
|
|
|
await postgresClient.bulkUpsert(tableName, records, ['value']);
|
|
|
|
|
|
|
|
|
|
const stats: EntitySyncStats = { recordsAdded, recordsUpdated, recordsDeleted: 0 };
|
|
|
|
|
syncLogger.complete('Company Categories sync', syncStartTime, stats);
|
|
|
|
|
return stats;
|
|
|
|
|
} catch (error) {
|
|
|
|
|
const err = error instanceof Error ? error : new Error(String(error));
|
|
|
|
|
syncLogger.fail('Company Categories sync', syncStartTime, err);
|
|
|
|
|
throw error;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Sync Company Types (Picklist from Companies field)
|
|
|
|
|
*/
|
|
|
|
|
async syncCompanyTypes(isIncremental: boolean = false): Promise<EntitySyncStats> {
|
|
|
|
|
const picklistLogger = this.logger.child({ entityType: EntityType.COMPANY_TYPES, syncType: 'picklist' });
|
|
|
|
|
const syncStartTime = picklistLogger.start('Picklist sync');
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
const picklistValues = await this.autotaskClient.getPicklistValues('Companies', 'companyType');
|
|
|
|
|
|
|
|
|
|
const records = Object.entries(picklistValues).map(([value, label]) => ({
|
|
|
|
|
value: parseInt(value),
|
|
|
|
|
label: label,
|
|
|
|
|
is_active: true,
|
|
|
|
|
sort_order: parseInt(value),
|
|
|
|
|
synced_at: new Date(),
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
picklistLogger.info('Found picklist values', { recordCount: records.length });
|
|
|
|
|
|
|
|
|
|
const tableName = getTableName(EntityType.COMPANY_TYPES);
|
|
|
|
|
const existingResult = await postgresClient.query<{ value: number }>(`SELECT value FROM ${tableName}`);
|
|
|
|
|
const existingValues = new Set(existingResult.rows.map((r: any) => r.value));
|
|
|
|
|
|
|
|
|
|
const recordsAdded = records.filter((r: any) => !existingValues.has(r.value)).length;
|
|
|
|
|
const recordsUpdated = records.filter((r: any) => existingValues.has(r.value)).length;
|
|
|
|
|
|
|
|
|
|
await postgresClient.bulkUpsert(tableName, records, ['value']);
|
|
|
|
|
|
|
|
|
|
const stats: EntitySyncStats = { recordsAdded, recordsUpdated, recordsDeleted: 0 };
|
|
|
|
|
picklistLogger.complete('Picklist sync', syncStartTime, stats);
|
|
|
|
|
return stats;
|
|
|
|
|
} catch (error) {
|
|
|
|
|
const err = error instanceof Error ? error : new Error(String(error));
|
2026-02-20 10:28:15 -05:00
|
|
|
picklistLogger.fail('Picklist sync', syncStartTime, err);
|
|
|
|
|
throw error;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-19 14:18:16 -05:00
|
|
|
/**
|
2026-01-23 17:02:09 -05:00
|
|
|
* Sync Work Types (Picklist from TimeEntry field)
|
2025-11-19 14:18:16 -05:00
|
|
|
*/
|
|
|
|
|
async syncWorkTypes(isIncremental: boolean = false): Promise<EntitySyncStats> {
|
2026-01-23 17:02:09 -05:00
|
|
|
const picklistLogger = this.logger.child({ entityType: EntityType.WORK_TYPES, syncType: 'picklist' });
|
|
|
|
|
const syncStartTime = picklistLogger.start('Picklist sync');
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
// Get work type picklist values from TimeEntries entity
|
|
|
|
|
const picklistValues = await this.autotaskClient.getPicklistValues('TimeEntries', 'workType');
|
|
|
|
|
|
|
|
|
|
// Convert picklist to database format
|
|
|
|
|
const records = Object.entries(picklistValues).map(([value, label]) => ({
|
|
|
|
|
value: parseInt(value),
|
|
|
|
|
label: label,
|
|
|
|
|
is_active: true,
|
|
|
|
|
sort_order: parseInt(value),
|
|
|
|
|
synced_at: new Date(),
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
picklistLogger.info('Found picklist values', { recordCount: records.length });
|
|
|
|
|
|
2026-01-24 08:47:52 -05:00
|
|
|
// Get existing values to calculate added vs updated
|
2026-01-23 17:02:09 -05:00
|
|
|
const tableName = getTableName(EntityType.WORK_TYPES);
|
2026-01-24 08:47:52 -05:00
|
|
|
const existingQuery = `SELECT value FROM ${tableName}`;
|
|
|
|
|
const existingResult = await postgresClient.query<{ value: number }>(existingQuery);
|
|
|
|
|
const existingValues = new Set(existingResult.rows.map((r: any) => r.value));
|
|
|
|
|
|
|
|
|
|
const recordsAdded = records.filter((r: any) => !existingValues.has(r.value)).length;
|
|
|
|
|
const recordsUpdated = records.filter((r: any) => existingValues.has(r.value)).length;
|
|
|
|
|
|
|
|
|
|
// Upsert to database
|
|
|
|
|
await postgresClient.bulkUpsert(tableName, records, ['value']);
|
2026-01-23 17:02:09 -05:00
|
|
|
|
|
|
|
|
const stats: EntitySyncStats = {
|
2026-01-24 08:47:52 -05:00
|
|
|
recordsAdded,
|
|
|
|
|
recordsUpdated,
|
2026-01-23 17:02:09 -05:00
|
|
|
recordsDeleted: 0,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
picklistLogger.complete('Picklist sync', syncStartTime, {
|
|
|
|
|
recordsAdded: stats.recordsAdded,
|
|
|
|
|
recordsUpdated: stats.recordsUpdated,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return stats;
|
|
|
|
|
} catch (error) {
|
|
|
|
|
const err = error instanceof Error ? error : new Error(String(error));
|
|
|
|
|
picklistLogger.fail('Picklist sync', syncStartTime, err);
|
|
|
|
|
throw error;
|
|
|
|
|
}
|
2025-11-19 14:18:16 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Sync Time Entries
|
|
|
|
|
*/
|
|
|
|
|
async syncTimeEntries(isIncremental: boolean = false): Promise<EntitySyncStats> {
|
|
|
|
|
return await this.syncEntity(EntityType.TIME_ENTRIES, isIncremental);
|
|
|
|
|
}
|
feat: add Autotask tags sync (tag groups, tags, ticket tag associations)
- Migration 057: autotask_tag_groups, autotask_tags, and junction tables
(ticket_tags, company_tags, configuration_item_tags, contact_tags)
- Add TAG_GROUPS and TAGS to EntityType enum and dependency map
- Add mapTagGroup() and mapTag() entity mapper functions
- Add syncTagGroups(), syncTags(), syncTicketTagAssociations() methods
- Wire TicketTagAssociations bulk sync into full/incremental sync flow
- Add 'exist' operator to QueryFilter type
- No FK on ticket_id (tagged tickets may be outside 2yr sync window)
Synced: 26 tag groups, 7299 tags, 10141 ticket-tag associations
2026-03-20 09:22:40 -04:00
|
|
|
|
feat: AI ticket analyzer (phases 1-6)
Multi-stage LLM pipeline that produces structured analyses of Autotask
tickets from local Postgres. Migration 069 + Zod schemas, Stage 0
preprocessor, IT Glue redaction + search, Anthropic SDK wrapper, Stages
1/3/4 (Haiku/Sonnet/Opus), pipeline + cost circuit breaker, job worker
(opt-in autostart), 6 API routes, 3 frontend pages, share-row
persistence (email send deferred to phase 7). 128 vitest tests, tsc
clean. Build journal in docs/wulf-pulse-ticket-analyzer-build-notes.md.
Sync: adds syncTicketNotes() + ticket_notes to ordered/date-filtered
entities so the analyzer's local mirror stays current via scheduler.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-29 10:59:40 -04:00
|
|
|
/**
|
|
|
|
|
* Sync Ticket Notes. Webhooks are the primary path; this exists so missed
|
|
|
|
|
* events (webhook outages, replays) get reconciled by the scheduled sync.
|
|
|
|
|
*/
|
|
|
|
|
async syncTicketNotes(
|
|
|
|
|
isIncremental: boolean = false,
|
|
|
|
|
yearsBack: number = 2
|
|
|
|
|
): Promise<EntitySyncStats> {
|
|
|
|
|
return await this.syncEntity(EntityType.TICKET_NOTES, isIncremental, yearsBack);
|
|
|
|
|
}
|
|
|
|
|
|
feat: add Autotask tags sync (tag groups, tags, ticket tag associations)
- Migration 057: autotask_tag_groups, autotask_tags, and junction tables
(ticket_tags, company_tags, configuration_item_tags, contact_tags)
- Add TAG_GROUPS and TAGS to EntityType enum and dependency map
- Add mapTagGroup() and mapTag() entity mapper functions
- Add syncTagGroups(), syncTags(), syncTicketTagAssociations() methods
- Wire TicketTagAssociations bulk sync into full/incremental sync flow
- Add 'exist' operator to QueryFilter type
- No FK on ticket_id (tagged tickets may be outside 2yr sync window)
Synced: 26 tag groups, 7299 tags, 10141 ticket-tag associations
2026-03-20 09:22:40 -04:00
|
|
|
/**
|
|
|
|
|
* Sync Tag Groups
|
|
|
|
|
*/
|
|
|
|
|
async syncTagGroups(isIncremental: boolean = false): Promise<EntitySyncStats> {
|
|
|
|
|
return await this.syncEntity(EntityType.TAG_GROUPS, isIncremental);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Sync Tags
|
|
|
|
|
*/
|
|
|
|
|
async syncTags(isIncremental: boolean = false): Promise<EntitySyncStats> {
|
|
|
|
|
return await this.syncEntity(EntityType.TAGS, isIncremental);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Sync TicketTagAssociations from Autotask API into the ticket_tags junction table.
|
|
|
|
|
* Autotask exposes TicketTagAssociations as a bulk-queryable entity with fields:
|
|
|
|
|
* id, tagID, ticketID
|
|
|
|
|
*/
|
|
|
|
|
async syncTicketTagAssociations(): Promise<EntitySyncStats> {
|
|
|
|
|
const tagLogger = this.logger.child({ entityType: 'ticket_tag_associations', syncType: 'full' });
|
|
|
|
|
const syncStartTime = tagLogger.start('TicketTagAssociations sync');
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
// Fetch all TicketTagAssociations from Autotask
|
|
|
|
|
tagLogger.info('Fetching TicketTagAssociations from Autotask');
|
|
|
|
|
const associations = await this.autotaskClient.queryEntityPaginated<{
|
|
|
|
|
id: number;
|
|
|
|
|
tagID: number;
|
|
|
|
|
ticketID: number;
|
|
|
|
|
}>('TicketTagAssociations', { filter: [{ op: 'exist', field: 'id' }] }, 500);
|
|
|
|
|
|
|
|
|
|
tagLogger.info('Fetched TicketTagAssociations', { count: associations.length });
|
|
|
|
|
|
|
|
|
|
if (associations.length === 0) {
|
|
|
|
|
tagLogger.info('No ticket tag associations found');
|
|
|
|
|
tagLogger.complete('TicketTagAssociations sync', syncStartTime, { recordsAdded: 0 });
|
|
|
|
|
return { recordsAdded: 0, recordsUpdated: 0, recordsDeleted: 0 };
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Validate tag IDs exist in our DB to avoid FK violations on autotask_tags
|
|
|
|
|
// (ticket_id has no FK constraint since tagged tickets may be outside sync window)
|
|
|
|
|
const validTagResult = await postgresClient.query<{ id: number }>(
|
|
|
|
|
'SELECT id FROM autotask_tags'
|
|
|
|
|
);
|
|
|
|
|
const validTagIds = new Set(validTagResult.rows.map(r => Number(r.id)));
|
|
|
|
|
|
|
|
|
|
const validAssociations = associations.filter(a => validTagIds.has(Number(a.tagID)));
|
|
|
|
|
|
|
|
|
|
tagLogger.info('Validated associations', {
|
|
|
|
|
total: associations.length,
|
|
|
|
|
valid: validAssociations.length,
|
|
|
|
|
skippedInvalidTag: associations.length - validAssociations.length,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Replace all ticket_tags: truncate and re-insert for a clean full sync
|
|
|
|
|
await postgresClient.query('DELETE FROM ticket_tags');
|
|
|
|
|
|
|
|
|
|
const CHUNK = 500;
|
|
|
|
|
let inserted = 0;
|
|
|
|
|
for (let i = 0; i < validAssociations.length; i += CHUNK) {
|
|
|
|
|
const chunk = validAssociations.slice(i, i + CHUNK);
|
|
|
|
|
const values = chunk
|
|
|
|
|
.map((_, idx) => `($${idx * 2 + 1}::bigint, $${idx * 2 + 2}::bigint, NOW())`)
|
|
|
|
|
.join(', ');
|
|
|
|
|
const params = chunk.flatMap(a => [a.ticketID, a.tagID]);
|
|
|
|
|
await postgresClient.query(
|
|
|
|
|
`INSERT INTO ticket_tags (ticket_id, tag_id, synced_at)
|
|
|
|
|
VALUES ${values}
|
|
|
|
|
ON CONFLICT (ticket_id, tag_id) DO UPDATE SET synced_at = NOW()`,
|
|
|
|
|
params
|
|
|
|
|
);
|
|
|
|
|
inserted += chunk.length;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const stats: EntitySyncStats = {
|
|
|
|
|
recordsAdded: inserted,
|
|
|
|
|
recordsUpdated: 0,
|
|
|
|
|
recordsDeleted: 0,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
tagLogger.complete('TicketTagAssociations sync', syncStartTime, stats);
|
|
|
|
|
return stats;
|
|
|
|
|
} catch (error) {
|
|
|
|
|
const err = error instanceof Error ? error : new Error(String(error));
|
|
|
|
|
tagLogger.fail('TicketTagAssociations sync', syncStartTime, err);
|
|
|
|
|
throw error;
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-11-19 14:18:16 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Create entity sync service instance
|
|
|
|
|
* @param autotaskClient Autotask client instance
|
|
|
|
|
* @returns EntitySyncService instance
|
|
|
|
|
*/
|
|
|
|
|
export function createEntitySyncService(autotaskClient: AutotaskClient): EntitySyncService {
|
|
|
|
|
return new EntitySyncService(autotaskClient);
|
|
|
|
|
}
|