Commit graph

27 commits

Author SHA1 Message Date
4dd9d5dab8 test(24-01): add failing test for Route 53 credential factory
- lib/types/route53.ts: camelCase interfaces for zones/records/history/audit-log/sync-result
- lib/services/route53-factory.test.ts: isRoute53Configured() + getRoute53Client() behavior
  cases — fails RED, factory module does not exist yet
2026-08-05 19:24:28 -04:00
b168d44585 feat(appgate): add AppGate SDP integration health check and sync service
Registers AppGate as a checkConfigOnly integration-health row and public
sync route, matching the existing factory + is<Name>Configured() pattern.
Committed now so Phase 13's worktree-isolated executors fork from a HEAD
that includes this integration-health.ts entry, since Plan 13-02 inserts
the PAX8 row immediately after it.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LHRgZqkzBHBbAbc3KHneuR
2026-07-11 09:43:48 -04:00
bddf612c7b fix(12): CR-02 stop folding company-match review counts into sync_history.records_deleted 2026-07-11 07:18:27 -04:00
5197cbebf1 feat(12-01): add Pax8Invoice/Pax8InvoiceItem types
- Replace stale unused Pax8Order/Pax8OrderItem stubs with live-verified
  Pax8Invoice (header) and Pax8InvoiceItem (per-company line item) types
- Field shapes sourced from 12-RESEARCH.md live PAX8 API verification
2026-07-10 22:41:20 -04:00
0d819badc2 feat(11-01): extend PAX8 types with cost fields and sync-result shapes
- Pax8Subscription: price, partnerCost, currencyCode, productName, endDate, updatedDate
- Pax8Product: vendorName, shortDescription
- New Pax8EntitySyncResult / Pax8SyncResult mirroring AppgateSyncResult shape
- Note pre-existing unrelated tsc errors in sync-scheduler.ts (missing untracked
  appgate-factory/appgate-sync-service files in this worktree) in deferred-items.md
2026-07-10 19:38:24 -04:00
5c9cee02af feat(10-01): add PAX8 typed entity barrel
- Pax8PageEnvelope<T> generic pagination envelope
- Pax8Company, Pax8Subscription, Pax8Product entity interfaces
- Pax8Order/Pax8OrderItem modeled on PAX8 Invoice/InvoiceItem fields
  (not bare Order/LineItem, which lack pricing) per 10-RESEARCH.md Pitfall 1
- escape-hatch [key: string]: unknown on each entity, matching appgate.ts convention
2026-07-10 17:31:38 -04:00
ef9b31e7c2 feat(260519-0oz-01): add QboPaymentCreatePayload, QboDepositCreatePayload types and createPayment/createDeposit methods to QboClient
- Add QboPaymentCreatePayload + QboDepositCreatePayload interfaces to lib/types/qbo.ts
- Add createPayment(payload) and createDeposit(payload) public methods to QboClient
- Both methods use existing private this.request<T>() with POST + minorversion=65
- Both methods throw descriptively if QBO returns no Id in response
2026-05-19 00:36:01 -04:00
d27462f713 feat(09-03): add RouteToUser types and resolver registry
- Add RouteToUser, ResolvedRecipient, NotifyResolver, UserRouteFallback,
  UserRouteFallbackReason types to lib/types/pipeline.ts (ROUTE-01)
- Create lib/services/pipeline-steps/notify-resolvers.ts with three v1
  resolvers: direct_email, pulse_user_id, autotask_resource_email (ROUTE-02)
- Resolver registry as Map<string, NotifyResolver> with registerResolver()
  and resolveRecipient() dispatcher with try/catch error handling
