- Fix flexbox collapse hiding alert titles in Overview mini-lists
(missing min-width:0 on .mini-row/.mr-user collapsed them to 0 width
in both light and dark mode)
- Establish token-based color system: 3-tier surface elevation, unified
severity/status scales, text scale — all with proper light/dark parity
- Replace scattered hardcoded hex values across CSS and JSX inline styles
with design tokens so both themes stay consistent
- Full dark-mode contrast audit (WCAG AA): badges, KPI tiles/icons,
source badges, tone classes, charts/gauges, form inputs, focus rings
- sevColor() now returns CSS vars so severity colors adapt per theme
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Addresses external review feedback on the project.
- Add SecretProtector (Windows DPAPI, machine scope) and encrypt SMTP
password and Teams/Slack/generic webhook URLs at rest in the database.
Values are decrypted only in memory at send time; SMTP password is
never returned by the API. Legacy plaintext rows are read transparently.
- Rewrite README "Security & Maturity" section: honest beta positioning,
read-only/least-privilege scope, credential handling, and a host
hardening checklist (dedicated low-priv host, BitLocker, no public
exposure, rotation). Notes certificate auth as recommended next step.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Normalize sevColor() input so lowercase backend severities map to
correct colors (were all falling back to grey)
- Add missing .sev-dot.sev-* CSS rules so Recent Alerts severity dots
are visible
- Add suppressionMinutes to AlertPolicy TS interface (was silently dropped)
- Correct misleading "no email sent" label on the policy modal
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Previously the alert engine was browser-only (localStorage) and only ran
while the dashboard was open. It now runs server-side on the 15-minute
collection cycle and actually delivers notifications.
Backend:
- New EF entities: AlertPolicy, TriggeredAlert, NotificationSettings, NotificationLog
- AlertEvaluator computes metrics from SecurityAlerts and fires policies with
per-policy suppression windows to prevent alert fatigue
- NotificationSender delivers to Teams/Slack incoming webhooks, SMTP email,
and a generic JSON webhook (SIEM/Power Automate); every attempt is logged
- Evaluation hooked into GraphCollectionWorker so alerts fire with no browser open
- Idempotent table creation + default policy seeding (works on existing DBs)
- REST endpoints for policies CRUD, triggered alerts ack/resolve, settings, test, log
Frontend:
- Alert Center now reads/writes via the API instead of localStorage
- New Notifications tab: Teams/webhook/SMTP config, send-test, delivery history
- Acknowledge/resolve/policy edits persist to the database
Verified against live tenant: 5 policies fired (MFA 7, risky users 1,
non-compliant 2, high alerts 10, service health 15); dedup and ack confirmed.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- SECURITY.md documents endpoint stability per area, how to report
broken Graph endpoints, and links to the MS Graph changelog
- New issue template for broken API reports with structured fields
(page, error, date, endpoint, license tier)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Full-stack Microsoft 365 security monitoring dashboard built with
ASP.NET Core 8 + React 18 + TypeScript. Aggregates security signals
from Microsoft Graph API across Defender XDR, Entra ID Protection,
Intune, Exchange Online, and M365 Compliance into a single
self-hosted dashboard.
Features:
- 13 monitoring pages: Identity, Devices, Email, Incidents, Compliance,
Service Health, Licenses, Conditional Access, Audit Log, Sign-in Locations,
M365 Connectivity, Alert Center, Overview
- Alert Policy Engine with 9 pre-built templates and custom policy builder
- Detail modals with direct M365 portal deep links per item type
- Per-page search, filter, sort, CSV export, saved filter presets
- Dark/light mode, collapsible sidebar, toast notifications
- Responsive layout, sticky filter bars, sortable table columns
All credentials must be supplied via .NET User Secrets (dev) or
appsettings.Production.json (prod) — never committed to source.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>