Commit graph

20 commits

Author SHA1 Message Date
8f8b5ab7be feat: AI ticket analyzer (phases 1-6)
Multi-stage LLM pipeline that produces structured analyses of Autotask
tickets from local Postgres. Migration 069 + Zod schemas, Stage 0
preprocessor, IT Glue redaction + search, Anthropic SDK wrapper, Stages
1/3/4 (Haiku/Sonnet/Opus), pipeline + cost circuit breaker, job worker
(opt-in autostart), 6 API routes, 3 frontend pages, share-row
persistence (email send deferred to phase 7). 128 vitest tests, tsc
clean. Build journal in docs/wulf-pulse-ticket-analyzer-build-notes.md.

Sync: adds syncTicketNotes() + ticket_notes to ordered/date-filtered
entities so the analyzer's local mirror stays current via scheduler.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-29 10:59:40 -04:00
ea3471d38d feat: Veeam RPO analysis, comparison, ticket analysis + company teams table
- Add Veeam RPO analysis page (/veeam-analysis) and comparison page (/veeam-comparison)
- Add API routes: /api/veeam/rpo-analyze, rpo-comparison, rpo-offline-log, ticket-analysis
- Add veeam-rpo-service.ts enhancements (RPO logic, offline detection, comparison)
- Add veeam-analysis-state.ts and rmm-device-resolver.ts services
- Add migrations 065-068: company_teams, veeam_rpo_offline_log, rpo_comparison_tables, veeam_ticket_analysis
- Add backup-status page updates and nav links for new Veeam pages
- Add scripts: deactivate-cis-for-inactive-companies, workstation category updates
- Add docs: mimecast-api-guide, veeam-backup-alerting-recommendation, workstation-backup-overview, ticket-analyzer-prompt
- Minor: webhook-service, entity-sync, entity-mapper, sync-helpers, sync.ts, middleware.ts updates
2026-04-29 09:16:46 -04:00
07067bef19 feat: Display Settings UI + Company Category/Type sync
- Add /admin/display-settings page with Kiosk and Mobile sections
- Company category checkbox filter + excluded companies searchable multi-select
- New DB tables: company_categories, company_types (migration 064)
- Sync COMPANY_CATEGORIES via CompanyCategories entity (id/name/isActive)
- Sync COMPANY_TYPES via Companies.companyType picklist
- Add to EntityType, ENTITY_DEPENDENCIES, sync-helpers, entity-mapper, entity-sync
- New API routes: /api/admin/display-settings (GET/POST), /api/data/company-categories, /api/data/companies-list
- Update all 4 routes (kiosk/stats, kiosk/activity, mobile/tickets, mobile/dashboard)
  to filter by kiosk_settings company_category_ids + excluded_company_ids
- Add Display Settings nav link (SlidersHorizontal icon) to Admin menu
- Seed kiosk_settings: kiosk_company_category_ids=1, mobile_company_category_ids=1
2026-04-06 09:03:19 -04:00
0e8eb4871e fix: prevent sync from nullifying assigned_resource_id on tickets
- bulkUpsert now accepts preserveExistingOnNull column list, using
  COALESCE(EXCLUDED.col, table.col) so null incoming values never
  overwrite existing non-null DB values
- bulkUpsertRecords passes resource ID columns as preserve-on-null
  for TICKETS and TASKS entities
- getValidResourceIds now throws on DB error instead of returning
  empty set (which would nullify every resource reference)
- Fix mimecast mailbox-remediate fetch handlers to check res.ok and
  content-type before calling res.json(), preventing JSON parse crash
  on 502 Bad Gateway responses
2026-04-05 08:55:41 -04:00
dd4cf68def feat: add project_phases entity sync with task project_id backfill
The Autotask Tasks bulk API does not return projectID in its response,
causing all tasks.project_id to be NULL. This fixes it by:

- Adding project_phases as a synced entity (Autotask endpoint: /Phases)
- Migration 059: project_phases table with project_id, phase_number,
  estimated_hours, start/due dates, parent_phase_id, is_scheduled
- EntityType.PROJECT_PHASES added to all sync maps and dependency graph
  (depends on PROJECTS, runs before TASKS in sync order)
- buildProjectPhasesFilter: Phases endpoint requires a filter (id > 0)
- mapProjectPhase: maps Autotask field names to DB columns
- Post-sync backfill in syncEntity: after each project_phases sync,
  UPDATE tasks SET project_id = pp.project_id FROM project_phases pp
  JOIN projects p WHERE tasks.phase_id = pp.id
  Only backfills where the project exists in our DB (FK constraint on
  tasks.project_id; archived projects are skipped gracefully)

Result: 2,455 of 4,966 tasks now have project_id populated. Tasks
belonging to archived/completed projects have phase_id resolvable via
project_phases even when project_id remains NULL.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-24 13:57:33 -04:00
ff9e34cafe feat: add Autotask tags sync (tag groups, tags, ticket tag associations)
- Migration 057: autotask_tag_groups, autotask_tags, and junction tables
  (ticket_tags, company_tags, configuration_item_tags, contact_tags)
- Add TAG_GROUPS and TAGS to EntityType enum and dependency map
- Add mapTagGroup() and mapTag() entity mapper functions
- Add syncTagGroups(), syncTags(), syncTicketTagAssociations() methods
- Wire TicketTagAssociations bulk sync into full/incremental sync flow
- Add 'exist' operator to QueryFilter type
- No FK on ticket_id (tagged tickets may be outside 2yr sync window)

Synced: 26 tag groups, 7299 tags, 10141 ticket-tag associations
2026-03-20 09:22:40 -04:00
b98c67482a feat: QuickBooks Online integration
- Add QBO OAuth2 client with token refresh (lib/services/qbo-client.ts)
- Add QBO sync service for invoices, payments, deposits, purchases, journal entries, reports (lib/services/qbo-sync-service.ts)
- Add QBO types (lib/types/qbo.ts)
- Add API routes: /api/qbo/auth, /api/qbo/sync, /api/qbo/disconnect
- Add /admin/qbo status and sync management page
- Add legal pages: /legal/eula, /legal/privacy (Intuit app assessment)
- Add QBO nav link under Admin
- Fix reports: remove invalid summarize_column_by, add accounting_method from Preferences API, add showrows=all&showcols=all
- Add CashFlow report type alongside P&L and BalanceSheet
- Add NoReportData check to skip empty report months
- Add intuit_tid capture in error messages
- Add redirect: follow for cluster routing
- Migration 051: qbo_tokens, qbo_invoices, qbo_payments, qbo_deposits, qbo_transactions, qbo_reports tables

Also includes earlier work:
- Ping flap suppression pipeline step
- Ticket digest reports with LLM analysis
- Zabbix WAN monitor and gap analysis
- Kiosk is_deleted filter fixes
- Datto RMM ping target enrichment
- Entity sync soft-delete detection
2026-03-17 07:39:55 -04:00
c518eefdb2 feat: Morning NOC Summary adaptive card for Teams
- Add MorningSummaryService with Zabbix aggregation and adaptive card builder
- Add webhook delivery system with Teams incoming webhooks
- Add admin UI at /admin/morning-summary for webhook/config management
- Add API routes: /send, /test, /webhooks, /webhooks/[id], /config, /history
- Register morning-summary cron job in SyncScheduler (Mon-Fri 6:30 AM)
- Add outages_only filter (Unavailable triggers only)
- Fix host resolution: use getTriggerEnabledHosts to exclude disabled hosts
- Fix resolved events: event.get value:1 scoped to window with r_eventid filter
- Remove emojis from fact rows and section headers in card
- Remove Open Zabbix button (duplicate of View Problems)
- Add migrations: morning_summary_config + morning_summaries tables
- Add outages_only column to morning_summary_config
2026-03-11 09:34:51 -04:00
d7c3dc7168 feat: Autotask webhook integration, TicketNotes, Datto RMM, workflow engine, Veeam agents/alarms, AI triage, misc improvements 2026-02-20 10:28:15 -05:00
root
d8e6931b85 fix: ensure Companies and Resources get filters during incremental sync fallback
Fixed critical logic bug where Companies and Resources were not getting
proper filters applied when falling back from incremental to full sync.

