feat: Morning NOC Summary adaptive card for Teams
- Add MorningSummaryService with Zabbix aggregation and adaptive card builder - Add webhook delivery system with Teams incoming webhooks - Add admin UI at /admin/morning-summary for webhook/config management - Add API routes: /send, /test, /webhooks, /webhooks/[id], /config, /history - Register morning-summary cron job in SyncScheduler (Mon-Fri 6:30 AM) - Add outages_only filter (Unavailable triggers only) - Fix host resolution: use getTriggerEnabledHosts to exclude disabled hosts - Fix resolved events: event.get value:1 scoped to window with r_eventid filter - Remove emojis from fact rows and section headers in card - Remove Open Zabbix button (duplicate of View Problems) - Add migrations: morning_summary_config + morning_summaries tables - Add outages_only column to morning_summary_config
This commit is contained in:
parent
19605f82aa
commit
c518eefdb2
61 changed files with 11236 additions and 237 deletions
|
|
@ -7,15 +7,21 @@ import cron, { ScheduledTask } from 'node-cron';
|
|||
import { SyncService, createSyncService } from './sync-service';
|
||||
import { postgresClient } from './postgres-client';
|
||||
import { AutotaskClient } from './autotask-client';
|
||||
import { EntityType, SyncType } from '../types/sync';
|
||||
import { VeeamSyncService } from './veeam-sync-service';
|
||||
import { VeeamRpoService } from './veeam-rpo-service';
|
||||
import { EngagementSyncService } from './engagement-sync-service';
|
||||
import { isMsgraphConfigured } from './msgraph-factory';
|
||||
import { ZoomSyncService } from './zoom-sync-service';
|
||||
import { isZoomConfigured } from './zoom-factory';
|
||||
import { MorningSummaryService } from './morning-summary-service';
|
||||
|
||||
export interface ScheduleConfig {
|
||||
id: string;
|
||||
name: string;
|
||||
description: string;
|
||||
cron_expression: string;
|
||||
sync_type: 'incremental' | 'full' | 'veeam-incremental' | 'veeam-full' | 'veeam-rpo-check';
|
||||
sync_type: 'incremental' | 'full' | 'veeam-incremental' | 'veeam-full' | 'veeam-rpo-check' | 'contract-services' | 'engagement-daily' | 'zoom-daily' | 'morning-summary';
|
||||
years_back?: number;
|
||||
is_enabled: boolean;
|
||||
last_run?: Date;
|
||||
|
|
@ -40,6 +46,8 @@ class SyncScheduler {
|
|||
private syncService: SyncService;
|
||||
private _veeamSyncService: VeeamSyncService | null = null;
|
||||
private _veeamRpoService: VeeamRpoService | null = null;
|
||||
private _engagementSyncService: EngagementSyncService | null = null;
|
||||
private _zoomSyncService: ZoomSyncService | null = null;
|
||||
|
||||
private getVeeamSyncService(): VeeamSyncService {
|
||||
if (!this._veeamSyncService) {
|
||||
|
|
@ -55,6 +63,28 @@ class SyncScheduler {
|
|||
return this._veeamRpoService;
|
||||
}
|
||||
|
||||
private getEngagementSyncService(): EngagementSyncService {
|
||||
if (!this._engagementSyncService) {
|
||||
this._engagementSyncService = new EngagementSyncService();
|
||||
}
|
||||
return this._engagementSyncService;
|
||||
}
|
||||
|
||||
private _morningSummaryService?: MorningSummaryService;
|
||||
private getMorningSummaryService(): MorningSummaryService {
|
||||
if (!this._morningSummaryService) {
|
||||
this._morningSummaryService = new MorningSummaryService();
|
||||
}
|
||||
return this._morningSummaryService;
|
||||
}
|
||||
|
||||
private getZoomSyncService(): ZoomSyncService {
|
||||
if (!this._zoomSyncService) {
|
||||
this._zoomSyncService = new ZoomSyncService();
|
||||
}
|
||||
return this._zoomSyncService;
|
||||
}
|
||||
|
||||
constructor() {
|
||||
// Create sync service instance
|
||||
const autotaskClient = new AutotaskClient({
|
||||
|
|
@ -105,7 +135,7 @@ class SyncScheduler {
|
|||
name VARCHAR(100) NOT NULL,
|
||||
description TEXT,
|
||||
cron_expression VARCHAR(50) NOT NULL,
|
||||
sync_type VARCHAR(30) NOT NULL CHECK (sync_type IN ('incremental', 'full', 'veeam-incremental', 'veeam-full')),
|
||||
sync_type VARCHAR(30) NOT NULL,
|
||||
years_back INTEGER DEFAULT 2,
|
||||
is_enabled BOOLEAN NOT NULL DEFAULT true,
|
||||
last_run TIMESTAMP,
|
||||
|
|
@ -180,6 +210,38 @@ class SyncScheduler {
|
|||
sync_type: 'veeam-rpo-check',
|
||||
is_enabled: false,
|
||||
},
|
||||
{
|
||||
id: 'contract-services',
|
||||
name: 'Contract Services Sync',
|
||||
description: 'Syncs Autotask contract service lines (service catalog items per contract) daily at 4 AM',
|
||||
cron_expression: '0 4 * * *',
|
||||
sync_type: 'contract-services',
|
||||
is_enabled: true,
|
||||
},
|
||||
{
|
||||
id: 'engagement-daily',
|
||||
name: 'Engagement Daily Sync',
|
||||
description: 'Syncs Microsoft Graph Teams and email activity for employee engagement dashboard daily at 6 AM',
|
||||
cron_expression: '0 6 * * *',
|
||||
sync_type: 'engagement-daily',
|
||||
is_enabled: false,
|
||||
},
|
||||
{
|
||||
id: 'zoom-daily',
|
||||
name: 'Zoom Daily Sync',
|
||||
description: 'Syncs Zoom Phone call logs and meeting data daily at 6 AM',
|
||||
cron_expression: '0 6 * * *',
|
||||
sync_type: 'zoom-daily',
|
||||
is_enabled: false,
|
||||
},
|
||||
{
|
||||
id: 'morning-summary',
|
||||
name: 'Morning NOC Summary',
|
||||
description: 'Posts a Zabbix overnight summary Adaptive Card to configured Teams channel webhooks at 6:30 AM Mon–Fri',
|
||||
cron_expression: '30 6 * * 1-5',
|
||||
sync_type: 'morning-summary',
|
||||
is_enabled: false,
|
||||
},
|
||||
];
|
||||
|
||||
for (const schedule of defaultSchedules) {
|
||||
|
|
@ -289,6 +351,22 @@ class SyncScheduler {
|
|||
await this.getVeeamSyncService().fullSync('scheduled');
|
||||
} else if (config.sync_type === 'veeam-rpo-check') {
|
||||
await this.getVeeamRpoService().runCheck();
|
||||
} else if (config.sync_type === 'contract-services') {
|
||||
await this.syncService.syncEntities([EntityType.AUTOTASK_SERVICES, EntityType.CONTRACT_SERVICES], SyncType.ENTITY_SPECIFIC, 'scheduled');
|
||||
} else if (config.sync_type === 'engagement-daily') {
|
||||
if (isMsgraphConfigured()) {
|
||||
await this.getEngagementSyncService().sync();
|
||||
} else {
|
||||
console.log('[SCHEDULER] Skipping engagement sync — Microsoft Graph not configured');
|
||||
}
|
||||
} else if (config.sync_type === 'zoom-daily') {
|
||||
if (isZoomConfigured()) {
|
||||
await this.getZoomSyncService().sync();
|
||||
} else {
|
||||
console.log('[SCHEDULER] Skipping Zoom sync — Zoom credentials not configured');
|
||||
}
|
||||
} else if (config.sync_type === 'morning-summary') {
|
||||
await this.getMorningSummaryService().run();
|
||||
} else if (config.sync_type === 'incremental') {
|
||||
await this.syncService.incrementalSync('scheduled');
|
||||
} else {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue