feat(dingtalk): unified DingTalk bot router with binding flow
- Add DingTalkRouterService: maintains single DingTalk Stream WS
connection, handles binding codes, routes messages to agent containers
- Add AgentChannelController: POST bind/:id, GET status/:id, POST unbind/:id
- Add findByDingTalkUserId() to AgentInstanceRepository
- Add dingTalkUserId field to AgentInstance entity + migration 011
- Register DingTalkRouterService + AgentChannelController in AgentModule
- Add IT0_DINGTALK_CLIENT_ID/SECRET env vars to docker-compose.yml
- Flutter: DingTalk bind UI in _InstanceCard (bottom sheet with code
display, countdown, auto-poll, open DingTalk deep link, bound badge)
Robustness improvements in DingTalkRouterService:
- Concurrent connect guard (connecting flag)
- Periodic cleanup timer for dedup/rateWindows/bindingCodes maps
- Non-text message graceful reply
- Empty senderStaffId guard
- serverHost null guard before bridge call
- unref() cleanup timers from event loop
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>