feat(engagement): replace Graph email counts with real-time mimecast data

- Broaden mimecast retention from 30 days to 18 months rolling
- Re-enable mimecast-sync schedule (was disabled since March 17)
- Full sync triggered: 35,559 messages loaded for last 30 days
- Users list API: LATERAL join on mimecast_messages for emails_sent/received
- User detail API: add emails{d7,d30,d90} field from mimecast
- Engagement page: prefer mimecast email counts in detail panel sub-label

Graph API has 48-72hr reporting lag; mimecast is same-day
This commit is contained in:
lorentz 2026-06-02 20:25:14 -04:00
parent 078e087d5f
commit 758b7e7f15
4 changed files with 38 additions and 7 deletions

View file

@ -1,6 +1,6 @@
/**
* Mimecast Sync Service
* Full sync (120 days back), incremental (since last sync), body fetch, 120-day purge
* Full sync (18 months back), incremental (since last sync), body fetch, 18-month rolling purge
*/
import { getMimecastClient, MimecastMessage, MimecastThreatEvent } from './mimecast-client';
@ -15,9 +15,10 @@ export interface MimecastSyncResult {
durationMs: number;
}
const RETENTION_DAYS = 30; // API max lookback is ~30 days
const RETENTION_DAYS = 548; // 18-month rolling retention in DB
const FULL_SYNC_DAYS = 548; // How far back a full sync reaches
const BODY_FETCH_LIMIT = 500;
const CHUNK_DAYS = 7; // Pages the 30-day window in 7-day chunks to avoid 5000-result cap
const CHUNK_DAYS = 7; // Pages the window in 7-day chunks to avoid 5000-result cap per request
// ── Upsert helpers ────────────────────────────────────────────────────────────
@ -283,7 +284,7 @@ export async function runMimecastFullSync(): Promise<MimecastSyncResult> {
const toDate = new Date();
const fromDate = new Date();
fromDate.setDate(fromDate.getDate() - RETENTION_DAYS);
fromDate.setDate(fromDate.getDate() - FULL_SYNC_DAYS);
const messagesUpserted = await syncMimecastMessages(fromDate, toDate, errors);
const threatsUpserted = await syncMimecastThreats(errors);