Root Cause:
- During scheduled incremental sync, Companies and Resources correctly
  identify they don't support incremental sync
- However, the filter-building logic was in an else block that only
  executed for non-incremental syncs
- This caused Companies and Resources to sync with NO filters at all
- Autotask API now rejects queries without filters, returning:
  'Value cannot be null. Parameter name: filters'

Fix:
- Restructured logic so filter building happens for BOTH:
  1. Non-incremental (full) syncs
  2. Incremental syncs that fall back to full sync
- Companies and Resources now get active filters applied even during
  scheduled incremental syncs

This resolves the scheduled sync failures for Companies, Resources,
and all other entities that were failing due to the cascading effect
of early failures.
2026-01-30 22:50:07 -05:00
root
fc284aba85 fix: disable incremental sync for Companies and Resources
Companies and Resources entities in Autotask API do not support
date-based filtering for incremental syncs. When attempting incremental
sync, Autotask returns errors:
- Companies: 'Unable to find lastTrackedModificationDateTime'
- Resources: 'Unable to find lastModifiedDate'

Solution:
- Skip incremental sync for these entities
- Always perform full sync for Companies and Resources
- Log informational message when falling back to full sync
- Other entities continue to support incremental sync normally

This prevents sync failures while maintaining data freshness for
Companies and Resources through full syncs.
2026-01-26 12:07:52 -05:00
root
31c2d94a1b fix: skip soft deletes for ALL entities with filters applied
More robust fix based on user feedback: instead of hardcoding specific
entity types, now dynamically checks if ANY filters were applied during
the sync and skips soft deletes accordingly.

Previous approach (hardcoded):
- Maintained list of specific entities to skip
- Easy to miss new entities (like billing_items bug)
- Required manual updates when adding new filters

New approach (dynamic):
- Tracks whether params.filter has any values
- Applies to ALL entities with ANY filter type:
  * Date filters (tickets, tasks, time_entries, billing_items)
  * Status filters (contracts, projects)
  * Active filters (companies, resources, contacts, etc.)
- Future-proof: automatically handles new filtered entities

Logic:
- hasAppliedFilters = params.filter && params.filter.length > 0
- if (!isIncremental && !hasAppliedFilters) → perform soft deletes
- if (!isIncremental && hasAppliedFilters) → skip soft deletes

This prevents deleting records that exist outside any filter criteria,
not just date ranges.
2026-01-24 09:57:01 -05:00
root
5b7532ee59 fix: prevent incorrect soft deletes of billing items
CRITICAL BUG FIX: Billing items were being incorrectly soft-deleted during
full sync because BILLING_ITEMS was missing from the hasDateFilter check.

The Issue:
- Billing items have a date filter (itemDate >= now - yearsBack)
- Full sync with 90-day range fetched only recent billing items
- Soft delete logic saw 89,714 older items not in fetched set
- Incorrectly marked them as deleted (outside sync window)

The Fix:
- Added EntityType.BILLING_ITEMS to hasDateFilter check
- Now billing items skip soft deletes (like tickets, tasks, time entries)
- Prevents deletion of records outside the sync date range

Recovery:
- Restored all 89,714 incorrectly deleted billing items
- UPDATE billing_items SET is_deleted = false WHERE is_deleted = true

This is the same pattern used for tickets, tasks, and time entries which
also have date filters and skip soft deletes.
2026-01-24 09:53:45 -05:00
root
71873dfb3b fix: correct picklist sync statistics to properly track added vs updated
Previously, all picklist syncs (Statuses, Issue Types, Sub-Issue Types, Work Types)
incorrectly reported all records as 'added' even on subsequent syncs.

The issue was that bulkUpsert returns total rowCount without distinguishing
between inserts and updates.

Fix:
- Query existing values before upserting
- Calculate recordsAdded = new values not in existing set
- Calculate recordsUpdated = values already in existing set
- Applied to all 4 picklist sync methods

