Data flow: Impact analysis
sequenceDiagram
autonumber
participant Admin as MSP admin
participant Next as Next.js
participant SbDB as Supabase Postgres
participant Edge as Edge Function graph-signin-impact
participant Graph as Microsoft Graph
Admin->>Next: Pick policy + window, click Run
Next->>SbDB: getImpactReport(forceFresh=true)
Next->>SbDB: check signin_summary_cache (tenant schema) - miss/expired
Next->>Edge: invoke graph-signin-impact { tenant_id, policy_id, window_days }
Edge->>Edge: verify JWT msp_id == tenant.msp_id
Edge->>Graph: GET /auditLogs/signIns?$filter=... (paginated, up to 10k events)
Graph-->>Edge: pages of sign-in events
Edge->>Edge: aggregate IN MEMORY (totals, by_user, by_app, by_reason)
Edge->>SbDB: upsert signin_summary_cache (10 min TTL)
Edge-->>Next: ImpactReport summary
Next->>SbDB: insert audit_log
Next-->>Admin: render cards + ranked tables
What's in the cache
signin_summary_cache.summary JSONB column. Key shape:
{
"policyId": "CA101",
"windowStart": "2026-05-12T00:00:00Z",
"windowEnd": "2026-05-19T00:00:00Z",
"totalSignins": 1873,
"uniqueUsers": 412,
"wouldBlock": 47,
"byResult": { "success": 1740, "reportOnlyFailure": 47, "..." },
"topAffectedUsers": [{ "key": "uid", "label": "user@org.com", "totalSignins": 18, "wouldBlock": 14 }, ...],
"topAffectedApps": [...],
"topFailureReasons": [{ "reason": "MFA required", "count": 32 }, ...]
}
expires_at is set to computed_at + 10 min. Cache hit returns instantly; cache miss kicks Graph fetch.
Why "would block" includes report-only failures
The whole point of the analysis is "if I enforce this policy, what changes?" - and the answer for a currently report-only policy is: every sign-in that's already a reportOnlyFailure would become a real failure. So those count as would-block.
For an already-enforced policy, reportOnlyFailure should be 0 in the response (the policy is enforced, not report-only) and failure carries the count.
Why we don't store raw events
- Customer trust - sign-in logs contain IPs, geolocations, and behavioural data
- Storage cost - a 1000-user tenant generates ~50k sign-ins per day
- Microsoft retention - they keep it 30 days; we don't need to duplicate
The cost: a fresh Impact analysis on a high-volume tenant takes 10-30s (paginating up to 20 pages of 500 events). That's why the 10-minute cache exists.