2026-05-10 07:27:00 -04:00
b4f8ccac8b feat(09-01): add owner_user_id to notification_channels + event-key and subscription tables
- migrations/085: ALTER TABLE notification_channels ADD COLUMN owner_user_id TEXT REFERENCES user(id) ON DELETE CASCADE
- migrations/085: partial unique index notification_channels_owner_user_id_channel_type_uniq WHERE owner_user_id IS NOT NULL (UPSERT race defense)
- migrations/086: CREATE TABLE notify_event_keys (key PK, display_label, description, sort_order, is_active) with seed row
- migrations/086: CREATE TABLE user_event_subscriptions composite PK (user_id, event_key, channel_type) opt-out model
- lib/types/pipeline.ts: NotificationChannel gains owner_user_id: string | null
- lib/types/pipeline.ts: exports NotifyEventKey and UserEventSubscription interfaces
2026-05-10 07:23:24 -04:00
1112a06afe feat: RMM Overshell, IT Glue audit/write-back, LogLift, link-aware bundles, dashboard overhaul
- RMM Overshell (migration 077): admin page, dispatch UI, executor/worker, target
  resolver, script registry (AD/DHCP/DNS/event-log/services/software/network/loglift)
- LogLift evidence pipeline (migration 078): upload webhook, B2 storage client,
  receiver/matcher, EventLogCollector PowerShell script
- IT Glue audit + write-back (migrations 075, 076): asset-audit runner, ticket
  xrefs, applications/configurations browse pages + apply/revert/audit endpoints
- Link-aware analyzer bundles (migration 073) + provider toggle (migration 074):
  link-discovery service, OpenRouter LLM provider, related-tickets/itglue-suggestion
  panels, analyze-bundle endpoint
- Endpoint data model + device-link reconciliation (migrations 079, 080): conflicts
  admin page, reconciler service, resolve endpoints
- Dashboard overhaul: integration-health service + alerts, overview/health endpoints
- Permissions: add itglue + rmm scopes; middleware: public /api/rmm/loglift route

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 07:13:18 -04:00
bd3401df1c feat(analyzer): Phase 2 — full stage persistence, fingerprints, aggregate reports, cost guards
Eight sub-phases per docs/ticket-analyzer-phase2-spec.md:

2.1 Schema (migration 070): analyzer_stage_executions table; source_snapshot,
    aggregate_fingerprint, fingerprint_generated_at columns on analyzer_analyses.
    model_traces marked LEGACY (kept for back-compat).
2.2 Every pipeline stage records a row to analyzer_stage_executions, success
    or failure. Worker persists a status='failed' analyzer_analyses row when
    the pipeline throws so partial stage records have a parent. Pipeline
    exposes raw triage/sonnet/opus responses for downstream stages.
2.3 Stage 3 prompt updated with markdown formatting rules + banned filler
    phrases. Added react-markdown + remark-gfm + @tailwindcss/typography.
    New <AnalysisMarkdown> component replaces <ProseText>; coerces stray
    headers to bold paragraphs.
2.4 Stage 6 fingerprint (Haiku) runs after persistence, failure-tolerant.
    scripts/backfill-fingerprints.ts reconstructs Stage 6 input from the
    legacy model_traces blob.
2.5 Browse UI rebuild at /analyzer/tickets: multi-select for client/issue/
    queue/status/priority/assignee, sticky filter bar, active-filter chips,
    bulk selection persisted via localStorage, "Analyze N selected" +
    "Generate aggregate report" actions. New <MultiSelect> primitive.
    Staleness uses last_activity_date > completed_at heuristic per spec C.1.
2.6 Aggregate reports (migration 071): runner is fire-and-forget, persists
    SQL distributions immediately so UI shows partial state during the
    Sonnet reduce call. Three endpoints, three pages (/analyzer/reports[/new
    /:id]). IT Glue context fetcher capped at 200 doc titles.
2.7 Cost guards (migration 072): per-request $5 confirmation, soft-warn at
    $20/day, hard-block at $50/day with ANALYZER_DAILY_COST_OVERRIDE_USERS
    override. Every gating decision audited.
2.8 Runbook + build notes updated.

