10 Service To Module Migration
Status (2026-10-04 doc reconciliation): M1–M6 are all complete —
internal/serviceshas been removed entirely (P3-2), business capabilities are closed out underinternal/modules/*(capped at 27 top-level modules), so this doc is now a migration-history archive. The current active status source is todo.md.
Scope:
- Close out the old
services/handlers - Solidify the
modules/*application entrypoints - Legacy service retirement and deletion
- Migration route and completion governance
M1 migration-inventory
- [x] Inventory the old
handlers -> services -> repochain - [x] Inventory the coverage of the new
delivery -> application -> domain -> infrachain - [x] Map the current-vs-target entrypoints for every domain module
- [x] Flag high-risk cross-dependencies, shared models, and circular reference points
Acceptance:
- Every core capability can answer "which chain it uses today, and which chain it targets"
Deliverables:
M2 module-entry-contracts
- [x] Define the single application entrypoint for
conversation,routing,ticket,analytics,ai - [x] Make explicit that handlers can depend only on adapter / application contracts, not assemble business logic directly
- [x] Define the compatibility responsibilities old services are allowed to retain
- [x] Establish one-way constraints for repo / gorm dependencies
Acceptance:
- New requirements no longer land in both the old service and the new module implementations at once
Currently landed:
ticket- The handler-facing contract is closed out to
modules/ticket/delivery.HandlerService - The runtime now uses
modules/ticket/delivery.NewHandlerServiceWithDependencies(...) - The old
services/TicketServiceis deleted
- The handler-facing contract is closed out to
agent- The handler-facing contract is closed out to
modules/agent/delivery.HandlerService - The runtime still reuses
services.AgentServiceas the contract implementation services.AgentServiceis explicitly retained as a compatibility facade + runtime state holder
- The handler-facing contract is closed out to
analytics- The handler-facing contract is closed out to
modules/analytics/delivery.HandlerService - The runtime still reuses
services.StatisticsServiceas the contract implementation services.StatisticsServiceis explicitly retained as a compatibility facade + event bus glue
- The handler-facing contract is closed out to
routing / session transfer- The handler-facing contract is closed out to
modules/routing/delivery.HandlerService - The runtime now uses
modules/routing/delivery.HandlerServiceAdapter - The old
services.SessionTransferServiceis deleted
- The handler-facing contract is closed out to
conversation / websocket runtime- The websocket persistence entrypoint is explicitly closed out to
modules/conversation/delivery.WebSocketMessageWriter - Both the main runtime and the lightweight realtime runtime inject the conversation module through
WebSocketMessageAdapter WebSocketHubhas deleted the gorm direct-write fallback forsessions/messages, keeping only the conversation delivery path
- The websocket persistence entrypoint is explicitly closed out to
ai- The handler-facing contract is closed out to
modules/ai/delivery.HandlerService AIAssemblyis split into a handler-facing service and a runtime-facing service- The default handler main path has been promoted to orchestrated enhanced AI instead of directly exposing the old
AIServiceInterface - The server/runtime/router/websocket main chain now depends on
modules/ai/delivery.RuntimeServiceor local runtime contracts and no longer passesservices.AIServiceInterfacethrough - The old
services/AIServiceInterface/EnhancedAIServiceInterfaceare deleted
- The handler-facing contract is closed out to
suggestion- The handler-facing contract is closed out to
modules/suggestion/delivery.HandlerService - The runtime now uses
modules/suggestion/delivery.NewHandlerService(db) - The old
services.SuggestionServiceis deleted; DTO aliases and helpers have sunk into module application / contract
- The handler-facing contract is closed out to
gamification- The handler-facing contract is closed out to
modules/gamification/delivery.HandlerService - The runtime now uses
modules/gamification/delivery.NewHandlerService(db) - The old
services.GamificationServiceis deleted; points / badge logic and DTO aliases have sunk into module application / contract
- The handler-facing contract is closed out to
- Boundary guards
- CI has added
scripts/check-module-boundaries.sh - It currently auto-verifies that the handler constructors, router dependencies, and runtime wiring of
ticket/agent/analytics/customer/automation/knowledge/routing/ai/suggestion/gamification, plus theconversationwebsocket persistence wiring, must all stay on module delivery contracts
- CI has added
M3 legacy-service-retirement
- [x] Add narrow interfaces or adapters for runtime entrypoints still in transition, instead of keeping handlers directly wired to old services
- [x] Move migratable business rules from old services into the module application / delivery layers
- [x] Delete the legacy service outright for closed-out capabilities instead of keeping a facade
- [x] Add tests for the adapter layer to ensure identical behavior before and after migration
Acceptance:
- Closed-out capabilities no longer keep dual entrypoints; unfinished capabilities have explicit freeze boundaries
Currently landed:
routing- Behavior tests were added for
modules/routing/delivery.SessionTransferAdaptercovering waiting lifecycle, assignment/history, and transaction-scoped repository behavior - The handler/runtime main path has switched to
modules/routing/delivery.HandlerServiceAdapter - The old
services/SessionTransferServiceis deleted and no compatibility facade is retained
- Behavior tests were added for
ticket- The handler/runtime main path has switched to
modules/ticket/delivery.NewHandlerServiceWithDependencies(...) - The old
services/TicketServiceis deleted and no compatibility facade is retained
- The handler/runtime main path has switched to
ai- The handler/runtime main path has switched to
modules/ai/delivery.HandlerServiceandAIAssembly.RuntimeService - The old
services/AIServiceInterface/services.OrchestratedAIServiceare deleted; the runtime keeps only local narrow interfaces
- The handler/runtime main path has switched to
conversationWebSocketHubhas deleted the gorm direct-write fallback forsessions/messages- Websocket persistence must go through
modules/conversation/delivery.WebSocketMessageWriter
M4 core-module-migrations
- [x] Migrate
conversationfirst - [x] Migrate
routingfirst - [x] Migrate
ticketfirst - [x] Migrate
aifirst - [x] Split each module into 1 to 3 independently committable small task packages
Acceptance:
- Core-chain modules close out first, and later modules can reuse the migration pattern
Suggested task packages:
conversation- C1: Keep closing out the conversation write paths beyond websocket message persistence into
modules/conversation/application - C2: Keep shrinking the conversation/protocol orchestration inside
WebSocketHub, so conversation-private write paths do not regrow
- C1: Keep closing out the conversation write paths beyond websocket message persistence into
routing- R1: Keep sinking the waiting queue / assignment / cancel runtime orchestration into
modules/routing/application - R2: Add before/after behavior-consistency tests for the routing runtime adapter
- R1: Keep sinking the waiting queue / assignment / cancel runtime orchestration into
ticket- T1: Keep adding cross-module behavior tests for module delivery orchestration
- T2: Review for leftover comments, docs, or call sites referencing the deleted
TicketService
ai- A1: Keep slicing the runtime surface still shared by websocket / router into explicit contracts
- A2: Add regression tests for the AI handler/runtime dual entrypoints, locking the assembly boundary
M5 boundary-enforcement-and-scorecard
- [x] Add the migration completion scorecard
- [x] Document directory responsibilities and dependency directions
- [x] Add boundary constraint checks to code review / CI
- [x] Define the freeze policy and retirement conditions for
services/*
Acceptance:
- Migration work is trackable and quantifiable, no longer stuck in "refactoring in progress"
Deliverables:
M6 app-server-assembly-hardening
- [x] Split
app/server/router.goby auth / management / public / realtime - [x] Split
app/server/runtime.gointo composable phase-based assembly functions - [x] Keep current behavior unchanged and verify via
app/serverandapp/bootstraptests
Acceptance:
app/serverno longer relies on a single giant assembly file to carry all startup complexity- New modules or access surfaces have a clear assembly landing point instead of piling into the main entrypoint