- Add searchMailboxMessages, deleteMailboxMessage, moveToDeletedItems to MsGraphClient
- POST /api/mimecast/mailbox-remediate: search, move, delete actions with permission error handling
- DeliveredAnalysisDialog: Remove from mailbox panel with search → confirm → delete flow
- Shows matching messages in mailbox with checkboxes, received time, read/unread status
- Moves selected to Deleted Items (recoverable) via Graph API
- Surfaces clear permission guidance if Mail.ReadWrite not yet granted
- New POST /api/mimecast/delivered route using message-finder/search API
- DeliveredMailTab: search by recipient, sender, subject, time range (6h–7d)
- Results table with status badge, spam score, row tinting for high/moderate risk
- Summary stats bar: total / high spam (≥10) / moderate (5-9) / clean counts
- Sort by date or spam score; filter by status (accepted/held/rejected/bounced)
- DeliveredAnalysisDialog: explains why high-score mail got through, envelope mismatch detection, actionable remediation steps (block domain, adjust policy threshold, report)
- MimecastDeliveredMessage interface + searchDeliveredMessages() method in client
- Add releaseHeldMessage() to MimecastClient (POST /api/gateway/hold-release)
- Add POST /api/mimecast/held/release route
- HeldMailTab: tenant selector before load (defaults to Wulf), only fetches selected tenant
- Release button per row with spinner + optimistic removal on success
- Error shown inline under Release button if release fails
- export const dynamic = 'force-dynamic' on /api/mimecast/held to prevent Next.js caching
- Add AbortController timeout (20s) per request in MimecastClient.request()
- getHeldMessages: 403 fallback without admin:true flag for tenants lacking permission
- Reduce maxMessages default to 100 (10 pages) to stay within route timeout
- Show 'permission denied' tooltip in tenant badge for 403 errors
- Surface HTTP errors in HeldMailTab instead of silently failing
- Add missing favicons: sentinelone.ico, itglue.ico, mimecast.ico
Bypass = security risk (MFA not enforced) — shown in red, expandable panel
Disabled = locked out, no threat — shown in muted gray, separate expandable panel
- Split /api/duo/status counts into bypass and disabled separately
- /api/duo/users/flagged returns { bypass: [], disabled: [] } instead of flat list
- Overview card: only bypass triggers red warning icon (disabled does not)
- Detail page: two separate expandable sections with distinct severity styling
- Both sections include user, email, account name, enrolled status, last login, notes
- Covers all accounts (parent + children)
- Created GET /api/duo/users/flagged — returns users with status bypass or disabled, joined with account name
- Clickable warning banner expands to show full user table
- Table shows: user, email, account, status badge (yellow=bypass, red=disabled), enrolled, last login, notes
- Fixed JOIN: duo_users.duo_account_id is varchar account_id, not integer id
- Separate Sync Status and Sync History into tabs with icons
- Fix pagination in sync history by adding offset parameter
- Update getSyncHistory to support offset for proper pagination
- Update API endpoint to pass offset parameter
- Previous/Next buttons now work correctly to navigate pages
This improves UX by organizing the sync page into logical sections
and enables users to browse through historical sync records.
- Add admin dashboard with sync controls and data browser
- Implement RMM, Auvik, and Addigy organization mappings
- Add chunked ticket sync with progress tracking
- Implement entity sync service with rate limiting
- Add analytics engine and performance optimizer
- Create data browser for all PSA entities
- Add navigation components and UI improvements
- Implement background processing and sync services
- Add comprehensive documentation and migration scripts
- Update configuration items with multi-system support
- Enhance contact management and purchase history
- Add issue type assignment and LLM analyzer
- Improve error handling and logging utilities