- Add label_ids and categories columns to notification_routes via idempotent migration
- Matcher logic always evaluates routes (AND semantics across all non-empty matchers)
- getStackLabelIds skips DB call when no enabled route uses label filtering
- Extract ALL_NOTIFICATION_CATEGORIES array from NotificationService as single source of truth
- Derive VALID_CATEGORIES set from the array in the route handler
- Extract validateLabelIds and validateCategories helpers to remove POST/PUT duplication
- Extract tryAddColumn as a private DatabaseService class method (removes 5 local re-declarations)
- Extract CATEGORY_LABELS to frontend/src/lib/notificationCategories.ts (shared by NotificationPanel and NotificationRoutingSection)
- Frontend form adds label and category multiselects with AND-filter hint
- Route cards show label and category badges; empty-matcher routes show 'Matches all alerts'
- Add tests for category-only, label-only, and combined AND-semantics routing
- Add authMiddleware to GET/POST /api/agents (previously unauthenticated)
- Add input validation to POST /api/agents (type, URL, enabled)
- Add URL host validation via new URL() to notification-routes POST/PUT
- Add priority type validation and enabled boolean check to routes
- Add name length limit (100 chars) to routes POST/PUT
- Add stack pattern dedup and whitespace filtering
- Add NaN guard to DELETE /api/notifications/:id
- Add dispatch_error to NotificationHistory TypeScript interface
- Extract cleanStackPatterns() and validateHttpsUrl() helpers
- Add standard and diagnostic logging to agents and routes endpoints
- Add comprehensive integration tests for notification-routes CRUD
- Add agents auth and validation tests
- Add dispatch error recording unit tests