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
|
|
@ -16,6 +16,7 @@ import {
|
|||
buildActiveFilter,
|
||||
buildDateRangeFilter,
|
||||
buildContractsFilter,
|
||||
buildContractServicesFilter,
|
||||
buildProjectsFilter,
|
||||
buildTimeEntriesFilter,
|
||||
buildBillingItemsFilter,
|
||||
|
|
@ -125,6 +126,9 @@ export class EntitySyncService {
|
|||
if (entity === EntityType.CONTRACTS) {
|
||||
filters.push(...buildContractsFilter());
|
||||
entityLogger.info('Full sync with status filter for active contracts');
|
||||
} else if (entity === EntityType.CONTRACT_SERVICES) {
|
||||
filters.push(...buildContractServicesFilter());
|
||||
entityLogger.info('Full sync of all contract services');
|
||||
} else if (entity === EntityType.PROJECTS) {
|
||||
filters.push(...buildProjectsFilter());
|
||||
entityLogger.info('Full sync with status filter for non-completed projects');
|
||||
|
|
@ -365,6 +369,21 @@ export class EntitySyncService {
|
|||
|
||||
entityLogger.info('Upserted records to PostgreSQL', { upsertedCount });
|
||||
|
||||
// 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)');
|
||||
}
|
||||
}
|
||||
|
||||
// For full sync, soft delete records not in the fetched set
|
||||
// IMPORTANT: Skip soft deletes if ANY filters were applied (date, status, active, etc.)
|
||||
// because we cannot know what records exist outside the filter criteria
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue