feat: ticketing sync workers with idempotent import and orphan flagging (phase 6)
- task domain model + exhaustive §4.4 status machine tests (single source of truth) - per-customer polling workers reconciled every 30s from the customers collection; panic-safe runs; manual sync-now trigger; status provider for the admin panel - §5.3 upsert keyed on (system, key, customerId): refreshes content while status=imported, records upstream_changed timeline + notification after - attachments cached into GridFS via connector-authorized downloads - orphaned tickets flagged with timeline + consultant notification, never deleted; idempotent across polls - consultant identity from users.extra.ticketingIdentities per system - notifications store (insert/list/unread-count/mark-read) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -22,6 +22,19 @@ func (s *Server) SetPerformerInfo(b BreakerInfo) { s.performer = b }
|
||||
|
||||
// SetSyncTrigger wires the sync manager's "sync now" entry point.
|
||||
func (s *Server) SetSyncTrigger(f func(customerID string)) { s.syncTrigger = f }
|
||||
|
||||
// Publish forwards a live event to connected clients. Until the WebSocket
|
||||
// hub lands this is a metrics-only no-op, so subsystems can emit events
|
||||
// unconditionally.
|
||||
func (s *Server) Publish(channel, event string, payload any) {
|
||||
s.metrics.Inc("events_published_total", 1)
|
||||
if s.publishFn != nil {
|
||||
s.publishFn(channel, event, payload)
|
||||
}
|
||||
}
|
||||
|
||||
// SetPublishFn wires the actual hub broadcast.
|
||||
func (s *Server) SetPublishFn(f func(channel, event string, payload any)) { s.publishFn = f }
|
||||
func (s *Server) SetSyncStatusProvider(p StatusProvider) {
|
||||
s.syncProvider = p
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user