- AppNavigation returns null on /mobile/* (no more horizontal scroll)
- Mobile header: 'Pulse' title (links home) + Menu icon (links to /mobile/nav)
- /mobile/nav: full-screen nav page with touch-friendly cards
- Mobile Views: Dashboard, Tickets, Finance (large icon cards)
- Full Site: Quotes, Config Items, Backup, Engagement, Ticket Digest, Admin
- Sign out button
- Bottom tab bar unchanged (Dashboard / Tickets / Finance)
- DB: inserted qbo-sync-2am (0 2 * * *) and qbo-sync-4pm (0 16 * * *) schedules
- Mobile finance: 'Sync QBO' button triggers POST /api/qbo/sync incremental,
polls /api/qbo/sync GET until lastSync timestamp changes (max 90s),
then reloads finance data
- Shows last sync timestamp below page title
- Separate refresh-only button (↻) for quick display refresh without re-syncing
- Sync status message shown during polling
- Replace stripHtml() with renderContent() that:
1. Extracts <a href="...">...</a> anchors before stripping HTML
2. Strips remaining HTML tags cleanly
3. Detects bare https?:// URLs in plain text
4. Renders each as a tappable <a>[link]</a> with text-primary underline
- Collapsed note preview still shows plain text (no link clutter)
- Expanded note/time-entry body shows inline [link] elements
- API: marks note_type 13,91,93,94,99,101 as is_system=true
(13=workflow rule fired, 91=workflow templates, 99=RMM system notes,
93/94=merge/absorb, 101=other system)
- Frontend: system notes filtered out by default; 'Show system' toggle
in timeline header reveals them
- Time entry expanded card uses bg-muted/border-border (dark-mode safe)
instead of hard-coded bg-blue-50 which was unreadable in dark theme
- Priority labels and colors corrected to match actual Autotask values
- Status labels expanded to full set
- API: replaced hardcoded wrong map (1=Critical etc) with JOIN on priorities table
- API: sorted by count DESC instead of priority value
- Frontend: PRIORITY_COLOR/TEXT maps updated to cover all 10 actual Autotask values (1-11)
- Middleware: added /api/mobile to publicRoutes (was getting auth-redirected)