128 vitest tests passing, tsc clean. Migrations 070/071/072 idempotent
(IF NOT EXISTS). model_traces double-write retained — drop in a future
migration once aggregate reports have soaked.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-29 14:00:22 -04:00
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
e3aba93857 feat: Duo Security integration — full data sync from Accounts + Admin API
Duo API Client (lib/services/duo-client.ts):
- HMAC-SHA1 request signing, GET/POST, automatic pagination
- Rate-limit handling (429 + Retry-After), configurable timeout
- Accounts API: listAccounts() via POST /accounts/v1/account/list
- Admin API: getUsers, getPhones, getGroups, getIntegrations, getAuthLogs
- Child account access: parent creds signed against child api_hostname + account_id
- Factory helpers: getDuoAccountsClient(), getDuoAdminClient()

Database (migration 058):
- 6 tables: duo_accounts, duo_users, duo_phones, duo_auth_logs, duo_groups, duo_integrations
- All with proper FKs, indexes, JSONB fields for capabilities/location/groups

Sync Service (lib/services/duo-sync-service.ts):
- syncAll() orchestration, per-child sequential sync, incremental auth logs
- Company matching: exact then case-insensitive containment (30/32 = 94% matched)
- Non-blocking with sync ID tracking

API Routes:
- POST/GET /api/duo/sync — trigger sync / check status
- GET /api/duo/accounts — list all accounts with stats + matched company
- GET /api/duo/accounts/[id]/users — users for a specific account
- POST /api/openclaw/sync/duo — OpenClaw trigger with API key auth

Verified data: 33 accounts, 832 users, 925 phones, 5927 auth logs, 46 groups, 78 integrations

Also: entity-mapper company fields update, task list marked complete
2026-03-27 11:10:30 -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
19605f82aa feat: IT Glue integration, workflow engine, pipelines, Zabbix WAN, notification channels, backup status UI improvements, nav alignment fixes 2026-02-27 14:52:14 -05: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
5dc7a7e66b feat: Veeam VSPC backup integration - sync, compliance, UI
- Database: 7 Veeam tables + backup_type_udf column on configuration_items
- API Client: VSPC REST API v3 client with pagination, rate limiting, Bearer auth
- Sync Service: full/incremental sync for orgs, servers, repos, jobs, agent jobs, workloads
- Scheduler: veeam-incremental (30min) and veeam-full (daily 2AM) schedules
- Compliance Engine: cross-references Autotask config items vs Veeam workloads
- API Endpoints: backup-status, companies, workloads, jobs, repos, compliance, sync
- UI: Backup Status page with Overview + Contract Compliance tabs
- Navigation: added Backup Status link with HardDrive icon
- Docker: added VEEAM_VSPC_URL and VEEAM_VSPC_API_KEY env vars to compose
2026-02-11 21:04:28 -05:00
root
8e0ca0a63b feat: expand Resources entity to include all Autotask API fields
Add comprehensive field support for Resources entity including:
- Name fields: middleInitial, namePrefix, nameSuffix
- Contact: emailAddress2, emailAddress3, homePhone
- Employment: accountingReferenceID, payrollType, internalCost
- System: emailTypeCode, numberFormat, timeFormat, dateFormat
- Demographics: gender
- Security: licenseType, securityLevel
- Location: defaultServiceDeskRoleID

Changes:
- Migration 015: Add new columns to resources table
- Updated entity mapper to map all Autotask Resource fields
- Expanded TypeScript Resource interface with all fields
- Maintains backward compatibility with existing field names

This ensures all data exposed by the Autotask Resources API is
now captured and stored in the database.
2026-01-26 14:28:51 -05:00
root
a093f8787c feat: add IP address logging to webhooks for whitelisting
Implements comprehensive IP logging for webhook requests to enable
IP whitelisting and security monitoring.

Features:
- Capture source IP from webhook requests (x-forwarded-for, x-real-ip)
- Capture user agent for identification
- Store in webhook_logs table
- New API endpoint: GET /api/webhooks/ips
- View unique IPs with request counts and statistics
- Identify Autotask IPs for whitelisting