This resolves the confusing sync history where Sub-Issue Types showed
+805 on every sync instead of ~0 added, ~805 updated.
2026-01-24 08:47:52 -05:00
root
2f20b99195 fix: add resource foreign key validation for tasks
Tasks also reference resources via assigned_resource_id and other fields.
Added validation for all task resource foreign keys:
- assigned_resource_id
- creator_resource_id
- completed_by_resource_id
- last_activity_resource_id

This completes the fix for tasks foreign key constraint violations.
2026-01-24 08:13:18 -05:00
root
f1037d7964 fix: add required filters for billing items and validate task project references
- Add buildBillingItemsFilter() to provide required itemDate filter
  BillingItems API requires a filter parameter and returns 500 error without it
- Add validation for task project_id foreign key references
  Tasks with invalid project_id now have the field nullified instead of failing
- Add getValidProjectIds() method to fetch valid project IDs from database

Fixes:
- Billing Items: 'Value cannot be null. Parameter name: filters' error
- Tasks: 'violates foreign key constraint tasks_project_id_fkey' error

Both entities should now sync successfully.
2026-01-24 08:09:10 -05:00
root
0dee311457 fix: add routing for Statuses and Work Types in syncEntity method
The previous fix created the picklist sync methods but forgot to add
routing in the syncEntity() method. This caused the sync service to
still call the generic entity sync path instead of the picklist methods.

Added routing for:
- EntityType.STATUSES -> syncStatuses()
- EntityType.WORK_TYPES -> syncWorkTypes()

This completes the fix for the 404 errors on these picklist entities.
2026-01-23 17:16:19 -05:00
root
4f99de364a fix: correct Statuses and Work Types sync to use picklist API
Problem:
- syncStatuses() and syncWorkTypes() were trying to query /Statuses/query
  and /WorkTypes/query endpoints which don't exist in Autotask API
- This caused 404 errors: 'File or directory not found'
- These are picklist values, not queryable entities

Solution:
- Changed syncStatuses() to use getPicklistValues('Tickets', 'status')
- Changed syncWorkTypes() to use getPicklistValues('TimeEntries', 'workType')
- Now follows same pattern as syncIssueTypes() and syncSubIssueTypes()
- Uses proper picklist API endpoint: /entity/entityInformation/fields

This fixes today's sync failures for statuses and work_types entities.
2026-01-23 17:02:09 -05:00
root
e25eb3fa5e feat: implement structured logging for sync operations
- Add comprehensive structured logging utility (lib/utils/sync-logger.ts)
  - Log levels: DEBUG, INFO, WARN, ERROR
  - Automatic error categorization (NETWORK_ERROR, AUTH_ERROR, DATABASE_ERROR, etc.)
  - Phase tracking (INITIALIZING, FETCHING, MAPPING, VALIDATING, UPSERTING, DELETING, COMPLETING)
  - Contextual metadata (syncId, entityType, phase, duration, record counts)
  - Timing helpers for operations

- Update sync-service.ts with structured logging
  - Replace console.log/error with structured logger
  - Consistent error categorization across all error paths
  - Fix swallowed errors in sync history updates
  - Add child loggers for entity-specific operations

- Update entity-sync.ts with structured logging
  - Complete phase tracking throughout sync lifecycle
  - Detailed context for warnings and errors
  - Update chunked sync methods with structured logging
  - Update picklist sync methods (issue types, sub-issue types)
  - Better debugging info with timing and sample data

- Add sync failure analysis script (scripts/analyze-sync-failures.ts)
  - Query sync history by date range, entity type, or status
  - Generate failure summaries by entity
  - Automatic error categorization
  - Calculate success rates and statistics
  - Display detailed sync records with timing

- Add comprehensive documentation (docs/SYNC_LOGGING_IMPROVEMENTS.md)
  - Usage guide and examples
  - Migration guide for developers
  - Before/after comparisons

This addresses inconsistent logging and improves debugging capabilities for sync operations.
2026-01-23 08:02:02 -05:00
root
6eee14f8af Add comprehensive admin features and multi-system integration
- 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
2025-11-19 14:18:16 -05:00