03 Business Modules
Scope:
- conversation
- routing
- agent
- ticket
- customer
- automation
- analytics
- voice
B1 conversation
- [x] Create
internal/modules/conversation/domain - [x] Create
internal/modules/conversation/application - [x] Create
internal/modules/conversation/infra - [x] Create
internal/modules/conversation/delivery - [x] Define
Conversation - [x] Define
Participant - [x] Define
ConversationMessage - [x] Define
ChannelBinding - [x] Define
ConversationStatus - [x] Implement CreateConversation
- [x] Implement ResumeConversation
- [x] Implement IngestTextMessage
- [x] Implement IngestSystemEvent
- [x] Publish
conversation.created - [x] Publish
conversation.message_received - [x] Add the
conversationGORM repository, mapping the existingSession/Messagemodels - [x]
WebSocketHubtext-message persistence goes through theconversationadapter first, with the old direct DB write kept as fallback - [x] The
WebSocketHub"human agent has taken over" check goes through theconversationreader first, preventing the AI from replying first - [x]
WebSocketHubrecent message history reads go through theconversationadapter first, reducing direct queries against theMessagetable
Acceptance:
- conversation becomes the unified interaction model
B2 routing
- [x] Create
internal/modules/routing/domain - [x] Create
internal/modules/routing/application - [x] Create
internal/modules/routing/infra - [x] Create
internal/modules/routing/delivery - [x] Define
Assignment - [x] Define
QueueEntry - [x] Define
TransferRecord - [x] Define
AgentAvailabilityPolicy - [x] Define
SkillMatchPolicy - [x] Define
LoadBalancePolicy - [x] Implement RequestHumanHandoff
- [x] Implement AssignAgent
- [x] Implement AddToWaitingQueue
- [x] Implement CancelWaiting
- [x] Publish
routing.agent_assigned - [x] Publish
routing.transfer_completed - [x] Add the
routingGORM repository, mapping the existingTransferRecord/WaitingRecordmodels - [x] The
SessionTransferServicewaiting queue path starts delegating to theroutingadapter, with the old notification/message logic retained
Acceptance:
- Replaces the existing session transfer cross-dependencies
B3 agent
- [x] Create
internal/modules/agent/domain - [x] Create
internal/modules/agent/application - [x] Create
internal/modules/agent/infra - [x] Create
internal/modules/agent/delivery - [x] Define
AgentProfile - [x] Define
AgentPresence - [x] Define
AgentLoad - [x] Add chat concurrency
- [x] Add voice concurrency
- [x] Implement GoOnline
- [x] Implement GoOffline
- [x] Implement MarkBusy
- [x] Implement MarkAway
Acceptance:
- The agent module supports future voice load
B4 ticket
- [x] Create
internal/modules/ticket/domain - [x] Create
internal/modules/ticket/application - [x] Create
internal/modules/ticket/infra - [x] Create
internal/modules/ticket/delivery - [x] Add
query_service.go - [x] Migrate
ListTickets - [x] Migrate
GetTicketByID - [x] Add
command_service.go - [x] Migrate
CreateTicket - [x] Fold
CreateTicketinitial status history into the repository transaction - [x] Migrate
UpdateTicket - [x] Fold the
UpdateTicketmain ticket update and status history into the repository transaction - [x] Fold the
UpdateTicketcustom field sync into the module aggregate transaction - [x] Migrate
AssignTicket - [x] Sink
AssignTicketdown to the module command and repository transaction - [x] Sink
UnassignTicketdown to the module command and repository transaction - [x] Migrate
AddComment - [x] Migrate
CloseTicket - [x] Fold the
CloseTicketstatus history and agent load decrement into the repository transaction - [x] Split out
StatusTransitionPolicy - [x] Split out
CustomFieldValidator - [x] Split out
BulkUpdateTickets - [x] Publish
ticket.created - [x] Publish
ticket.assigned - [x] Publish
ticket.closed - [x] Inject
eventbusinto the oldTicketServiceruntime entrypoint - [x] Replace the
TicketHandlerhard dependency on the oldTicketServicewith an interface dependency - [x] Add the ticket handler adapter and switch
main.goto adapter injection - [x] Sink
AddCommentfrom the adapter down to the module command implementation - [x] Sink
AssignTicketfrom the adapter down to the module command implementation, keeping the post-assignment SLA side effects - [x] Sink
CloseTicketfrom the adapter down to the module command implementation, keeping the post-close comment/SLA/CSAT side effects - [x] Sink
BulkUpdateTicketsfrom the adapter down to the module command implementation - [x] Sink
CreateTicketfrom the adapter down to the module repository implementation, keeping the post-create auto-assignment/event/SLA side effects - [x] Sink
UpdateTicketfrom the adapter down to the module aggregate transaction implementation, keeping the post-update event/SLA side effects - [x] Sink
ListTicketCustomFieldsfrom the adapter down to direct data access - [x] Sink
GetTicketStatsfrom the adapter down to the moduleQueryService - [x] Extract
TicketOrchestratorand switch to explicitCommandService + Orchestratorinjection - [x] Startup wiring no longer passes the whole
TicketServiceto the ticket handler adapter - [x] Move the ticket HTTP/adapter shared DTOs into the module
contractpackage, keeping theservicesalias for compatibility - [x]
SLAHandlerfetches tickets through the minimal ticketReaderServiceAdapterread interface, no longer depending on the concreteTicketServicetype - [x] Move handler-layer sqlite integration tests under the
integrationbuild tag; the default test chain keeps only stable unit tests - [x] The old
TicketServiceis converged into a module compatibility shell: all core reads/writes delegate toapplication/infra/orchestration, and legacy fallback branches are removed
Acceptance:
- The old TicketService is no longer a giant monolith
B5 customer
- [x] Create
internal/modules/customer/domain - [x] Create
internal/modules/customer/application - [x] Create
internal/modules/customer/infra - [x] Create
internal/modules/customer/delivery - [x] Define
CustomerProfile - [x] Define
CustomerTag - [x] Define
CustomerNote - [x] Define
CustomerActivity - [x] Implement CreateCustomer
- [x] Implement UpdateCustomer
- [x] Implement AddNote
- [x] Implement UpdateTags
- [x] Implement GetCustomerActivity
Acceptance:
- The customer module stands on its own
B6 automation
- [x] Create
internal/modules/automation/domain - [x] Create
internal/modules/automation/application - [x] Create
internal/modules/automation/infra - [x] Create
internal/modules/automation/delivery - [x] Define
Trigger - [x] Define
Condition - [x] Define
Action - [x] Define
Execution - [x] Subscribe to ticket events
- [x] Subscribe to conversation events
- [x] Subscribe to routing events
- [x] Migrate dry-run
Acceptance:
- automation executes on the event bus
B7 analytics
- [x] Create
internal/modules/analytics/domain - [x] Create
internal/modules/analytics/application - [x] Create
internal/modules/analytics/infra - [x] Create
internal/modules/analytics/delivery - [x] DashboardReadModel
- [x] TicketTrendReadModel
- [x] AgentPerformanceReadModel
- [x] SatisfactionTrendReadModel
- [x] SLATrendReadModel
- [x] Scheduled aggregation first
- [x] Event-driven incremental aggregation next
Acceptance:
- Statistics are separated from business services
B8 voice
- [x] Create
internal/modules/voice/domain - [x] Create
internal/modules/voice/application - [x] Create
internal/modules/voice/infra - [x] Create
internal/modules/voice/delivery - [x] Define
CallSession - [x] Define
MediaSession - [x] Define
VoiceParticipant - [x] Define
Recording - [x] Define
Transcript - [x] Abstract
RecordingProvider - [x] Abstract
TranscriptProvider - [x] Implement StartCall
- [x] Implement AnswerCall
- [x] Implement HoldCall
- [x] Implement ResumeCall
- [x] Implement EndCall
- [x] Implement TransferCall
- [x] Publish
call.started - [x] Publish
call.held - [x] Publish
call.resumed - [x] Publish
call.transferred - [x] Publish
call.ended - [x] Implement StartRecording
- [x] Implement StopRecording
- [x] Implement AppendTranscript
- [x] Publish
recording.started - [x] Publish
recording.stopped - [x] Publish
transcript.appended - [x] Assemble
VoiceCoordinator - [x] Wire into the runtime / WebRTC lifecycle
Acceptance:
- The voice module is the business landing point for SIP
voiceis not bound to a single protocol; signaling goes throughvoiceprotocol.CallSignalingAdapter, media throughvoiceprotocol.MediaSessionAdapter- Recording and transcription are reserved via provider interfaces and are not bound to a single vendor
- Recording and transcription already exist as formal application use cases, not just interface declarations
- The runtime has wired the WebRTC lifecycle into the voice module via
VoiceCoordinator