Database Changes:
- Added source_ip column (VARCHAR 45) to webhook_logs
- Added user_agent column (TEXT) to webhook_logs
- Added index on source_ip for efficient queries
- Migration 005 for existing installations

API Endpoints:
- GET /api/webhooks/ips?hours=168&entityType=Tickets
  Returns unique IPs with:
  * Request counts (total, successful, failed)
  * First/last seen timestamps
  * Entity types accessed
  * User agent strings

Use Cases:
1. Identify Autotask webhook IPs
2. Configure IP whitelist in nginx/Pangolin/Cloudflare
3. Monitor for unauthorized webhook attempts
4. Audit webhook sources
5. Detect IP changes from Autotask

Security Benefits:
- Enable IP whitelisting for webhook endpoint
- Block unauthorized webhook attempts
- Monitor for suspicious activity
- Audit trail of webhook sources

Documentation:
- Complete IP whitelisting guide (WEBHOOK_IP_WHITELISTING.md)
- Configuration examples for nginx, Pangolin, Cloudflare
- Monitoring queries and best practices
- Troubleshooting guide

Files Modified:
- migrations/004_webhook_support.sql - Added IP columns
- migrations/005_add_webhook_ip_logging.sql - Migration for existing installs
- lib/types/webhook.ts - Added IP fields to WebhookLog
- lib/services/webhook-service.ts - Capture and log IPs
- app/api/webhooks/autotask/route.ts - Extract IP from headers
- app/api/webhooks/ips/route.ts - New IP viewing endpoint
- docs/WEBHOOK_IP_WHITELISTING.md - Complete guide

Next Steps:
1. Run migration (004 for new, 005 for existing)
2. Deploy updated code
3. Receive webhooks from Autotask
4. View IPs via /api/webhooks/ips
5. Configure IP whitelist in proxy/tunnel
2026-01-24 17:28:56 -05:00
root
1f83456199 feat: add webhook support for real-time Autotask updates
Implements comprehensive webhook infrastructure to receive and process
real-time entity updates from Autotask, reducing API calls and improving
data freshness.

Features:
- Webhook receiver endpoint: POST /api/webhooks/autotask
- Automatic entity mapping and upsert to PostgreSQL
- Event logging and tracking in webhook_logs table
- Duplicate event prevention via unique event_id
- Failed event tracking with error messages
- Statistics and monitoring APIs
- Support for 8 entity types: Companies, Tickets, Tasks, Projects,
  Time Entries, Contacts, Contracts, Configuration Items

Architecture:
- WebhookService: Core processing logic
- Database tables: webhook_logs, webhook_configs
- API endpoints: /autotask (receiver), /logs, /stats
- Automatic data mapping using existing entity-mapper

Benefits:
- Near real-time updates (<1 minute vs 24 hours)
- Reduced API usage (webhooks vs polling)
- Complements daily incremental sync for redundancy
- Automatic recovery from webhook failures

Files Added:
- lib/types/webhook.ts - TypeScript types and interfaces
- lib/services/webhook-service.ts - Webhook processing service
- app/api/webhooks/autotask/route.ts - Webhook receiver
- app/api/webhooks/logs/route.ts - Logs API
- app/api/webhooks/stats/route.ts - Statistics API
- migrations/004_webhook_support.sql - Database schema
- docs/WEBHOOK_SETUP.md - Complete setup guide (47 sections)
- docs/WEBHOOKS_README.md - Quick start guide

Next Steps:
1. Run database migration
2. Configure webhooks in Autotask
3. Test endpoint and monitor logs

See docs/WEBHOOK_SETUP.md for detailed setup instructions.
2026-01-24 10:07:20 -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
3c3124d8c9 Restructure: rename to Pulse and move app to root
- Renamed project from PSA-Utils to Pulse
- Moved all app files from autotask-app/ to root
- Updated package.json name to 'pulse'
- Updated Docker container names to pulse-app and pulse-redis
- Updated Docker network name to pulse-network
2025-10-28 23:08:54 -04:00